www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Casting arrays

reply solidstate1991 <laszloszeremi outlook.com> writes:
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
parent reply Dennis <dkorpel gmail.com> writes:
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
parent solidstate1991 <laszloszeremi outlook.com> writes:
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