Reputation: 1834
I'm using visual studio 2015 building some single-thread C++ project.
I have a very crude pool that the rest of project acquire memory and return back to it. It runs with no problem before return 0;
in main. After that, I know there's some compiler generated code for exiting, in which it called some scalar deleting destructor of my own class (class foo
below).
Here's some assembly code of the scalar deleting destructor (I hide the name of those class and namespace by aaaaa
and foo
):
000000013FC30FC0 mov dword ptr [rsp+10h],edx
000000013FC30FC4 mov qword ptr [rsp+8],rcx
000000013FC30FC9 push rbp
000000013FC30FCA push rdi
000000013FC30FCB sub rsp,0E8h
000000013FC30FD2 lea rbp,[rsp+20h]
000000013FC30FD7 mov rdi,rsp
000000013FC30FDA mov ecx,3Ah
000000013FC30FDF mov eax,0CCCCCCCCh
000000013FC30FE4 rep stos dword ptr [rdi]
000000013FC30FE6 mov rcx,qword ptr [rsp+108h]
000000013FC30FEE mov rcx,qword ptr [this]
000000013FC30FF5 call aaaaa::foo::~foo (013FC2381Bh)
000000013FC30FFA mov eax,dword ptr [rbp+0E8h]
000000013FC31000 and eax,1
000000013FC31003 test eax,eax
000000013FC31005 je aaaaa::foo::`scalar deleting destructor'+58h (013FC31018h)
000000013FC31007 mov edx,30h
000000013FC3100C mov rcx,qword ptr [this]
000000013FC31013 call operator delete (013FC2661Ah)
000000013FC31018 mov rax,qword ptr [this]
000000013FC3101F lea rsp,[rbp+0C8h]
000000013FC31026 pop rdi
000000013FC31027 pop rbp
000000013FC31028 ret
In debugging session I finally find out where the problem arose. In the normal running phase (i.e. in the major part of main function), 000000013FC30FFA mov eax,dword ptr [rbp+0E8h]
would set eax
to 0, and thus bypass those several lines of code after je
, and most crucially bypass the call to operator delete
.
But on the last hit of those lines, eax
was set to 1 after the mov
, and then execute the call to operator delete
and at exactly that line it triggered a break point at operator delete
.
So my questions are:
eax
to 1 after call to my custom destructor? Why is the compiler doing this, that is, what's the object operator delete
originally to delete?operator delete
a double deletion?rbp+0E8h
to see how the error occurs? (Any other way to do?)EDIT about the class:
The foo
class (which is my own class mentioned above) have all (raw) pointer members, which itself have all ownership of those pointers, i.e. responsible for deleting them. And the buffer_t
below is the underlying pool or buffer which is basically a large region of raw memory partitioned providing interface of allocate and deallocate for single (i.e. not array or alike) object.
Minimal reproduce of the classes:
template <typename T>
struct other_t{
// members, but none of them are pointer member
other_t(){}// ctor with argument in reality
static buffer_t buffer;
};
struct foo{
other_t<some_T>* ptr;
foo(const foo&)=delete;
foo& operator=(const foo&)=delete;
//~foo{ delete ptr; } //originally
~foo{ other_t<some_T>::buffer.deallocate(ptr); }; // actually
};
PS: I'm not familiar with assembly language and if the above is not enough for solving the problem, please comment below, thanks.
Upvotes: 0
Views: 104
Reputation: 58888
Is scalar deleting destructor a unique concept in Visual Studio, that is, it's not seen in any other compilers?
Yes.
In what case the above code would set eax to 1 after call to my custom destructor?
In the case where the low bit of the 4-byte value at rbp + 0x0E8
is 1.
What is your actual problem?
Upvotes: 1