www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Casting in Safe D

reply =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
I just noticed that

void foo()  safe pure nothrow
{
     void[] void_array = new void[3];
     auto ubyte_array = cast(ubyte[])void_array;
     auto short_array = cast(short[])void_array;
}

compiles but gives a

object.Error (0): array cast misalignment

because of the

     cast(short[])

I'm surprised---why is cast between different alignments and 
element lengths allowed at all in Safe D?

IMO, cast(ubyte[]), should be safe here though.
Nov 23 2014
parent reply "anonymous" <anonymous example.com> writes:
On Sunday, 23 November 2014 at 19:37:45 UTC, Nordlöw wrote:
 I just noticed that

 void foo()  safe pure nothrow
 {
     void[] void_array = new void[3];
     auto ubyte_array = cast(ubyte[])void_array;
     auto short_array = cast(short[])void_array;
 }

 compiles but gives a

 object.Error (0): array cast misalignment

 because of the

     cast(short[])

 I'm surprised---why is cast between different alignments and 
 element lengths allowed at all in Safe D?
As far as I understand, it's safe because it's guaranteed to fail at run time on mismatches. Similarly, array accesses are safe because invalid ones will throw RangeError: void foo(int[] a) safe {a[100] = 13;} And even pointer dereferencing is safe. Invalid ones will fail with a segfault at run time: void foo(int* a) safe {*a = 13;}
Nov 23 2014
parent reply David Held <dmd wyntrmute.com> writes:
On 11/23/2014 3:12 PM, anonymous wrote:
 [...]
 And even pointer dereferencing is  safe. Invalid ones will fail
 with a segfault at run time:
 void foo(int* a)  safe {*a = 13;}
Hmm...throwing an exception is a well-defined behavior, but is segfaulting a well-defined behavior of correct D programs? This seems like a peculiar definition of "safe" to me... Dave
Nov 26 2014
next sibling parent =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
On Thursday, 27 November 2014 at 00:27:59 UTC, David Held wrote:
 On 11/23/2014 3:12 PM, anonymous wrote:
 [...]
 And even pointer dereferencing is  safe. Invalid ones will fail
 with a segfault at run time:
 void foo(int* a)  safe {*a = 13;}
Hmm...throwing an exception is a well-defined behavior, but is segfaulting a well-defined behavior of correct D programs? This seems like a peculiar definition of "safe" to me... Dave
I would personally see that this became a compile-time error in safe code either always or even better when the compile cannot prove that the operation will never cause an exception at run-time. Alternatively we could disallow this only in safe *nothrow* functions.
Nov 27 2014
prev sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Wednesday, November 26, 2014 16:27:53 David Held via Digitalmars-d-learn
wrote:
 On 11/23/2014 3:12 PM, anonymous wrote:
 [...]
 And even pointer dereferencing is  safe. Invalid ones will fail
 with a segfault at run time:
 void foo(int* a)  safe {*a = 13;}
Hmm...throwing an exception is a well-defined behavior, but is segfaulting a well-defined behavior of correct D programs? This seems like a peculiar definition of "safe" to me...
safe is about guaranteeing that memory will not be corrupted and that any memory that's accessed has not been corrupted. Segfaults don't corrupt memory and don't allow you to access corrupted memory. Rather, it's the OS catching that your program has accessed memory that it shouldn't and then essentially killing your program. The OS is _preventing_ any possible memory corruption. So, as much as robust programs shouldn't segfault, segfaults are perfectly safe with regards to memory - which is what safe is all about. - Jonathan M Davis
Nov 28 2014
parent reply =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
On Friday, 28 November 2014 at 22:54:42 UTC, Jonathan M Davis via 
Digitalmars-d-learn wrote:
 On Wednesday, November 26, 2014 16:27:53 David Held via 
 Digitalmars-d-learn wrote:
 On 11/23/2014 3:12 PM, anonymous wrote:
 [...]
 And even pointer dereferencing is  safe. Invalid ones will 
 fail
 with a segfault at run time:
 void foo(int* a)  safe {*a = 13;}
Hmm...throwing an exception is a well-defined behavior, but is segfaulting a well-defined behavior of correct D programs? This seems like a peculiar definition of "safe" to me...
safe is about guaranteeing that memory will not be corrupted and that any memory that's accessed has not been corrupted. Segfaults don't corrupt memory and don't allow you to access corrupted memory. Rather, it's the OS catching that your program has accessed memory that it shouldn't and then essentially killing your program. The OS is _preventing_ any possible memory corruption. So, as much as robust programs shouldn't segfault, segfaults are perfectly safe with regards to memory - which is what safe is all about. - Jonathan M Davis
So what about forbidding this in nothrow functions? My vision with D is to be able to get more guarantees about stability than all other imperative languages. If the compiler cannot prove that alignments and memory regions match then a safe nothrow function doing these casts should IMO fail at compile time.
Nov 29 2014
parent Jonathan M Davis via Digitalmars-d-learn writes:
On Saturday, November 29, 2014 14:34:06 Nordlöw via Digitalmars-d-learn wrote:
 So what about forbidding this in nothrow functions? My vision
 with D is to be able to get more guarantees about stability than
 all other imperative languages. If the compiler cannot prove that
 alignments and memory regions match then a safe nothrow function
 doing these casts should IMO fail at compile time.
Forbidding what exactly? Your original post involves an Error being thrown (which doesn't violate nothrow, because nothrow is for Exceptions, whereas Errors don't), and there's nothing about that that violates safety. The operation being attempted is invalid, so an Error is thrown, ensuring that the operation does not corrupt memory. The same goes for stuff like array bounds checking on indexing. Errors are normally used in cases where what's being done is invalid but can't be detected at compile time, in which case, there's no way that you'd be able to get a compilation error instead. With regards to array cast misalignment, I don't know. My guess is that it's because it doesn't know what the actual underlying type of the void[] array is. For instance, if you change it to void[] void_array = new short[3]; then no Error gets thrown. In this basic example, flow analysis could detect the actual type of the array, but dmd almost never does flow analysis, and as soon as void_array is initialized by something opaque like the return value of a function, then the compiler has no way of detecting the alignment mismatch, and we're forced to have the runtime detect it. So, while I can see why a compilation error would be desirable in this case, it doesn't surprise me that there isn't one. And regardless, it doesn't violate safe, because having an Error thrown ensures that the operation that would be unsafe never actually takes place. - Jonathan M Davis
Nov 30 2014