Thread overview
Casting in Safe D
Nov 23, 2014
Nordlöw
Nov 23, 2014
anonymous
Nov 27, 2014
David Held
Nov 27, 2014
Nordlöw
Nov 28, 2014
Jonathan M Davis
Nov 29, 2014
Nordlöw
Nov 30, 2014
Jonathan M Davis
November 23, 2014
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.
November 23, 2014
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;}
November 27, 2014
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

November 27, 2014
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.
November 28, 2014
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

November 29, 2014
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.
November 30, 2014
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