init (via ctor) of function local static var : not thread safe ????
Hello,
I have a function which creates a (function-)local static data member.
this function is called by multiple threads, and as it appears to me, VC++
9.0 does not create thread safe code when the local static is initialized.
sample:
Foo & getFoo()
{
static Foo aFoo
return aFoo;
}
As assembler source code looks as following:
Foo & getFoo()
{
00401050 push ebp
00401051 mov ebp,esp
00401053 push 0FFFFFFFFh
00401055 push offset __ehhandler$?getFoo@@YAAAVFoo@@XZ (40337Eh)
0040105A mov eax,dword ptr fs:[00000000h]
00401060 push eax
00401061 mov eax,dword ptr [___security_cookie (408018h)]
00401066 xor eax,ebp
00401068 push eax
00401069 lea eax,[ebp-0Ch]
0040106C mov dword ptr fs:[00000000h],eax
static Foo aFoo;
00401072 mov eax,dword ptr [$S1 (40815Ch)]
00401077 and eax,1
0040107A jne getFoo+60h (4010B0h)
0040107C mov ecx,dword ptr [$S1 (40815Ch)]
00401082 or ecx,1
00401085 mov dword ptr [$S1 (40815Ch)],ecx
0040108B mov dword ptr [ebp-4],0
00401092 mov ecx,offset aFoo (408158h)
00401097 call Foo::Foo (40100Ah)
0040109C push offset `getFoo'::`2'::`dynamic atexit destructor for
'aFoo'' (4043B0h)
004010A1 call atexit (4012C0h)
004010A6 add esp,4
004010A9 mov dword ptr [ebp-4],0FFFFFFFFh
return aFoo;
004010B0 mov eax,offset aFoo (408158h)
}
004010B5 mov ecx,dword ptr [ebp-0Ch]
004010B8 mov dword ptr fs:[0],ecx
004010BF pop ecx
004010C0 mov esp,ebp
004010C2 pop ebp
004010C3 ret
i would interpret
00401072 mov eax,dword ptr [$S1 (40815Ch)]
00401077 and eax,1
0040107A jne getFoo+60h (4010B0h)
....
0040107C mov ecx,dword ptr [$S1 (40815Ch)]
00401082 or ecx,1
00401085 mov dword ptr [$S1 (40815Ch)],ecx
.....
....
00401097 call Foo::Foo (40100Ah)
as
if (!initDone)
{
_initDone=1;
call Foo::ctor();
}
So, i think about the following scenario :
thread 1 starts with getFoo
switch to thread2 immediate after _initDone=1; was executed (after:
00401085 mov dword ptr [$S1 (40815Ch)],ecx )
thread2 starts with getFoo.
thread2 sees _initDone IS 1 and so returns a reference to aFoo which is not
initialized. Now thread2 is using an unitinitialized data item.
thread2 crashes.
the game is over.
Note : i could think about other similar bad scenarios. like :
void safeCode()
{
try
{
getFoo().bar();
}
catch()
{
....
}
}
thread1: starts and is not interrupted.
Now assume Foo::ctor throws an exception. This is caught by catch() in
safeCode.
Later thread2 enters getFoo() and see "initDone==1" and try to use aFoo, but
this is not initialized correctly, since it throwed an exception.....
so, does this mean, that i have to do implement all the stuff to make local
statics useable?
any ideas?
regards,
mario semo