1 //===-- tsan_external.cc --------------------------------------------------===// 2 // 3 // This file is distributed under the University of Illinois Open Source 4 // License. See LICENSE.TXT for details. 5 // 6 //===----------------------------------------------------------------------===// 7 // 8 // This file is a part of ThreadSanitizer (TSan), a race detector. 9 // 10 //===----------------------------------------------------------------------===// 11 #include "tsan_rtl.h" 12 #include "tsan_interceptors.h" 13 14 namespace __tsan { 15 16 #define CALLERPC ((uptr)__builtin_return_address(0)) 17 18 struct TagData { 19 const char *object_type; 20 const char *header; 21 }; 22 23 static TagData registered_tags[kExternalTagMax] = { 24 {}, 25 {"Swift variable", "Swift access race"}, 26 }; 27 static atomic_uint32_t used_tags{kExternalTagFirstUserAvailable}; // NOLINT. 28 static TagData *GetTagData(uptr tag) { 29 // Invalid/corrupted tag? Better return NULL and let the caller deal with it. 30 if (tag >= atomic_load(&used_tags, memory_order_relaxed)) return nullptr; 31 return ®istered_tags[tag]; 32 } 33 34 const char *GetObjectTypeFromTag(uptr tag) { 35 TagData *tag_data = GetTagData(tag); 36 return tag_data ? tag_data->object_type : nullptr; 37 } 38 39 const char *GetReportHeaderFromTag(uptr tag) { 40 TagData *tag_data = GetTagData(tag); 41 return tag_data ? tag_data->header : nullptr; 42 } 43 44 void InsertShadowStackFrameForTag(ThreadState *thr, uptr tag) { 45 FuncEntry(thr, (uptr)®istered_tags[tag]); 46 } 47 48 uptr TagFromShadowStackFrame(uptr pc) { 49 uptr tag_count = atomic_load(&used_tags, memory_order_relaxed); 50 void *pc_ptr = (void *)pc; 51 if (pc_ptr < GetTagData(0) || pc_ptr > GetTagData(tag_count - 1)) 52 return 0; 53 return (TagData *)pc_ptr - GetTagData(0); 54 } 55 56 #if !SANITIZER_GO 57 58 typedef void(*AccessFunc)(ThreadState *, uptr, uptr, int); 59 void ExternalAccess(void *addr, void *caller_pc, void *tag, AccessFunc access) { 60 CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed)); 61 ThreadState *thr = cur_thread(); 62 if (caller_pc) FuncEntry(thr, (uptr)caller_pc); 63 InsertShadowStackFrameForTag(thr, (uptr)tag); 64 bool in_ignored_lib; 65 if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) { 66 access(thr, CALLERPC, (uptr)addr, kSizeLog1); 67 } 68 FuncExit(thr); 69 if (caller_pc) FuncExit(thr); 70 } 71 72 extern "C" { 73 SANITIZER_INTERFACE_ATTRIBUTE 74 void *__tsan_external_register_tag(const char *object_type) { 75 uptr new_tag = atomic_fetch_add(&used_tags, 1, memory_order_relaxed); 76 CHECK_LT(new_tag, kExternalTagMax); 77 GetTagData(new_tag)->object_type = internal_strdup(object_type); 78 char header[127] = {0}; 79 internal_snprintf(header, sizeof(header), "race on %s", object_type); 80 GetTagData(new_tag)->header = internal_strdup(header); 81 return (void *)new_tag; 82 } 83 84 SANITIZER_INTERFACE_ATTRIBUTE 85 void __tsan_external_register_header(void *tag, const char *header) { 86 CHECK_GE((uptr)tag, kExternalTagFirstUserAvailable); 87 CHECK_LT((uptr)tag, kExternalTagMax); 88 atomic_uintptr_t *header_ptr = 89 (atomic_uintptr_t *)&GetTagData((uptr)tag)->header; 90 header = internal_strdup(header); 91 char *old_header = 92 (char *)atomic_exchange(header_ptr, (uptr)header, memory_order_seq_cst); 93 if (old_header) internal_free(old_header); 94 } 95 96 SANITIZER_INTERFACE_ATTRIBUTE 97 void __tsan_external_assign_tag(void *addr, void *tag) { 98 CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed)); 99 Allocator *a = allocator(); 100 MBlock *b = nullptr; 101 if (a->PointerIsMine((void *)addr)) { 102 void *block_begin = a->GetBlockBegin((void *)addr); 103 if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin); 104 } 105 if (b) { 106 b->tag = (uptr)tag; 107 } 108 } 109 110 SANITIZER_INTERFACE_ATTRIBUTE 111 void __tsan_external_read(void *addr, void *caller_pc, void *tag) { 112 ExternalAccess(addr, caller_pc, tag, MemoryRead); 113 } 114 115 SANITIZER_INTERFACE_ATTRIBUTE 116 void __tsan_external_write(void *addr, void *caller_pc, void *tag) { 117 ExternalAccess(addr, caller_pc, tag, MemoryWrite); 118 } 119 } // extern "C" 120 121 #endif // !SANITIZER_GO 122 123 } // namespace __tsan 124