Devin Jenson's WebLog

That One Guy

  • The Danger of Marshal.StructureToPtr

    Pop Quiz! Is the following code secure:

    
    public static unsafe IntPtr WriteListToNewNativeBuffer<T>(
        List<T> list)
    {
        if (list == null)
        {
            throw new ArgumentNullException("list");
        }
    
        IntPtr nativeBuffer = IntPtr.Zero;
        Int32 elementSize = Marshal.SizeOf(typeof(T));
    
        try
        {
            nativeBuffer = Marshal.AllocCoTaskMem(list.Count * elementSize);
            Byte* bytePtr = (Byte*)nativeBuffer.ToPointer();
    
            foreach (T element in list)
            {
                Marshal.StructureToPtr(element, new IntPtr(bytePtr), false);
                bytePtr += elementSize;
            }
    
            return nativeBuffer;
        }
    
        catch
        {
            if (nativeBuffer != IntPtr.Zero)
            {
                Marshal.FreeCoTaskMem(nativeBuffer);
            }
    
            throw;
        }
    }
    
    

    Assuming the caller is properly freeing up memory, and assuming I didn't mess up the blog translation, it sure looks like all bases are covered. As you expected me to conclude, this code is insecure -- it can lead to a buffer overflow. Take this program which demonstrates the problem:

    
    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    
    
    
    class Program
    {
        [StructLayout(LayoutKind.Sequential)]
        public class Base
        {
            public Int32 One;
    
            public Base(Int32 one)
            {
                One = one;
            }
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public class Derived : Base
        {
            public Int32 Two;
    
            public Derived(Int32 one, Int32 two) : base(one)
            {
                Two = two;
            }
        }
    
        private static void Main()
        {
            List<Base> list = new List<Base>();
            list.Add(new Base(1));
            list.Add(new Derived(2, 3));
    
            IntPtr nativeBuffer = WriteListToNewNativeBuffer<Base>(list);
            Marshal.FreeCoTaskMem(nativeBuffer);
        }
    }
    
    

    The root of the problem is that Marshal.StructureToPtr only takes a basic System.Object parameter. Our WriteListToNewNativeBuffer library call is passing in the base type, but if the instance is actually a derived type, more data than expected will be written. In the sample above 12 bytes are written into an 8-byte buffer.

    I couldn't tell you why 2.0 doesn't provide a generic overload (or an overload containing a System.Type parameter) to resolve this. Outside the generic environment, one can make an encapsulation class with a single field of the expected element type to "trick" the marshaler into marshaling only the base type even if the instance is derived. Unfortunately, classes with generic reference-type fields cannot be marshaled so in the sample above the only realistic solution is to fail (throw an exception) if the element instance type is not the expected type. Sure one can write each element into a size-checked buffer before copying the base size over to the destination buffer, but that is a lot of undesirable work for something which should be simple. Even that work-around won't work if the derived type is not marshalable.

    Perhaps I overlooked a work-around, let me know if I did. :-)

  • Dynamically Writing and Executing Native Assembly in C#

    Generally, executing native assembly in C# is bad because you lose all the benefits of the managed world. In the cases where it is impossible to perform something in C#, it is better to make a C++ DLL. That said, the new method Marshal.GetDelegateForFunctionPointer() in the .NET Framework v2.0 opens up the possibility for dynamically writing and executing assembly code. Consider the following basic C function:

    
    int __declspec(noinline) __stdcall MyAdd(int x, int y)
    {
        return x + y;
    }
    
    

    The C compiler will compile the code into assembly. Though the code which gets compiled may vary from compiler to platform, for x86 it will usually have this basic form:

    
    Instruction                 Code Bytes   Comment
    ------------------------------------------------------------------------------
    mov eax,dword ptr [esp+8] ' 8B 44 24 08  Load the x into eax
    mov ecx,dword ptr [esp+4] ' 8B 4C 24 04  Load the y into ecx
    add eax,ecx               ' 03 C1        Add eax and ecx, result goes into eax
    ret 8                     ' C2 08 00     Pop x and y off the stack, return eax
    
    

    The instructions listed are disassembly copied from the VC++ debugger. The code bytes are what actually executes. The idea is to take those code bytes, write them into a native buffer, acquire a delegate for that buffer, and finally execute the delegate. Here is sample code to run these code bytes from C#:

    
    using System; 
    using System.Runtime.InteropServices;
    
    
    
    
    class Program
    {
        private delegate Int32 MyAdd(Int32 x, Int32 y);
    
        private static void Main() 
        {
            // A simple Add function
            Byte[] myAddNativeCodeBytes = new Byte[]
            {
                0x8B, 0x44, 0x24, 0x08, // mov eax,dword ptr [esp+8]
                0x8B, 0x4C, 0x24, 0x04, // mov ecx,dword ptr [esp+4]
                0x03, 0xC1,             // add eax,ecx
                0xC2, 0x08, 0x00        // ret 8
            };
    
            // We need to push the code bytes into a native buffer
            IntPtr myAddNativeCodeBytesPtr = IntPtr.Zero;
    
            try
            {
                // Allocate the native buffer
                myAddNativeCodeBytesPtr =
                    Marshal.AllocCoTaskMem(myAddNativeCodeBytes.Length);
    
                // Push the code bytes over
                Marshal.Copy(myAddNativeCodeBytes, 0,
                    myAddNativeCodeBytesPtr, myAddNativeCodeBytes.Length);
    
                // Get a function pointer for the native code bytes
                MyAdd myAdd = (MyAdd)Marshal.GetDelegateForFunctionPointer(
                    myAddNativeCodeBytesPtr, typeof(MyAdd));
    
                // Call the native code bytes
                Int32 result = myAdd(4, 5);
    
                // Did it work?
                Console.WriteLine("Result: {0}", result);
            }
    
            finally
            {
                // Free the native buffer
                if (myAddNativeCodeBytesPtr != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(myAddNativeCodeBytesPtr);
                    myAddNativeCodeBytesPtr = IntPtr.Zero;
                }
            }
        }
    }
    
    

    In this sample I just used Marshal.AllocCoTaskMem(), but one should actually P/Invoke VirtualAllocEx and VirtualProtectEx to ensure the page where the code exists has PAGE_EXECUTE access. Additionally the above sample is targetted to my personal x86 machine, and will not run on x64 or any other platform for that matter.

  • Accessing Dynamic Generic Methods via Interfaces

    It is possible to use the Reflection.Emit classes to emit generic methods on a dynamic type. Additionally, dynamic types can implement interfaces making it easy to access it's generic methods (or any of it's published members). Without interfaces, to call a generic method on a dynamic type, a call to MethodInfo.MakeGenericMethod() is required to bind the generic parameters to real type parameters. Only then can you call MethodInfo.Invoke() leading to code which can be difficult to read.

    With interfaces you can simply make your method calls as you would with any interface. For example:

    
    using System; 
    using System.Reflection; 
    using System.Reflection.Emit; 
    using System.Threading; 
     
     
     
    public interface MyInterface 
    { 
        Boolean MyEquals<T>(T x, T y); 
    } 
     
     
     
    class Program 
    { 
        private static void Main() 
        { 
            // Create a dynamic assembly 
            // --------------------------------------------------------------------- 
            AssemblyName assemblyName = new AssemblyName("DynamicAssembly"); 
     
            AssemblyBuilder assemblyBuilder = 
                AppDomain.CurrentDomain.DefineDynamicAssembly( 
                assemblyName, AssemblyBuilderAccess.RunAndSave); 
     
            ModuleBuilder moduleBuilder = 
                assemblyBuilder.DefineDynamicModule("DynamicAssembly.exe"); 
     
            // Create a type which inherits from MyInterface 
            // --------------------------------------------------------------------- 
            TypeBuilder typeBuilder = moduleBuilder.DefineType("MyType", 
                TypeAttributes.Public | TypeAttributes.Class); 
     
            typeBuilder.AddInterfaceImplementation(typeof(MyInterface)); 
     
            // Define the instance method: bool MyEquals<T>(T x, T, y) 
            // --------------------------------------------------------------------- 
            MethodBuilder methodBuilder = typeBuilder.DefineMethod( 
                "MyEquals", MethodAttributes.Public | MethodAttributes.Virtual, 
                CallingConventions.Standard); 
     
            GenericTypeParameterBuilder genericTypeParameterBuilder = 
                methodBuilder.DefineGenericParameters("T")[0]; 
     
            methodBuilder.SetReturnType(typeof(Boolean)); 
     
            methodBuilder.SetParameters(new Type[2] { 
                genericTypeParameterBuilder, genericTypeParameterBuilder } ); 
     
            // Generate a simple Object.Equals() wrapper 
            // ---------------------------------------------------------------------- 
            MethodInfo equalsMethodInfo = typeof(Object).GetMethod( 
                "Equals", BindingFlags.Public | BindingFlags.Static); 
     
            ILGenerator ilGenerator = methodBuilder.GetILGenerator(); 
     
            ilGenerator.Emit(OpCodes.Ldarg_1); 
            ilGenerator.Emit(OpCodes.Box, genericTypeParameterBuilder); 
            ilGenerator.Emit(OpCodes.Ldarg_2); 
            ilGenerator.Emit(OpCodes.Box, genericTypeParameterBuilder); 
            ilGenerator.Emit(OpCodes.Tailcall); 
            ilGenerator.EmitCall(OpCodes.Call, equalsMethodInfo, null); 
            ilGenerator.Emit(OpCodes.Ret); 
     
            // Create the type 
            // --------------------------------------------------------------------- 
            Type myType = typeBuilder.CreateType(); 
     
            MyInterface myInterface = (MyInterface)Activator.CreateInstance(myType); 
     
            // Verify the generated IL works (ugly code) 
            // --------------------------------------------------------------------- 
            MethodInfo methodInfo1 = myType.GetMethod("MyEquals"); 
     
            MethodInfo methodInfo2 = methodInfo1.MakeGenericMethod( 
                new Type[1] { typeof(Int32) } ); 
     
            Boolean result = (Boolean)methodInfo2.Invoke( 
                myInterface, new Object[2] { 5, 4 }); 
     
            result = (Boolean)methodInfo2.Invoke( 
                myInterface, new Object[2] { 5, 5 }); 
     
            // Verify the interface implementation (clean code) 
            // --------------------------------------------------------------------- 
            result = myInterface.MyEquals<int>(5, 4); 
            result = myInterface.MyEquals<int>(5, 5); 
     
            return; 
        } 
    }
    
    

    After saving the dynamic assembly, .NET Reflector shows us the code we generated:

    
    .method public virtual instance bool MyEquals<T>(!!0, !!0) cil managed 
    { 
        // Code Size: 20 byte(s) 
        .maxstack 2 
        L_0000: ldarg.1 
        L_0001: box !!0 
        L_0006: ldarg.2 
        L_0007: box !!0 
        L_000c: tail 
        L_000e: call bool object::Equals(object, object) 
        L_0013: ret 
    }
    
    

    Or the C# view:

    
    public override bool MyEquals<T>(T local1, T local2) 
    { 
        return object.Equals(local1, local2); 
    }
    
    

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker