[Mono-bugs] [Bug 565143] New: calli incorectly marshals byte[]

bugzilla_noreply at novell.com bugzilla_noreply at novell.com
Wed Dec 16 08:59:54 EST 2009


http://bugzilla.novell.com/show_bug.cgi?id=565143

http://bugzilla.novell.com/show_bug.cgi?id=565143#c0


           Summary: calli incorectly marshals byte[]
    Classification: Mono
           Product: Mono: Runtime
           Version: 2.6.x
          Platform: x86
        OS/Version: Windows 7
            Status: NEW
          Severity: Normal
          Priority: P5 - None
         Component: interop
        AssignedTo: mono-bugs at lists.ximian.com
        ReportedBy: tomas.matousek at microsoft.com
         QAContact: mono-bugs at lists.ximian.com
          Found By: ---
           Blocker: ---


Created an attachment (id=332921)
 --> (http://bugzilla.novell.com/attachment.cgi?id=332921)
Repro

User-Agent:       Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1;
Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729;
Media Center PC 6.0; InfoPath.3; MS-RTC LM 8; MALC)

calli instruction doesn't correctly marshal parameters of type byte[]. It
should marhsal the array as a pointer to its first element. Instead it passes a
wrong pointer so the array length is rewritten if the buffer is written to.

The below code works if it injects instructions:
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldelema, typeof(byte));
after each byte[] array parameter load.

--- code ---
using System;
using System.ComponentModel;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;

namespace IronRuby.StandardLibrary.Win32API {
    public class Win32API {
        delegate int F(IntPtr a, int b, int c, int d, int e, byte[] f);

        public static void Main() {
            DynamicMethod calli = EmitCalliStub();
            var f = (F)calli.CreateDelegate(typeof(F));
            IntPtr ftn = GetFunction("shell32", "SHGetFolderPath");
            byte[] path = new byte[1000]; 
            f(ftn, 0, 0x0023, 0, 1, path);
            Console.WriteLine(path.Length);
        }

        [DllImport("kernel32.dll")]
        private static extern IntPtr LoadLibrary(string lpFileName);

        [DllImport("kernel32.dll")]
        private static extern IntPtr GetProcAddress(IntPtr module, string
lpProcName);

        private static IntPtr GetFunction(string/*!*/ libraryName, string/*!*/
functionName) {
            IntPtr library = LoadLibrary(libraryName);
            if (library == IntPtr.Zero) {
                throw new Win32Exception();
            }

            string procName = functionName;
            IntPtr function = GetProcAddress(library, procName);
            if (function == IntPtr.Zero) {
                function = GetProcAddress(library, procName + "A");
                if (library == IntPtr.Zero) {
                    throw new Win32Exception();
                }
            }

            return function;
        }

        private static DynamicMethod/*!*/ EmitCalliStub() {
            var returnType = typeof(int);
            var parameterTypes = new Type[1 + 5];

            // target function ptr:
            parameterTypes = new[] { 
                typeof(IntPtr),
                typeof(int),
                typeof(int),
                typeof(int),
                typeof(int),
                typeof(byte[])
            };

            DynamicMethod dm = new DynamicMethod("calli", returnType,
parameterTypes, DynamicModule);

            var il = dm.GetILGenerator();
            var signature =
SignatureHelper.GetMethodSigHelper(CallingConvention.Winapi, returnType);

            // calli args:
            for (int i = 1; i < parameterTypes.Length; i++) {
                il.Emit(OpCodes.Ldarg, i);
                signature.AddArgument(parameterTypes[i]);
            }

            il.Emit(OpCodes.Ldarg_0);

            il.Emit(OpCodes.Calli, signature);
            il.Emit(OpCodes.Ret);

            return dm;
        }

        private static ModuleBuilder _dynamicModule; 

        private static ModuleBuilder DynamicModule {
            get {
                if (_dynamicModule == null) {
                    var attributes = new[] { 
                        new
CustomAttributeBuilder(typeof(UnverifiableCodeAttribute).GetConstructor(Type.EmptyTypes),
new object[0]),
                        new
CustomAttributeBuilder(typeof(PermissionSetAttribute).GetConstructor(new Type[]
{ typeof(SecurityAction) }), 
                            new object[]{ SecurityAction.Demand },
                            new PropertyInfo[] {
typeof(PermissionSetAttribute).GetProperty("Unrestricted") }, 
                            new object[] { true }
                        )
                    };

                    string name = "DynamicAssembly";
                    var assembly =
AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(name),
AssemblyBuilderAccess.Run, attributes);
                    assembly.DefineVersionInfoResource();
                    _dynamicModule = assembly.DefineDynamicModule(name);
                }

                return _dynamicModule;
            }
        }

    }
}


Reproducible: Always

Steps to Reproduce:
1. compile and run the above code or run the attached .exe
Actual Results:  
24948 (or some other random number != 1000)

Expected Results:  
1000

-- 
Configure bugmail: http://bugzilla.novell.com/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.
You are the assignee for the bug.


More information about the mono-bugs mailing list