using namespace std;
class A {
public:
virtual void fun1()=0;
};
class B : public A {
public:
virtual void fun1();
};
void B::fun1() {
cout << " In B::fun1 function\n" << endl;
}
class C {
public:
A *pobj;
void Reset(A *pobj);
void fun2();
};
void C::fun2() {
pobj->fun1();
}
void C::Reset(A* p_obj) {
pobj = p_obj;
}
class D {
public:
C cobj;
bool initialized;
void Initialize(A *pAobj);
};
void D::Initialize(A *pAobj) { // casting
if(initialized == false) {
initialized = true;
cobj.Reset(pAobj);
}
cobj.fun2();
}
class E {
public:
E();
~E();
void fun4();
void fun5();
D *p_Dobj;
};
E::E()
: p_Dobj(new D){
}
E::~E() {
if(p_Dobj != NULL) {
delete p_Dobj;
}
}
void E::fun4() {
B Bobj; // Created Local Object which may causing issue.
p_Dobj->Initialize(&Bobj);
}
void E::fun5() {
fun4();
fun4();
}
int main() {
E Eobj;
Eobj.fun5();
return 0;
}
When i am compiling the above code like,
$clang++ Demo.cpp
then is is properly working,
$./a.out
Output:
In B::fun1 function
In B::fun1 function
but when i compile with -fsanitize=address flag like,
$clang++ -fsanitize=address Demo.cpp
Output:
> In B::fun1 function
>
>
> ==32155==ERROR: AddressSanitizer: stack-use-after-return on address 0x7f49b5900060 at pc 0x565479ba8963 bp 0x7fff9ca67730 sp 0x7fff9ca67728
> READ of size 8 at 0x7f49b5900060 thread T0
> #0 0x565479ba8962 (/home/excellarate/Desktop/All Tasks/Wasm/a.out+0xf4962)
> #1 0x565479ba8aae (/home/excellarate/Desktop/All Tasks/Wasm/a.out+0xf4aae)
> #2 0x565479ba8cab (/home/excellarate/Desktop/All Tasks/Wasm/a.out+0xf4cab)
> #3 0x565479ba8d21 (/home/excellarate/Desktop/All Tasks/Wasm/a.out+0xf4d21)
> #4 0x565479ba8e04 (/home/excellarate/Desktop/All Tasks/Wasm/a.out+0xf4e04)
> #5 0x7f49b7f8f082 (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
> #6 0x565479ad337d (/home/excellarate/Desktop/All Tasks/Wasm/a.out+0x1f37d)
>
> Address 0x7f49b5900060 is located in stack of thread T0 at offset 32 in frame
> #0 0x565479ba8bbf (/home/excellarate/Desktop/All Tasks/Wasm/a.out+0xf4bbf)
>
> This frame has 1 object(s):
> [32, 40) 'Bobj' (line 68) <== Memory access at offset 32 is inside this variable
> HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
> (longjmp and C++ exceptions are supported)
> SUMMARY: AddressSanitizer: stack-use-after-return (/home/excellarate/Desktop/All Tasks/Wasm/a.out+0xf4962)
> Shadow bytes around the buggy address:
> 0x7f49b58ffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> 0x7f49b58ffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> 0x7f49b58ffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> 0x7f49b58fff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> 0x7f49b58fff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> =>0x7f49b5900000: f1 f1 f1 f1 00 f3 f3 f3 f5 f5 f5 f5[f5]f5 f5 f5
> 0x7f49b5900080: f1 f1 f1 f1 00 f3 f3 f3 00 00 00 00 00 00 00 00
> 0x7f49b5900100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> 0x7f49b5900180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> 0x7f49b5900200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> 0x7f49b5900280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> Shadow byte legend (one shadow byte represents 8 application bytes):
when it is calling virtual function (fun1) then there is crash occur can you explain why it is happening? Share documentation related to this issue if possible
I don't think this is really anything to do with virtual functions. It's a simple lifetime issue and your own comment points it out. In the first call to fun4()
, you call p_Dobj->Initialize
with a pointer to the local object Bobj
, which results in p_Dobj->cobj.pobj
pointing to this object, and p_Dobj->initialized
set to true
. The lifetime of this object ends when fun4()
returns. When you call fun4()
for the second time, p_Dobj->initialized
is true
so p_Dobj->cobj.pobj
is left alone, and it is dereferenced in the call to p_Dobj->cobj.fun2()
. So you are dereferencing a pointer to an object whose lifetime has ended, and the behavior is undefined.
Bonus bug: in D::Initialize
, the member initialized
is, ironically, read without being initialized.