Cook Computing

This C++ program compiled with

April 30, 2002 Written by Charles Cook

This C++ program compiled with /clr sums up what I don't like about Managed C++. It runs without complaint even though the buffer overrun is corrupting both allocated memory and unallocated memory, deallocated memory is accessed (admittedly the latter problem is trapped in the debug build but problems often occur only when running in released code), and an unitialized variable is used. A couple of people I've discussed this with are surprised that IL can access unmanaged types so I've included the output from ILDASM below.

void main(void)
  char* buff1 = new char[16];
  char* buff2 = new char[16];
  for (int i = 0; i < 33; i++)
    buff1[i] = i;
  delete buff1;
  int x;
  *buff1 = x;

This is no different to what you'd expect with a conventional C++ program, and I should mention that you can also write unsafe code in C# using pointers (it has to be explicitly marked as unsafe), but the ease with which you can use unmanaged types in C++, combined with the temptation to reuse pieces of existing C++ code, suggests to me that many new projects written in Managed C++ code will succumb to using unmanaged types. I think that this will be a mistake because one of the advantages of the managed environment is that you can develop applications which are not subject to problems like these. To quote the Framework SDK docs:

In the core C# language it is simply not possible to have an uninitialized variable, a "dangling"; pointer, or an expression that indexes an array beyond its bounds. Whole categories of bugs that routinely plague C and C++ programs are thus eliminated.

Why throw these advantages away if you are developing new code?

.method public static
int32 modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) 
        main() cil managed
  .vtentry 1 : 1
  // Code size       58 (0x3a)
  .maxstack  2
  .locals ([0] int32 i,
           [1] int8 modopt([Microsoft.VisualC]Microsoft.VisualC.NoSignSpecifiedModifier)*
           [2] int32 x)
  IL_0000:  ldc.i4.s   16
  IL_0002:  call       void* modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)
new(unsigned int32)
  IL_0007:  stloc.1
  IL_0008:  ldc.i4.s   16
  IL_000a:  call       void* modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)
new(unsigned int32)
  IL_000f:  pop
  IL_0010:  ldc.i4.0
  IL_0011:  stloc.0
  IL_0012:  ldloc.0
  IL_0013:  ldloc.1
  IL_0014:  add
  IL_0015:  ldloc.0
  IL_0016:  stind.i1
  IL_0017:  ldloc.0
  IL_0018:  ldc.i4.1
  IL_0019:  add
  IL_001a:  stloc.0
  IL_001b:  ldloc.0
  IL_001c:  ldc.i4.s   33
  IL_001e:  blt.s      IL_0012
  IL_0020:  ldloc.1
  IL_0021:  call       void modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)
  IL_0026:  ldloc.1
  IL_0027:  ldloc.2
  IL_0028:  stind.i1
  IL_0029:  ldsflda    valuetype $ArrayType$0x52715acd
  IL_002e:  newobj     instance void [mscorlib]System.String::.ctor(int8*)
  IL_0033:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0038:  ldc.i4.0
  IL_0039:  ret
} // end of method 'Global Functions'::main