问题
Let's consider follwing code. In fact this is narrowed problem I found using gmock and mocking void(void) method.
class Base {
public:
virtual ~Base() {}
};
class Derived : public Base
{
public:
void GetValueAndDelete() { delete this; } //here we crash
};
int main() {
Derived* p = 0;
p->GetValueAndDelete();
}
Building it with:
/tools/gcc6.1/bin/g++ --version
g++ (GCC) 6.1.0
with optimization level different than -O0 and running the result causes segmentation fault.
Is it gcc bug or something with c++ code (yes, yes, I know that it uses side effects, but it works with other compilers and without optimization as well)
回答1:
Is it gcc bug
No.
or something with c++ code
Yes. You use the arrow operator on a pointer that doesn't point to a valid object. This has undefined behaviour.
Dereferencing null pointer and calling method in this way that does not use any members is fine.
It's not fine according to the standard. It's UB.
What is calling method on pointer?
Is implementation specific.
Deleting this is nothing special.
Deleting this
is very special.
You should only take care of not using any member after
Yes, that and you must make sure that only new
was used to create all instances on which the function is ever called. No automatic objects, no static objects no new[]
, no malloc
+ placement new.
So yes, you can delete this
, but be careful.
回答2:
Your intuition here seems to be:
p->
is OK because it is just a syntax for filling inthis
.delete this
is OK because you don't usethis
afterdelete
.
But the above may not actually be OK, because dereferencing a null pointer is always undefined behavior. Without optimization enabled this may not cause any trouble, because the compiler is doing a "basic compile" which somewhat matches what you imagine when you "compile in your mind." With optimization, however, GCC will do a lot of things that it normally would not do, such as not bothering to emit "correct" instructions when faced with incorrect source code. There's literally no need for it to do anything at all when you say p->
as your program's first act--it could just pretend main()
was empty (or crash, as in your case).
回答3:
I know that calling method on nullptr is out of standard, but so far I haven't seen a compiler that wouldn't cope with that in described manner. It seems that gcc6.1 works different (still according to spec). So this is gmock bug. I wonder how many other projects depend on such compiler behavior :)
What is worth to mention is that method is called, 'this' inside is zero as expected and then delete fails. I looked into assembly an there is mov (%rax), %rbx which fails because rax contains zero.
来源:https://stackoverflow.com/questions/38352381/gcc-6-1-0-segmentation-fault-gcc-bug