Wednesday, September 13, 2006

Possible bug with interior_ptr<> in C++ CLI

UPDATE: It's fixed! It will be in the next release. Now THAT is service.

UPDATE: Bug is confirmed and reported. Thanks to Brian Kramer for his help.

I encountered some strange behaviour when using interior_ptr in a generic function. It appears that, for the purposes of pointer arithmetic, the byte size of the template parameter is always assumed to be 4, regardless of whether it is a char or a double. This doesn't happen when interior_ptr is given a concrete type directly.

The following example is a generic version of the online help example that demonstates the problem:


// interior_ptr bug example
// compile with: /clr
 
generic<typename T>
void ProbeFirstTwoElements(array<T>^ arr)
{
   // create an interior pointer into the array
   interior_ptr<T> ipi = &arr[0];
 
   System::Console::WriteLine("1st element in arr holds: {0}", arr[0]);
   System::Console::WriteLine("ipi points to memory address whose value is: {0}", *ipi);
 
   ipi++;
 
   System::Console::WriteLine("after incrementing ipi, it points to memory address whose value is: {0}", *ipi);
   System::Console::WriteLine();
}
 
int main(array<System::String ^> ^args)
{
    array<int>^ arrInt = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    ProbeFirstTwoElements(arrInt);  
 
    array<double>^ arrDouble = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    ProbeFirstTwoElements(arrDouble);  
 
    array<char>^ arrChar = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    ProbeFirstTwoElements(arrChar);  
 
    return 0;
}
 
// Expected output:
//
// 1st element in arr holds: 1
// ipi points to memory address whose value is: 1
// after incrementing ipi, it points to memory address whose value is: 2
//
// 1st element in arr holds: 1
// ipi points to memory address whose value is: 1
// after incrementing ipi, it points to memory address whose value is: 2
//
// 1st element in arr holds: 1
// ipi points to memory address whose value is: 1
// after incrementing ipi, it points to memory address whose value is: 2
//
// Actual output:
//
// 1st element in arr holds: 1
// ipi points to memory address whose value is: 1
// after incrementing ipi, it points to memory address whose value is: 2
//
// 1st element in arr holds: 1
// ipi points to memory address whose value is: 1
// after incrementing ipi, it points to memory address whose value is: 5.29980882362664E-315
//
// 1st element in arr holds: 1
// ipi points to memory address whose value is: 1
// after incrementing ipi, it points to memory address whose value is: 5


Most seriously, this bug has the potential for buffer overflows, even though the code might appear to pass various "correctness" tests.

No comments: