Created
June 1, 2016 21:56
-
-
Save xoofx/111663e43a035ac109973eff53fd6f08 to your computer and use it in GitHub Desktop.
Cast an array of blittable structs to an array of byte[], transform length as well
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.InteropServices; | |
namespace EvilArray | |
{ | |
/// <summary> | |
/// Cast an array of structs to an array of byte[] | |
/// </summary> | |
class Program | |
{ | |
/// <summary> | |
/// A blittable struct | |
/// </summary> | |
struct Vector3 | |
{ | |
public Vector3(byte x, byte y, byte z) | |
{ | |
X = x; | |
Y = y; | |
Z = z; | |
} | |
// We use byte here just to be able to read easily and verify the values | |
// But we could use floats | |
public byte X; | |
public byte Y; | |
public byte Z; | |
} | |
// Allow to cast a Vector3[] to byte[] | |
[StructLayout(LayoutKind.Explicit)] | |
struct AliasArray | |
{ | |
[FieldOffset(0)] | |
public Vector3[] Array; | |
[FieldOffset(0)] | |
public byte[] AsByteArray; | |
} | |
/// <summary> | |
/// Transform an array of Vector3[] to an array of byte[]. Transform length | |
/// </summary> | |
/// <param name="array">The array.</param> | |
/// <returns>The equivalent byte array</returns> | |
static unsafe byte[] Alias(Vector3[] array) | |
{ | |
// Create a new array | |
var patch = new AliasArray | |
{ | |
Array = array | |
}; | |
// Get the length | |
fixed (void* pArray = patch.Array) | |
{ | |
// Patch the Type ptr | |
fixed (void* pByte = new byte[1]) | |
{ | |
var arrayBytePType = *(void**)((byte*)pByte - 4 - IntPtr.Size); | |
*(void**)((byte*)pArray - 4 - IntPtr.Size) = arrayBytePType; | |
} | |
// Patch the length | |
*((int*)pArray - 1) = patch.Array.Length * sizeof(Vector3); | |
} | |
return patch.AsByteArray; | |
} | |
// Patch the Vector3[] to a byte[] | |
static void Main(string[] args) | |
{ | |
// Create a new array | |
var byteArray = Alias(new[] | |
{ | |
new Vector3(0, 1, 2), | |
new Vector3(3, 4, 5), | |
} | |
); | |
for (int i = 0; i < byteArray.Length; i++) | |
{ | |
Console.WriteLine(byteArray[i]); | |
} | |
} | |
} | |
} |
These tricks will result into crashes - when the GC kicks in at the wrong moment.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very interesting!!
While I can make a guess reading the code, it would be nice to to have the function to do the reverse transformation.
As a side note I tried to extend this sample with generic type "T" (where T: struct), but the compiler refuse to compile this code for generic! :'(
I guess it's a good use for T4 templates....