Thread overview | |||||
---|---|---|---|---|---|
|
May 30, 2019 Casting arrays | ||||
---|---|---|---|---|
| ||||
For casting arrays in @safe functions between very different types, I have to write a @trusted wrapper that checks if the two arrays are within boundaries, then returns the requested array type (or even a single instance with a different one) from the nested @system function, and throws an exception if the cast would result in an error. Here's an example of one such wrapper, I probably have to put them into a separate library instead: /** * Safely casts one type of an array to another. */ T[] reinterpretCast(T, U)(ref U[] input) @trusted{ T[] _reinterpretCast() @system{ return cast(T[])(cast(void[])input); } if ((U.sizeof * input.length) % T.sizeof == 0){ return _reinterpretCast(); } else { throw new Exception("Cannot cast safely!"); } } The cast to void[] is needed because D often doesn't always let me to cast directly between types this way ("Cannot implicitly cast between types..."), especially structs. |
May 30, 2019 Re: Casting arrays | ||||
---|---|---|---|---|
| ||||
Posted in reply to solidstate1991 | On Thursday, 30 May 2019 at 01:14:57 UTC, solidstate1991 wrote: > /** > * Safely casts one type of an array to another. > */ > T[] reinterpretCast(T, U)(ref U[] input) @trusted{ > T[] _reinterpretCast() @system{ > return cast(T[])(cast(void[])input); > } > if ((U.sizeof * input.length) % T.sizeof == 0){ > return _reinterpretCast(); > } else { > throw new Exception("Cannot cast safely!"); > } > } Don't do this, that function can not be trusted. For casts of basic types, the compiler already has such runtime checks: ``` int[] a = [3, 4, 5]; auto b = cast(double[]) a; ``` "An array of size 12 does not align on an array of size 8, so `int` cannot be cast to `double`" You allowing it for ANY type as long as alignment is okay invites all kinds of safety violations. ``` void main() @safe { char*[1] a = [new char('\xCC')]; auto slice = a[]; auto b = reinterpretCast!(int*)(slice); writefln("%08X", *b[0]); } ``` https://run.dlang.io/is/QVNlEv Prints: 743B50CC The 74 3B 50 are bytes out of bounds. There's more to array casting than alignment for it to be safe. |
May 30, 2019 Re: Casting arrays | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dennis | On Thursday, 30 May 2019 at 08:30:14 UTC, Dennis wrote:
> Don't do this, that function can not be trusted. For casts of basic types, the compiler already has such runtime checks:
>
> ```
> int[] a = [3, 4, 5];
> auto b = cast(double[]) a;
> ```
>
> "An array of size 12 does not align on an array of size 8, so `int` cannot be cast to `double`"
>
> You allowing it for ANY type as long as alignment is okay invites all kinds of safety violations.
>
> ```
> void main() @safe
> {
> char*[1] a = [new char('\xCC')];
> auto slice = a[];
> auto b = reinterpretCast!(int*)(slice);
> writefln("%08X", *b[0]);
> }
> ```
> https://run.dlang.io/is/QVNlEv
>
> Prints:
> 743B50CC
>
> The 74 3B 50 are bytes out of bounds. There's more to array casting than alignment for it to be safe.
I know. I probably should upgrade the wrapper to filter out pointer arrays, structs with pointers (or arrays) in them are also an interesting question. I mainly use it for fast loading of structs from files rather than painstakingly load each individual value, also this way I just can put the read or writebuffer to the checksum calculator, so pointers weren't really an issue for me.
|
Copyright © 1999-2021 by the D Language Foundation