[Insight-developers] Intel C++ and vnl_*_ref
Brad King
brad . king at kitware . com
Mon, 18 Aug 2003 14:52:11 -0400 (EDT)
Hello,
Recently Bill Hoffman and I tracked down some test failures in ITK when
built with the Intel C++ Compiler for Linux (icc70). The problem turned
out to be a compiler bug that is exposed by passing a vnl_matrix_fixed
instance to a function that takes a vnl_matrix argument. The intermediate
vnl_matrix_ref that is created does not destruct properly and ends up
trying to free memory owned by the vnl_matrix_fixed instance.
The program included below duplicates the problem in a small test case.
Classes map as
A -> vnl_matrix
B -> vnl_matrix_ref
C -> vnl_matrix_fixed
When built with icc70, it produces this output:
operator B()
A(): 0xbffff8f8
B(): 0xbffff8f8
A(const A&): 0xbffff908
B(const B&): 0xbffff908
f()
~A(): 0xbffff908
~B(): 0xbffff8f8
~A(): 0xbffff8f8
By carefully tracing the program, one finds that the argument to f() is
created by copy-constructing a B, but it is destroyed by calling only ~A()
and not ~B().
Using CMake, it is easy to detect this bug in the C++ compiler with a
TRY_RUN command (the same bug exists in the Comeau C++ compiler from
www.comeaucomputing.com because it is also based on the EDG compiler).
For ITK, I'm going to add the following work-around when the bug is
detected:
// Use a base class to ensure the ownership flag
// is initialized to 1 by every constructor.
class vnl_matrix_base_own
{
public:
vnl_matrix_base_own(): vnl_matrix_own_data(1) {}
protected:
int vnl_matrix_own_data;
};
template<class T>
class vnl_matrix: public vnl_matrix_base_own
{
~vnl_matrix() { if (data && vnl_matrix_own_data) destroy(); }
};
template <class T>
class vnl_matrix_ref : public vnl_matrix<T>
{
vnl_matrix_ref(/* ...args... */)
{
// ...
// Tell the vnl_matrix destructor we do not own the memory.
vnl_matrix_own_data = 0;
}
};
Obviously this work-around implementation could be tweaked for
size/alignment of the vnl_matrix_own_data member.
I've reported this problem to the VXL people to see if they can find a
better work-around and fix it in VXL proper. I'm also planning to submit
the bug to Intel to get the compiler fixed.
Thoughts?
-Brad
#include <stdio.h>
struct A
{
A() { printf("A(): %p\n", this); }
A(const A&) { printf("A(const A&): %p\n", this); }
~A() { printf("~A(): %p\n", this); }
};
struct B: public A
{
B() { printf("B(): %p\n", this); }
B(const B& b): A(b) { printf("B(const B&): %p\n", this); }
~B() { printf("~B(): %p\n", this); }
};
struct C
{
operator B () { printf("operator B()\n"); return B(); }
};
void f(A) { printf("f()\n"); }
int main()
{
C c;
f(c);
return 0;
}