none
CLR pass by value bug - Please run this test code RRS feed

  • Question

  • Hi see this post for the original source of this issue.

    It seems after much investigation, that .Net 2, 3 and 3.5 have a limit on the size of a value type that can be passed to a method when that method references that passed argument.

    This size limit seems to be 4096 bytes approx and causes an access violation rather than some helpful compiler waring or a specific runtime exception.

    Consider this struct:

        public unsafe struct Structure
        {
            public fixed Byte buffer[10241];  // 4095 or less runs fine.
    
            public static int Method(Structure arg)
            {
                return(arg.Number());
            }
    
            public int Number()
            {
                return(0);
            }
        }
    
    

    If you then run the following code:

                Structure     struc = new Structure();
    
                Structure.Method(struc);
    
    

    You will see an access violation.

    To get the address of the method 'Number' the code must first get the address of arg and do some arithmetic - it seems that the fact that the stack frame has a 4K or more datum on it, causes this to fail.

    This is seen in .Net 2, 3 and 3.5 but not 4.

    Is there a workaround because this is causing a serious issue for some SQL/CLR code that must run under .Net 2 (the only option for SQL/CLR) ?

    Thx

    Cap'n

     

     



    Saturday, November 12, 2011 10:38 PM

All replies

  • I cannot duplicate this.  The following runs fine in .NET 3.5 and .NET 4:

    namespace Test
    {
        using System;
    
        public unsafe struct Structure
        {
            public fixed Byte buffer[10241];  // 4095 or less runs fine.
    
            public static int Method(Structure arg)
            {
                return (arg.Number());
            }
    
            public int Number()
            {
                return (0);
            }
        }
    
        class Test
        {
            static void Main(string[] args)
            {
                Structure struc = new Structure();
    
                Console.WriteLine("Calling method");
                var value = Structure.Method(struc);
                Console.WriteLine("After method - received {0}", value);
                Console.ReadKey();
            }
    
        }
    }
    
    


    Can you provide full code that demonstrates this problem in .NET 3.5?

     

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Sunday, November 13, 2011 12:15 AM
    Moderator
  • I cannot duplicate this.  The following runs fine in .NET 3.5 and .NET 4:

     

    namespace Test
    {
        using System;
    
        public unsafe struct Structure
        {
            public fixed Byte buffer[10241];  // 4095 or less runs fine.
    
            public static int Method(Structure arg)
            {
                return (arg.Number());
            }
    
            public int Number()
            {
                return (0);
            }
        }
    
        class Test
        {
            static void Main(string[] args)
            {
                Structure struc = new Structure();
    
                Console.WriteLine("Calling method");
                var value = Structure.Method(struc);
                Console.WriteLine("After method - received {0}", value);
                Console.ReadKey();
            }
    
        }
    }
    
    

     


    Can you provide full code that demonstrates this problem in .NET 3.5?

     

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".


    Hello Reed

    Thanks for looking at this.

    I think you may be targeting x86 - it doesn't have the issue with that CPU, try Any, X64 etc.

    I got your posted code to fail when I did this, but it did indeed work with x86.

    I seems like a serious code generator flaw, it gens bad code (that's why it gets an access violation) and has trouble dealing with large datums passed by value, it looks like the datum can't exceed FFF bytes (or perhaps it has trouble dealing with offsets > than this with respect to its passed arg pointer).

    A struct passed by value is (almost certainly if the code generator is conventional) copied into the stack frame of the called method and then a ptr to that is passed to the method - again via the stack frame, something dumb is then going on in this area I think.

     

    Cap'n

     

     




    Sunday, November 13, 2011 2:22 PM
  • I cannot reproduce it on .NET 3.5 (x64) either (mscorwks.dll version 2.0.50727.5448 (Win7SP1GDR.050727-5400)).

    Can you please send me standalone .cs file that reproduces your problem and info about which version of mscorwks.dll it is? (Please send it to my email karel (dot) zikmund (at) microsoft.com).

    Thanks,
    -Karel

    Monday, November 14, 2011 5:49 PM
    Moderator
  • I cannot reproduce it on .NET 3.5 (x64) either (mscorwks.dll version 2.0.50727.5448 (Win7SP1GDR.050727-5400)).

    Can you please send me standalone .cs file that reproduces your problem and info about which version of mscorwks.dll it is? (Please send it to my email karel (dot) zikmund (at) microsoft.com).

    Thanks,
    -Karel


    Hi Karel, you should have received some e-mails from us.

    I have reproduced the issue on two systems and a colleague has also run the same tests and seen the same error.

    It is most interesting that you found a .Net 35 system that didn't fail - there may be more to this failure than meets the eye, perhaps a service pack or system update issue.

    I will let you get on with things and see what comes up!

     

    Thanks

    Cap'n

     

    Tuesday, November 15, 2011 2:40 PM
  •  

    Hello Reed

    Thanks for looking at this.

    I think you may be targeting x86 - it doesn't have the issue with that CPU, try Any, X64 etc.

    I got your posted code to fail when I did this, but it did indeed work with x86.

     

    I actually managed to repro this on a different system.  I posted it to connect here: https://connect.microsoft.com/VisualStudio/feedback/details/704159/value-type-size-limitation-in-x64-runtime-in-clr-2

     

    I'd recommend marking it as reproducible there if you agree with my writeup...

     

    -Reed

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Tuesday, November 15, 2011 8:38 PM
    Moderator
  • I cannot reproduce it on .NET 3.5 (x64) either (mscorwks.dll version 2.0.50727.5448 (Win7SP1GDR.050727-5400)).

    Can you please send me standalone .cs file that reproduces your problem and info about which version of mscorwks.dll it is? (Please send it to my email karel (dot) zikmund (at) microsoft.com).

    Thanks,
    -Karel


    Hi Karel, you should have received some e-mails from us.

    I have reproduced the issue on two systems and a colleague has also run the same tests and seen the same error.

    It is most interesting that you found a .Net 35 system that didn't fail - there may be more to this failure than meets the eye, perhaps a service pack or system update issue.

    I will let you get on with things and see what comes up!

     

    Thanks

    Cap'n

     

    Karel and Cap'n,

     

    I just discovered something interesting, with some more testing...

     

    It's not just a matter of the size of the struct.  Doing the same with a struct containing 300 System.Guid values (which has a size of 4800 bytes) does not cause the bug - it's specific to having the fixed byte array...

     

    The code below works fine.

     

    -Reed

     

     

    namespace Test
    {
        using System;
    
        public struct Structure
        {
            public Guid value000;
            public Guid value001;
            public Guid value002;
            public Guid value003;
            public Guid value004;
            public Guid value005;
            public Guid value006;
            public Guid value007;
            public Guid value008;
            public Guid value009;
    
            public Guid value010;
            public Guid value011;
            public Guid value012;
            public Guid value013;
            public Guid value014;
            public Guid value015;
            public Guid value016;
            public Guid value017;
            public Guid value018;
            public Guid value019;
    
            public Guid value020;
            public Guid value021;
            public Guid value022;
            public Guid value023;
            public Guid value024;
            public Guid value025;
            public Guid value026;
            public Guid value027;
            public Guid value028;
            public Guid value029;
    
            public Guid value030;
            public Guid value031;
            public Guid value032;
            public Guid value033;
            public Guid value034;
            public Guid value035;
            public Guid value036;
            public Guid value037;
            public Guid value038;
            public Guid value039;
    
            public Guid value040;
            public Guid value041;
            public Guid value042;
            public Guid value043;
            public Guid value044;
            public Guid value045;
            public Guid value046;
            public Guid value047;
            public Guid value048;
            public Guid value049;
    
            public Guid value050;
            public Guid value051;
            public Guid value052;
            public Guid value053;
            public Guid value054;
            public Guid value055;
            public Guid value056;
            public Guid value057;
            public Guid value058;
            public Guid value059;
    
            public Guid value060;
            public Guid value061;
            public Guid value062;
            public Guid value063;
            public Guid value064;
            public Guid value065;
            public Guid value066;
            public Guid value067;
            public Guid value068;
            public Guid value069;
    
            public Guid value070;
            public Guid value071;
            public Guid value072;
            public Guid value073;
            public Guid value074;
            public Guid value075;
            public Guid value076;
            public Guid value077;
            public Guid value078;
            public Guid value079;
    
            public Guid value080;
            public Guid value081;
            public Guid value082;
            public Guid value083;
            public Guid value084;
            public Guid value085;
            public Guid value086;
            public Guid value087;
            public Guid value088;
            public Guid value089;
    
            public Guid value090;
            public Guid value091;
            public Guid value092;
            public Guid value093;
            public Guid value094;
            public Guid value095;
            public Guid value096;
            public Guid value097;
            public Guid value098;
            public Guid value099;
    
            public Guid value100;
            public Guid value101;
            public Guid value102;
            public Guid value103;
            public Guid value104;
            public Guid value105;
            public Guid value106;
            public Guid value107;
            public Guid value108;
            public Guid value109;
    
            public Guid value110;
            public Guid value111;
            public Guid value112;
            public Guid value113;
            public Guid value114;
            public Guid value115;
            public Guid value116;
            public Guid value117;
            public Guid value118;
            public Guid value119;
    
            public Guid value120;
            public Guid value121;
            public Guid value122;
            public Guid value123;
            public Guid value124;
            public Guid value125;
            public Guid value126;
            public Guid value127;
            public Guid value128;
            public Guid value129;
    
            public Guid value130;
            public Guid value131;
            public Guid value132;
            public Guid value133;
            public Guid value134;
            public Guid value135;
            public Guid value136;
            public Guid value137;
            public Guid value138;
            public Guid value139;
    
            public Guid value140;
            public Guid value141;
            public Guid value142;
            public Guid value143;
            public Guid value144;
            public Guid value145;
            public Guid value146;
            public Guid value147;
            public Guid value148;
            public Guid value149;
    
            public Guid value150;
            public Guid value151;
            public Guid value152;
            public Guid value153;
            public Guid value154;
            public Guid value155;
            public Guid value156;
            public Guid value157;
            public Guid value158;
            public Guid value159;
    
            public Guid value160;
            public Guid value161;
            public Guid value162;
            public Guid value163;
            public Guid value164;
            public Guid value165;
            public Guid value166;
            public Guid value167;
            public Guid value168;
            public Guid value169;
    
            public Guid value170;
            public Guid value171;
            public Guid value172;
            public Guid value173;
            public Guid value174;
            public Guid value175;
            public Guid value176;
            public Guid value177;
            public Guid value178;
            public Guid value179;
    
            public Guid value180;
            public Guid value181;
            public Guid value182;
            public Guid value183;
            public Guid value184;
            public Guid value185;
            public Guid value186;
            public Guid value187;
            public Guid value188;
            public Guid value189;
    
            public Guid value190;
            public Guid value191;
            public Guid value192;
            public Guid value193;
            public Guid value194;
            public Guid value195;
            public Guid value196;
            public Guid value197;
            public Guid value198;
            public Guid value199;
    
            public Guid value200;
            public Guid value201;
            public Guid value202;
            public Guid value203;
            public Guid value204;
            public Guid value205;
            public Guid value206;
            public Guid value207;
            public Guid value208;
            public Guid value209;
    
            public Guid value210;
            public Guid value211;
            public Guid value212;
            public Guid value213;
            public Guid value214;
            public Guid value215;
            public Guid value216;
            public Guid value217;
            public Guid value218;
            public Guid value219;
    
            public Guid value220;
            public Guid value221;
            public Guid value222;
            public Guid value223;
            public Guid value224;
            public Guid value225;
            public Guid value226;
            public Guid value227;
            public Guid value228;
            public Guid value229;
    
            public Guid value230;
            public Guid value231;
            public Guid value232;
            public Guid value233;
            public Guid value234;
            public Guid value235;
            public Guid value236;
            public Guid value237;
            public Guid value238;
            public Guid value239;
    
            public Guid value240;
            public Guid value241;
            public Guid value242;
            public Guid value243;
            public Guid value244;
            public Guid value245;
            public Guid value246;
            public Guid value247;
            public Guid value248;
            public Guid value249;
    
            public Guid value250;
            public Guid value251;
            public Guid value252;
            public Guid value253;
            public Guid value254;
            public Guid value255;
            public Guid value256;
            public Guid value257;
            public Guid value258;
            public Guid value259;
    
            public Guid value260;
            public Guid value261;
            public Guid value262;
            public Guid value263;
            public Guid value264;
            public Guid value265;
            public Guid value266;
            public Guid value267;
            public Guid value268;
            public Guid value269;
    
            public Guid value270;
            public Guid value271;
            public Guid value272;
            public Guid value273;
            public Guid value274;
            public Guid value275;
            public Guid value276;
            public Guid value277;
            public Guid value278;
            public Guid value279;
    
            public Guid value280;
            public Guid value281;
            public Guid value282;
            public Guid value283;
            public Guid value284;
            public Guid value285;
            public Guid value286;
            public Guid value287;
            public Guid value288;
            public Guid value289;
    
            public Guid value290;
            public Guid value291;
            public Guid value292;
            public Guid value293;
            public Guid value294;
            public Guid value295;
            public Guid value296;
            public Guid value297;
            public Guid value298;
            public Guid value299;
    
            public static int Method(Structure arg)
            {
                return (arg.Number());
            }
    
            public int Number()
            {
                return (0);
            }
        }
    
        class Test
        {
            static unsafe void Main(string[] args)
            {
                Structure struc = new Structure();
    
                Console.WriteLine("Size {0}", sizeof(Structure));
                Console.WriteLine("Calling method");
                var value = Structure.Method(struc);
                Console.WriteLine("After method - received {0}", value);
                Console.ReadKey();
            }
    
        }
    }
    


     

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Tuesday, November 15, 2011 8:52 PM
    Moderator
  • Interesting discovery Reed.

    I wonder if having additional fields before the buffer has any impact.....nope it has no effect on failure.

     

     

    Cap'n

     

     

     

     

    Tuesday, November 15, 2011 9:32 PM
  • Interesting discovery Reed.

    I wonder if having additional fields before the buffer has any impact.....nope it has no effect on failure.

     

     

    Cap'n

     

     

     

     

    BTW - I'd recommend adding comments to the connect item with stuff like this - It may help them repro/fix it in the future....

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Tuesday, November 15, 2011 9:34 PM
    Moderator
  •  

    Hello Reed

    Thanks for looking at this.

    I think you may be targeting x86 - it doesn't have the issue with that CPU, try Any, X64 etc.

    I got your posted code to fail when I did this, but it did indeed work with x86.

     

    I actually managed to repro this on a different system.  I posted it to connect here: https://connect.microsoft.com/VisualStudio/feedback/details/704159/value-type-size-limitation-in-x64-runtime-in-clr-2

     

    I'd recommend marking it as reproducible there if you agree with my writeup...

     

    -Reed

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".


    Well MS have confirmed to me this is a bug but are gonna flag it as "Wont Fix" they say pass by ref is the workaround - but not quite !

    We actually get this because we have structs (some large) that provide static implicit and explicit conversion operators and the C# language itself doesn't allow these (or cause these) to be passed by ref.

    I have asked if they can confirm that this IS fixed in .Net 4 (as it seems to be) or this just apparent...

    Also several other have told me that they don't see it on .Net 3.5 despite same versions of mscorwks.dll and so on, so I'd love to know what going on - even if "not fixed" there may be something that causes it to go away on some systems...

     

    Cap'n

     


    Thursday, November 17, 2011 2:28 PM