Skip to content

Commit b7cc40f

Browse files
authored
Merge pull request #114 from benlangmuir/tsan-workaround
[tsan] Workaround uninstrumented library code
2 parents 8ac9e5e + 7a799a9 commit b7cc40f

File tree

1 file changed

+47
-7
lines changed

1 file changed

+47
-7
lines changed

include/indexstore/IndexStoreCXX.h

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ADT/Optional.h"
2020
#include "llvm/ADT/STLExtras.h"
2121
#include "llvm/ADT/SmallString.h"
22+
#include "llvm/Support/Mutex.h"
2223
#include <ctime>
2324

2425
namespace indexstore {
@@ -203,6 +204,29 @@ class IndexStore {
203204
typedef std::function<void(UnitEventNotification)> UnitEventHandler;
204205
typedef std::function<void(indexstore_unit_event_notification_t)> RawUnitEventHandler;
205206

207+
private:
208+
struct EventHandlerContext {
209+
RawUnitEventHandler handler;
210+
#if __has_feature(thread_sanitizer)
211+
std::unique_ptr<llvm::sys::Mutex> eventHandlerMutex;
212+
#endif
213+
214+
EventHandlerContext(RawUnitEventHandler handler) : handler(std::move(handler)) {
215+
#if __has_feature(thread_sanitizer)
216+
eventHandlerMutex = std::make_unique<llvm::sys::Mutex>();
217+
#endif
218+
}
219+
220+
~EventHandlerContext() {
221+
#if __has_feature(thread_sanitizer)
222+
// See comment in event_handler_finalizer.
223+
assert(!eventHandlerMutex);
224+
#endif
225+
}
226+
};
227+
228+
public:
229+
206230
void setUnitEventHandler(UnitEventHandler handler) {
207231
auto localLib = std::weak_ptr<IndexStoreLibrary>(library);
208232
if (!handler) {
@@ -212,7 +236,7 @@ class IndexStore {
212236

213237
#pragma clang diagnostic push
214238
#pragma clang diagnostic ignored "-Wc++14-extensions"
215-
auto fnPtr = new RawUnitEventHandler([handler, localLib=std::move(localLib)](
239+
auto fnPtr = new EventHandlerContext([handler, localLib=std::move(localLib)](
216240
indexstore_unit_event_notification_t evt_note) {
217241
if (auto lib = localLib.lock()) {
218242
handler(UnitEventNotification(evt_note, lib));
@@ -223,13 +247,29 @@ class IndexStore {
223247
}
224248

225249
private:
226-
static void event_handler(void *ctx, indexstore_unit_event_notification_t evt) {
227-
auto fnPtr = (RawUnitEventHandler*)ctx;
228-
(*fnPtr)(evt);
250+
static void event_handler(void *ctx_, indexstore_unit_event_notification_t evt) {
251+
auto ctx = (EventHandlerContext*)ctx_;
252+
253+
#if __has_feature(thread_sanitizer)
254+
// See comment in event_handler_finalizer.
255+
llvm::sys::ScopedLock L(*ctx->eventHandlerMutex);
256+
#endif
257+
258+
(ctx->handler)(evt);
229259
}
230-
static void event_handler_finalizer(void *ctx) {
231-
auto fnPtr = (RawUnitEventHandler*)ctx;
232-
delete fnPtr;
260+
static void event_handler_finalizer(void *ctx_) {
261+
auto ctx = (EventHandlerContext*)ctx_;
262+
263+
#if __has_feature(thread_sanitizer)
264+
// We need to convince TSan that the event handler callback never overlaps the
265+
// destructor of the context. We use `eventHandlerMutex` to ensure TSan can
266+
// see the synchronization, and we need to move the mutex out of the context
267+
// so that it can be held during `delete` below.
268+
auto mutexPtr = std::move(ctx->eventHandlerMutex);
269+
llvm::sys::ScopedLock L(*mutexPtr);
270+
#endif
271+
272+
delete ctx;
233273
}
234274

235275
public:

0 commit comments

Comments
 (0)