This is an archive of the discontinued LLVM Phabricator instance.

[asan] Fix pthread_create interceptor
ClosedPublic

Authored by vitalybuka on Jan 30 2021, 12:44 AM.

Details

Summary

AsanThread::Destroy implementation expected to be called on
child thread.

I missed authors concern regarding this reviewing D95184.

Diff Detail

Event Timeline

vitalybuka requested review of this revision.Jan 30 2021, 12:44 AM
vitalybuka created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptJan 30 2021, 12:44 AM
Herald added a subscriber: Restricted Project. · View Herald Transcript
delcypher requested changes to this revision.Jan 31 2021, 8:13 PM

Thanks for catching this. Did this break something somewhere? I didn't see any emails about breaking CI.

I've left some minor comments in the review but overall the approach seems good to me.

compiler-rt/lib/asan/asan_thread.cpp
103

Should we have something like this to document the assumption and catch if it's being violated?

// Must be called on owning thread if `create_failed` is false.
AsanThread::Destroy(bool create_failed) {
...

bool called_by_owning_thread = tid == GetCurrentTidOrInvalid();

...
if (!create_failed) {
  CHECK(called_by_owning_thread);
  ...
}
compiler-rt/test/sanitizer_common/TestCases/Posix/create_thread_fail.cpp
22

I'm guessing you're trying to zero the 16 least significant bits in sz which makes the size 64KiB aligned. Maybe add a comment explaining why? Perhaps you need to do this to make pthread_attr_setstacksize() to succeed?

I presume the idea here is that the requested stack size is supposed to be too large to succeed? If that's the case could you add a comment explaining this?

This revision now requires changes to proceed.Jan 31 2021, 8:13 PM
vitalybuka marked 2 inline comments as done.Feb 1 2021, 1:23 AM

Thanks for catching this. Did this break something somewhere? I didn't see any emails about breaking CI.

It fails many_threads_detach.cpp on my workstation. Probably bots have higher thread limits.

delcypher added inline comments.Feb 1 2021, 10:46 AM
compiler-rt/lib/asan/asan_thread.cpp
103

@vitalybuka Do you want to add the checks I suggested to AsanThread::Destroy()? It's fine to not do it I'd just like to understand why.

131

Maybe add a comment here about keeping this in sync with AsanThread::Destroy()?

compiler-rt/lib/asan/asan_thread.h
67 ↗(On Diff #320413)

How about?

// Destroy this object. Should be called from the corresponding thread when it terminates.
void Destroy();
// Destroy this object. Should be called if the thread fails to start. May be called from any thread
void DestroyFailed();

Perhaps we should pick clearer names. E.g. DestroyOnThreadTermination() and DestroyOnFailedCreate()?

vitalybuka updated this revision to Diff 320575.Feb 1 2021, 1:15 PM
vitalybuka marked an inline comment as done.

update

vitalybuka added inline comments.Feb 1 2021, 1:21 PM
compiler-rt/lib/asan/asan_thread.cpp
103

I guess we we have enough info to perform appropriate version cleanup here.

vitalybuka added inline comments.Feb 1 2021, 1:28 PM
compiler-rt/lib/asan/asan_thread.cpp
109

I changing order of UnsetAlternateSignalStack/FinishThread but I don't see a reason for particular order.

delcypher added inline comments.Feb 2 2021, 12:08 PM
compiler-rt/lib/asan/asan_thread.cpp
102–103

@vitalybuka Should malloc_storage().CommitBack(); be guarded by `was_running too?

I'm not very familiar with this part of ASan's allocator but it looks like malloc_storage() is returning some kind of thread local cache for the quarantine and the primary allocator. I'm guessing that this cache would not be used if was_running is false because we never started the thread and so no allocations could have occurred. That would imply that technically calling malloc_storage().CommitBack(); when was_running is false is unnecessary.

However, for simplicity and to avoid creating an avenue for future bugs calling malloc_storage().CommitBack(); unguarded is probably better provided we are sure it's safe to do this for storage for a thread that was never started. Are we sure it's safe?

109

Seems reasonable. I think the only impact would be if a signal was raised in this function. Previously if a signal was raised in asanThreadRegistry().FinishThread(tid); then I think it would not use the alt signal stack. In the new patch if a signal is raised in asanThreadRegistry().FinishThread(tid) then it will use the alt signal stack.

We should not be raising a signal from asanThreadRegistry().FinishThread(tid); so I think this change should be okay.

Thanks for working on this. The new approach LGTM apart from calling malloc_storage().CommitBack();. I've left a comment on this. I suspect it's probably okay but I wanted to bring this up before we land this.

vitalybuka added inline comments.Feb 2 2021, 1:41 PM
compiler-rt/lib/asan/asan_thread.cpp
102–103

I think it should be safe either way.
"was_running" is hot case so if we wrong about running it after FinishThread() we should notice that soon.

Alternative to add getter for thread state, but it will require additional lock and so fare it looks unnecessary

delcypher accepted this revision.Feb 3 2021, 8:08 AM

LGTM. Thanks for working on this.

This revision is now accepted and ready to land.Feb 3 2021, 8:08 AM
This revision was automatically updated to reflect the committed changes.