digitalmars.D - Casting arrays
- solidstate1991 (24/24) May 29 2019 For casting arrays in @safe functions between very different
- Dennis (25/38) May 30 2019 Don't do this, that function can not be trusted. For casts of
- solidstate1991 (8/32) May 30 2019 I know. I probably should upgrade the wrapper to filter out
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 29 2019
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
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.
May 30 2019