0

I was profiling a C++/CLI project at work that had a strange memory signature: it had a huge amount of Commited bytes (7GB) but it only had about 30MB in the Working Set. What I discovered was that the problem lay in something like this piece of code:

ref class c1
{
public:
    int x;

    static void createArray()
    {
        auto val = gcnew c1;
        auto arr = gcnew array<c1^>(1) { val };
        auto jagged= gcnew array<array<c1^>^>{ arr };

        //Make sure the array doesn't get optimized away
        Console::WriteLine(jagged[0][0]->x);
    }
};

I was expecting the initialization of jaged to translate to something like this in C#:

var jagged = new c1[][] { arr };

Instead, using ILSpy, I discovered it actually translates to something like this (decompiling the optimized binaries:

public static void createArray()
{
    c1 val = new c1();
    c1[] array = new c1[]
    {
        val
    };
    c1[][] array2 = new c1[][]
    {
        new c1[12648430] //the constant is equal to 0xC0FFEE
    };
    array2[0] = array;
    Console.WriteLine(array2[0][0].x);
}

I find it very hard to understand why it would allocate a 12648430 element temporary array. However, I also find it hard to imagine such a bug actually was released in the Visual Studio 2013 Professional edition MSVC compiler, but I can't think of any other explanation.

Am I missing something?

  • Wouldn't it be int jagged_row0[] = {0,1}; int jagged_row1[] = {1,2,3}; int (*jagged[])[] = { &jagged_row0, &jagged_row1 }; taken from http://stackoverflow.com/questions/1083658/jagged-array-in-c – Thomas Lindvall May 31 '14 at 09:41
  • Perhaps someone needed a caffeine boost. – phoog May 31 '14 at 09:56
  • It's not corrupted memory is it? – user541686 May 31 '14 at 09:59
  • Programmers tend to use magic constants to initialize variables to an "unknown value" state. Usually with a quip, 0xdeadbeef for example. 0xc0ffee fits that pattern. This quacks like a compiler bug, initializer lists in C++11 would certainly help to destabilize code like this. Your repro code is however not good enough to demonstrate the problem so finding a workaround is illusive. You'll need help from Microsoft Support if you can't narrow it down. – Hans Passant May 31 '14 at 10:10
  • @ThomasLindvall No, the answer you're linking to is about native C++ arrays. This question is about managed arrays in C++/CLI, a way of compiling C++ code for the .NET managed environment. – Tudor Simionescu May 31 '14 at 11:03
  • @HansPassant Do you mean that my repro code doesn't actually reproduce the problem on your machine? Anyway, the workaround is easy - don't use initializers, fill out each element of the array manually. – Tudor Simionescu May 31 '14 at 11:07
  • Tried it on VS2013 Update 2, release build with the optimizer enabled. Worked fine, no coffee. Your "myArrArr" didn't exactly help btw. – Hans Passant May 31 '14 at 11:16
  • I was talking about var jagged = new c1[][] { arr }; but I'm a c++ scrub – Thomas Lindvall May 31 '14 at 12:17
  • @HansPassant Thank you for taking the time to try this out (and sorry for the myArrArr, edited that now). It's very strange that it doesn't reproduce for you - I am compiling exactly the code I attached (+ a main function) using VS2013 update 2 as well, and using /Ox. It also reproduces both when compiling for x86 and for x64. I will probably talk to some co-workers on Monday and see if it happens on their setups as well or not. Once again, thanks for your time in looking at this. – Tudor Simionescu May 31 '14 at 14:45

1 Answers1

0

This is actually a bug in the C++/CLI compiler implementation. Microsoft is aware of the issue, but they won't fix it for a while.

Some more details can be found in the bug report here.

The report also suggests two simple workarounds:

  1. Manually initialize the array instead of using an initializer list.

  2. Use two-dimensional arrays instead of jagged arrays.