[llvm-dev] call_once and TSan

Kuba Brecka via llvm-dev llvm-dev at lists.llvm.org
Fri Sep 2 05:38:40 PDT 2016


> On 2 Sep 2016, at 14:33, Dmitry Vyukov <dvyukov at google.com> wrote:
> 
> On Fri, Sep 2, 2016 at 2:21 PM, Kuba Brecka <kuba.brecka at gmail.com> wrote:
>> Same problem exists, thread A can still be within REAL(call_once), but after it ran user code and set the flag to ~0.  Roughly, call_once does:
>> 
>> __call_once(flag, arg, func) {
>>  mutex_lock(mut);
>>  if (flag == BEING_INITIALIZED) { wait }
>>  else if (flag == NOT_INITIALIZED_AT_ALL) {
>>    flag = BEING_INITIALIZED;
>>    mutex_unlock(mut);
>>    func(arg);    // <=== user code callback
>>    mutex_lock(mut);
>>    atomic_store(&flag, FULLY_INITIALIZED, mo_release);   // "release" store, but within a compiled dylib, thus invisible to TSan
>>  }
>>  mutex_unlock(mut);
>> }
>> 
>> If thread A is just after the release store, which is invisible to TSan, __tsan_acquire in thread B will have no effect, and the stores from the callback to func(arg) will not be synchronized to thread B.
> 
> right
> 
>> Anyway, I just realized that we can wrap "func" into our own callback, which will perform the (extra) __tsan_release...  Do you think that would work?  E.g.:
>> 
>> void call_once_callback_wrapper(...) {
>>  orig_func(orig_arg);
>>  __tsan_release(flag);
>> }
>> 
>> INTERCEPTOR(call_once, o, func, arg) {
>>  REAL(call_once)(flag, ..., call_once_callback_wrapper);
>> }
> 
> this should work
> but I am obviously bad at thinking today

Lol okay, I'll try to implement that.  I'm still curious if we can allow C++ exception handling in TSan RTL, because then we could reimplement call_once in the wrapper in a way that it would also support already-compiled and non-instrumented user code.

Kuba



More information about the llvm-dev mailing list