1 //===-- tsan_external.cc --------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 //===----------------------------------------------------------------------===//
12 #include "tsan_interceptors.h"
16 #define CALLERPC ((uptr)__builtin_return_address(0))
19 const char *object_type
;
23 static TagData registered_tags
[kExternalTagMax
] = {
25 {"Swift variable", "Swift access race"},
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
];
34 const char *GetObjectTypeFromTag(uptr tag
) {
35 TagData
*tag_data
= GetTagData(tag
);
36 return tag_data
? tag_data
->object_type
: nullptr;
39 const char *GetReportHeaderFromTag(uptr tag
) {
40 TagData
*tag_data
= GetTagData(tag
);
41 return tag_data
? tag_data
->header
: nullptr;
44 void InsertShadowStackFrameForTag(ThreadState
*thr
, uptr tag
) {
45 FuncEntry(thr
, (uptr
)®istered_tags
[tag
]);
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))
53 return (TagData
*)pc_ptr
- GetTagData(0);
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
);
65 if (!caller_pc
|| !libignore()->IsIgnored((uptr
)caller_pc
, &in_ignored_lib
)) {
66 access(thr
, CALLERPC
, (uptr
)addr
, kSizeLog1
);
69 if (caller_pc
) FuncExit(thr
);
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
;
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
);
92 (char *)atomic_exchange(header_ptr
, (uptr
)header
, memory_order_seq_cst
);
93 if (old_header
) internal_free(old_header
);
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();
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
);
110 SANITIZER_INTERFACE_ATTRIBUTE
111 void __tsan_external_read(void *addr
, void *caller_pc
, void *tag
) {
112 ExternalAccess(addr
, caller_pc
, tag
, MemoryRead
);
115 SANITIZER_INTERFACE_ATTRIBUTE
116 void __tsan_external_write(void *addr
, void *caller_pc
, void *tag
) {
117 ExternalAccess(addr
, caller_pc
, tag
, MemoryWrite
);
121 #endif // !SANITIZER_GO
123 } // namespace __tsan