I have some code that is crashing in a large system. However, the code essentially boils down to the following pseudo-code. I've removed much of the detail, as I have tried to boil this down to the bare bones; I don't think this misses anything crucial though.
// in a DLL:
#ifdef _DLL
#define DLLEXP __declspec(dllexport)
#else
#define DLLEXP __declspec(dllimport)
#endif
class DLLEXP MyClass // base class; virtual
{
public:
MyClass() {};
virtual ~MyClass() {};
some_method () = 0; // pure virtual
// no member data
};
class DLLEXP MyClassImp : public MyClass
{
public:
MyClassImp( some_parameters )
{
// some assignments...
}
virtual ~MyClassImp() {};
private:
// some member data...
};
and:
// in the EXE:
MyClassImp* myObj = new MyClassImp ( some_arguments ); // scalar new
// ... and literally next (as part of my cutting-down)...
delete myObj; // scalar delete
Note that matching scalar new and scalar delete are being used.
In a Debug build in Visual Studio (2008 Pro), in Microsoft's <dbgheap.c>, the following assertion fails:
_ASSERTE(_CrtIsValidHeapPointer(pUserData));
Near the top of the stack are the following items:
mydll_d.dll!operator delete()
mydll_d.dll!MyClassImp::`vector deleting destructor'()
I think this ought to be
mydll_d.dll!MyClassImp::`scalar deleting destructor'()
That is, the program is behaving as if I'd written
MyClassImp* myObj = new MyClassImp ( some_arguments );
delete[] newObj; // array delete
The address in pUserData
is that of myObj
itself (as opposed to a member).
The memory around that address looks like this:
... FD FD FD FD
(address here)
VV VV VV VV MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
FD FD FD FD AB AB AB AB AB AB AB AB EE FE EE FE
...
where the four VV
s are presumably the address of the virtual function table,
the MM...MM
is recognisable member data,
and the other bytes are various special markers put in place by the debugger
(e.g. the FD FD
s are 'guard bytes' around the object's storage).
Shortly before the assertion failure I do see the VV
s change,
and wonder if that is due to a switch to the base class's virtual function table.
I'm aware of the problem of the wrong level in the class hierarchy undergoing destruction. That's not the problem here; my destructors are all virtual.
I note Microsoft's page "BUG: Wrong Operator Delete Called for Exported Class" http://support.microsoft.com/kb/122675 but that seems to be regarding the wrong executable (with the wrong heap) attempting to take responsibility for destruction of the data.
In my case, it's that the wrong 'flavour' of deleting destructor appears to be being applied: i.e. vector rather than scalar.
I am in the process of trying to produce minimal cut-down code that still exhibits the problem.
However, any hints or tips to help with how to investigate this problem further would be much appreciated.
Perhaps the biggest clue here is the mydll_d.dll!operator delete()
on the stack.
Should I expect this to be myexe_d.exe!operator delete()
,
indicating that the DLLEXP
s have been 'lost'?
I suppose this could be an instance of a double-delete (but I don't think so).
Is there a good reference I can read regarding what _CrtIsValidHeapPointer
checks for?
The scalar deleting destructor is a compiler generated function which invokes your class' destructor. In this case, the unresolved symbol is the actual destructor.
The vector deleting destructor takes some flags. If 2 is set, then a vector is being destructed; otherwise a single object is being destructed. If 1 is set, then the memory is also freed. In our case, the flags parameter is 3, so we will perform a vector destruct followed by a delete.
Sounds like this could be an issue of allocating off of one heap and trying to delete on another. This can be an issue when allocating objects from a dll as the dll has its own heap. From the code you're showing it doesn't seem like this would be the problem but maybe in the simplification something was lost? In the past I've see code like this use factory functions and virtual destroy
methods on the objects to make sure that the allocation and deletion happens in the dll code.
Microsoft provides the source for their C runtime; you can check there to see what _CrtIsValidHeapPointer
does. On my installation, it's under C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src\dbgheap.c
.
One other suggestion is to check the disassembly of
delete newObj; // scalar delete
and compare it to the disassembly generated for
delete[] newObj;
and
delete pointerToClassLikeMyClassThatIsInExeAndNotDll;
to test your theory about delete[]
being called. Similarly, you could check the call stack for
delete pointerToClassLikeMyClassThatIsInExeAndNotDll;
to test your theory about mydll_d.dll!operator delete()
versus myexe_d.exe!operator delete()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With