summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTimur Iskhodzhanov <timurrrr@google.com>2015-03-11 17:47:10 +0000
committerTimur Iskhodzhanov <timurrrr@google.com>2015-03-11 17:47:10 +0000
commit4779d3501762b1c89b54dd852787e410d1dc3e5e (patch)
treea7938b2dbd3ec5e3f10b3931c904c55313df2b7b /lib
parentc832cef78d250afa8265d018c2472678f7d2e63e (diff)
[ASan/Win] Fix a CHECK failure when an exception is thrown from a callback passed to QueueUserWorkItem
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@231947 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/asan/asan_interceptors.cc46
1 files changed, 46 insertions, 0 deletions
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index df5769692..2e08d99da 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -832,9 +832,55 @@ INTERCEPTOR_WINAPI(DWORD, CreateThread,
asan_thread_start, t, thr_flags, tid);
}
+struct UserWorkItemInfo {
+ DWORD (__stdcall *function)(void *arg);
+ void *arg;
+ u32 parent_tid;
+};
+
+static BlockingMutex mu_for_thread_tracking(LINKER_INITIALIZED);
+
+// QueueUserWorkItem may silently create a thread we should keep track of.
+// We achieve this by wrapping the user-supplied work items with our function.
+static DWORD __stdcall QueueUserWorkItemWrapper(void *arg) {
+ UserWorkItemInfo *item = (UserWorkItemInfo *)arg;
+
+ {
+ // FIXME: GetCurrentThread relies on TSD, which might not play well with
+ // system thread pools. We might want to use something like reference
+ // counting to zero out GetCurrentThread() underlying storage when the last
+ // work item finishes? Or can we disable reclaiming of threads in the pool?
+ BlockingMutexLock l(&mu_for_thread_tracking);
+ AsanThread *t = GetCurrentThread();
+ if (!t) {
+ GET_STACK_TRACE_THREAD;
+ t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
+ item->parent_tid, &stack, /* detached */ true);
+ t->Init();
+ asanThreadRegistry().StartThread(t->tid(), 0, 0);
+ SetCurrentThread(t);
+ }
+ }
+
+ DWORD ret = item->function(item->arg);
+ delete item;
+ return ret;
+}
+
+INTERCEPTOR_WINAPI(DWORD, QueueUserWorkItem, DWORD(__stdcall *function)(void *),
+ void *arg, DWORD flags) {
+ UserWorkItemInfo *work_item_info = new UserWorkItemInfo;
+ work_item_info->function = function;
+ work_item_info->arg = arg;
+ work_item_info->parent_tid = GetCurrentTidOrInvalid();
+ return REAL(QueueUserWorkItem)(QueueUserWorkItemWrapper, work_item_info,
+ flags);
+}
+
namespace __asan {
void InitializeWindowsInterceptors() {
ASAN_INTERCEPT_FUNC(CreateThread);
+ ASAN_INTERCEPT_FUNC(QueueUserWorkItem);
ASAN_INTERCEPT_FUNC(RaiseException);
ASAN_INTERCEPT_FUNC(_except_handler3);
ASAN_INTERCEPT_FUNC(_except_handler4);