digitalmars.D.learn - safe - why does this compile?
- Piotr Mitana (18/18) Jul 13 2018 This code:
- ketmar (3/21) Jul 13 2018 there is nothing wrong here. dereferencing null reference is completely
- Steven Schveighoffer (7/34) Jul 13 2018 To emphasize the point, this is @safe as well:
- ketmar (9/14) Jul 13 2018 yeah. in simple words: safe code is *predictable*, but not "segfault-les...
- Johan Engelen (5/15) Jul 16 2018 This is not true when using LDC (and I'd expect the same for GDC).
- bauss (2/20) Jul 13 2018 See: https://dlang.org/spec/function.html#function-safety
- Timoses (10/28) Jul 13 2018 I suppose this is another good example of how casting can be
- Dukc (7/16) Jul 13 2018 No, casting classes to their subclasses is not dangerous to
- Timoses (6/25) Jul 13 2018 Thanks for the explanation. Only read the function safety chapter
- Steven Schveighoffer (9/35) Jul 14 2018 Well, std.conv.to is going to throw if it doesn't dynamically convert.
This code: import std.stdio; class X1 {} class X2 : X1 { void run() safe { writeln("DONE"); } } void main() safe { X1 x1 = new X1; X2 x2 = cast(X2) x1; x2.run(); } is obviously wrong gets killed by OS's signal. Why is it safe? I thought safe should prevent such errors as well.
Jul 13 2018
Piotr Mitana wrote:This code: import std.stdio; class X1 {} class X2 : X1 { void run() safe { writeln("DONE"); } } void main() safe { X1 x1 = new X1; X2 x2 = cast(X2) x1; x2.run(); } is obviously wrong gets killed by OS's signal. Why is it safe? I thought safe should prevent such errors as well.there is nothing wrong here. dereferencing null reference is completely safe (in terms of result predictability).
Jul 13 2018
On 7/13/18 7:22 AM, ketmar wrote:Piotr Mitana wrote:To emphasize the point, this is safe as well: X2 x2; // = null x2.run(); D does not consider a segmentation fault due to null dereferencing to be unsafe -- no memory corruption happens. -SteveThis code: import std.stdio; class X1 {} class X2 : X1 { void run() safe { writeln("DONE"); } } void main() safe { X1 x1 = new X1; X2 x2 = cast(X2) x1; x2.run(); } is obviously wrong gets killed by OS's signal. Why is it safe? I thought safe should prevent such errors as well.there is nothing wrong here. dereferencing null reference is completely safe (in terms of result predictability).
Jul 13 2018
Steven Schveighoffer wrote:To emphasize the point, this is safe as well: X2 x2; // = null x2.run(); D does not consider a segmentation fault due to null dereferencing to be unsafe -- no memory corruption happens.yeah. in simple words: safe code is *predictable*, but not "segfault-less". segfaults (null dereferences) in safe code are allowed, 'cause they have completely predictable behavior (instant program termination). safe doesn't free you from doing your null checks, it protects you from so-called "undefined behavior" (aka "unpredictable execution results"). so when we are talking about "memory safety", it doesn't mean that your code cannot segfault, it means that your code won't corrupt random memory due to misbehaving.
Jul 13 2018
On Friday, 13 July 2018 at 14:51:17 UTC, ketmar wrote:yeah. in simple words: safe code is *predictable*, but not "segfault-less". segfaults (null dereferences) in safe code are allowed, 'cause they have completely predictable behavior (instant program termination). safe doesn't free you from doing your null checks, it protects you from so-called "undefined behavior" (aka "unpredictable execution results"). so when we are talking about "memory safety", it doesn't mean that your code cannot segfault, it means that your code won't corrupt random memory due to misbehaving.This is not true when using LDC (and I'd expect the same for GDC). With LDC, dereferencing `null` is undefined behavior regardless of whether you are in an safe context or not. - Johan
Jul 16 2018
Johan Engelen wrote:On Friday, 13 July 2018 at 14:51:17 UTC, ketmar wrote:then those compilers are broken, and should be fixed.yeah. in simple words: safe code is *predictable*, but not "segfault-less". segfaults (null dereferences) in safe code are allowed, 'cause they have completely predictable behavior (instant program termination). safe doesn't free you from doing your null checks, it protects you from so-called "undefined behavior" (aka "unpredictable execution results"). so when we are talking about "memory safety", it doesn't mean that your code cannot segfault, it means that your code won't corrupt random memory due to misbehaving.This is not true when using LDC (and I'd expect the same for GDC). With LDC, dereferencing `null` is undefined behavior regardless of whether you are in an safe context or not. - Johan
Jul 16 2018
Johan Engelen wrote:On Friday, 13 July 2018 at 14:51:17 UTC, ketmar wrote:p.s.: it worth noting that *program* *state* is undefined after null dereference, though. i.e. program cannot continue execution, and must be aborted. in this sense, null dereferencing is defined behavior: it aborts the app unconditionally. and if you will catch segfault with some OS mechanics, you still cannot reliably do *anything* except immediately aborting (strictly speaking, this is true for any `Error` condition, even for asserts). so compiler *can* assume that null dereferencing is something code generally won't do, but it cannot do any optimisations assuming that code will not dereference nulls at all (dmd -O, afair, was guilty of some such optimisations too). so, code can dereference null, and it will be immediately aborted, without any chance to perform cleanup (as program state is undefined after this operation). in this sense, null dereferencing is "defined behavior".yeah. in simple words: safe code is *predictable*, but not "segfault-less". segfaults (null dereferences) in safe code are allowed, 'cause they have completely predictable behavior (instant program termination). safe doesn't free you from doing your null checks, it protects you from so-called "undefined behavior" (aka "unpredictable execution results"). so when we are talking about "memory safety", it doesn't mean that your code cannot segfault, it means that your code won't corrupt random memory due to misbehaving.This is not true when using LDC (and I'd expect the same for GDC). With LDC, dereferencing `null` is undefined behavior regardless of whether you are in an safe context or not. - Johan
Jul 16 2018
On Friday, 13 July 2018 at 11:04:40 UTC, Piotr Mitana wrote:This code: import std.stdio; class X1 {} class X2 : X1 { void run() safe { writeln("DONE"); } } void main() safe { X1 x1 = new X1; X2 x2 = cast(X2) x1; x2.run(); } is obviously wrong gets killed by OS's signal. Why is it safe? I thought safe should prevent such errors as well.See: https://dlang.org/spec/function.html#function-safety
Jul 13 2018
On Friday, 13 July 2018 at 11:04:40 UTC, Piotr Mitana wrote:This code: import std.stdio; class X1 {} class X2 : X1 { void run() safe { writeln("DONE"); } } void main() safe { X1 x1 = new X1; X2 x2 = cast(X2) x1; x2.run(); } is obviously wrong gets killed by OS's signal. Why is it safe? I thought safe should prevent such errors as well.I suppose this is another good example of how casting can be dangerous? E.g. also: immutable int i = 3; int* j = cast(int*)&i; assert(i == 3); *j = 4; assert(j == &i); // data occupies same address space assert(i == 3 && *j == 4); // yet the values differ
Jul 13 2018
On Friday, 13 July 2018 at 13:52:27 UTC, Timoses wrote:I suppose this is another good example of how casting can be dangerous? E.g. also: immutable int i = 3; int* j = cast(int*)&i; assert(i == 3); *j = 4; assert(j == &i); // data occupies same address space assert(i == 3 && *j == 4); // yet the values differNo, casting classes to their subclasses is not dangerous to program integrity, because it is checked. It is just a regular bug that terminates the program when encountered. But casting away immutable can break program integrity as your example demonstrates. For that reason the compiler won't let you do that if you wrap that code in safe, unlike the class cast.
Jul 13 2018
On Friday, 13 July 2018 at 22:17:59 UTC, Dukc wrote:On Friday, 13 July 2018 at 13:52:27 UTC, Timoses wrote:Thanks for the explanation. Only read the function safety chapter in depth after posting this : D. Still, is `cast`ing seen as something "dangerous" or as something that should only be done as a last resort? Should std.conv : to be prioritized?I suppose this is another good example of how casting can be dangerous? E.g. also: immutable int i = 3; int* j = cast(int*)&i; assert(i == 3); *j = 4; assert(j == &i); // data occupies same address space assert(i == 3 && *j == 4); // yet the values differNo, casting classes to their subclasses is not dangerous to program integrity, because it is checked. It is just a regular bug that terminates the program when encountered. But casting away immutable can break program integrity as your example demonstrates. For that reason the compiler won't let you do that if you wrap that code in safe, unlike the class cast.
Jul 13 2018
On 7/14/18 2:50 AM, Timoses wrote:On Friday, 13 July 2018 at 22:17:59 UTC, Dukc wrote:Well, std.conv.to is going to throw if it doesn't dynamically convert. So it depends on the behavior you want. But yeah, if you know it's going to work, you probably want to do std.conv.to, it's safer. Just FYI, it's kind of bad that you have to use cast here, because cast isn't going to distinguish between dynamic casting and const casting. It's kind of a problem in D in general. We don't have C++ niceties like const_cast etc. -SteveOn Friday, 13 July 2018 at 13:52:27 UTC, Timoses wrote:Thanks for the explanation. Only read the function safety chapter in depth after posting this : D. Still, is `cast`ing seen as something "dangerous" or as something that should only be done as a last resort? Should std.conv : to be prioritized?I suppose this is another good example of how casting can be dangerous? E.g. also: immutable int i = 3; int* j = cast(int*)&i; assert(i == 3); *j = 4; assert(j == &i); // data occupies same address space assert(i == 3 && *j == 4); // yet the values differNo, casting classes to their subclasses is not dangerous to program integrity, because it is checked. It is just a regular bug that terminates the program when encountered. But casting away immutable can break program integrity as your example demonstrates. For that reason the compiler won't let you do that if you wrap that code in safe, unlike the class cast.
Jul 14 2018