11
11
#include <stddef.h>
12
12
#include <stdint.h>
13
13
#include <string.h>
14
+ #ifndef __STDC_NO_THREADS__
15
+ #include <threads.h>
16
+ #endif
14
17
18
+ #include "upb/port/atomic.h"
15
19
#include "upb/port/sanitizers.h"
16
20
17
21
// Must be last.
22
26
//
23
27
// We need this because the decoder inlines a upb_Arena for performance but
24
28
// the full struct is not visible outside of arena.c. Yes, I know, it's awful.
25
- #define UPB_ARENA_SIZE_HACK (9 + (UPB_XSAN_STRUCT_SIZE * 2))
29
+ #define UPB_ARENA_SIZE_HACK (10 + (UPB_XSAN_STRUCT_SIZE * 2))
26
30
27
31
// LINT.IfChange(upb_Arena)
28
32
29
33
struct upb_Arena {
30
34
char * UPB_ONLYBITS (ptr );
31
35
char * UPB_ONLYBITS (end );
36
+ #ifndef __STDC_NO_THREADS__
37
+ UPB_ATOMIC (thrd_t ) tid ;
38
+ #endif
32
39
UPB_XSAN_MEMBER
33
40
};
34
41
@@ -38,6 +45,32 @@ struct upb_Arena {
38
45
extern "C" {
39
46
#endif
40
47
48
+ // enterTid() and exitTid() are used to compare the current thread ID to the
49
+ // thread ID stored in the arena during allocations. If they are not the same
50
+ // during arena malloc/realloc, the arena is being used by another thread and
51
+ // should crash.
52
+ #ifndef __STDC_NO_THREADS__
53
+ static thrd_t enterTid (struct upb_Arena * a ) {
54
+ thrd_t t = thrd_current ();
55
+ thrd_t old = upb_Atomic_Exchange (& a -> tid , t , memory_order_relaxed );
56
+ if (old != t && old != 0 ) {
57
+ __builtin_trap ();
58
+ }
59
+ return old ;
60
+ }
61
+
62
+ static void exitTid (struct upb_Arena * a , uintptr_t tid ) {
63
+ thrd_t old = upb_Atomic_Exchange (& a -> tid , tid , memory_order_relaxed );
64
+ if (old != thrd_current ()) {
65
+ __builtin_trap ();
66
+ }
67
+ }
68
+ #else
69
+ // No-op for non-threaded builds.
70
+ static uintptr_t enterTid (struct upb_Arena * a ) { return 0 ; }
71
+ static void exitTid (struct upb_Arena * a , uintptr_t tid ) {}
72
+ #endif
73
+
41
74
void UPB_PRIVATE (_upb_Arena_SwapIn )(struct upb_Arena * des ,
42
75
const struct upb_Arena * src );
43
76
void UPB_PRIVATE (_upb_Arena_SwapOut )(struct upb_Arena * des ,
@@ -63,21 +96,24 @@ UPB_INLINE bool UPB_PRIVATE(_upb_Arena_IsAligned)(const void* ptr) {
63
96
}
64
97
65
98
UPB_API_INLINE void * upb_Arena_Malloc (struct upb_Arena * a , size_t size ) {
99
+ uintptr_t tid = enterTid (a );
66
100
UPB_PRIVATE (upb_Xsan_AccessReadWrite )(UPB_XSAN (a ));
67
101
68
102
size_t span = UPB_PRIVATE (_upb_Arena_AllocSpan )(size );
69
103
70
104
if (UPB_UNLIKELY (UPB_PRIVATE (_upb_ArenaHas )(a ) < span )) {
71
105
void * UPB_PRIVATE (_upb_Arena_SlowMalloc )(struct upb_Arena * a , size_t size );
72
- return UPB_PRIVATE (_upb_Arena_SlowMalloc )(a , span );
106
+ void * ret = UPB_PRIVATE (_upb_Arena_SlowMalloc )(a , span );
107
+ exitTid (a , tid );
108
+ return ret ;
73
109
}
74
110
75
111
// We have enough space to do a fast malloc.
76
112
void * ret = a -> UPB_ONLYBITS (ptr );
77
113
a -> UPB_ONLYBITS (ptr ) += span ;
78
114
UPB_ASSERT (UPB_PRIVATE (_upb_Arena_IsAligned )(ret ));
79
115
UPB_ASSERT (UPB_PRIVATE (_upb_Arena_IsAligned )(a -> UPB_ONLYBITS (ptr )));
80
-
116
+ exitTid ( a , tid );
81
117
return UPB_PRIVATE (upb_Xsan_NewUnpoisonedRegion )(UPB_XSAN (a ), ret , size );
82
118
}
83
119
@@ -123,6 +159,7 @@ UPB_API_INLINE bool upb_Arena_TryExtend(struct upb_Arena* a, void* ptr,
123
159
124
160
UPB_API_INLINE void * upb_Arena_Realloc (struct upb_Arena * a , void * ptr ,
125
161
size_t oldsize , size_t size ) {
162
+ uintptr_t tid = enterTid (a );
126
163
UPB_PRIVATE (upb_Xsan_AccessReadWrite )(UPB_XSAN (a ));
127
164
128
165
void * ret ;
@@ -145,7 +182,10 @@ UPB_API_INLINE void* upb_Arena_Realloc(struct upb_Arena* a, void* ptr,
145
182
// We want to invalidate pointers to the old region if hwasan is enabled, so
146
183
// we poison and unpoison even if ptr == ret.
147
184
UPB_PRIVATE (upb_Xsan_PoisonRegion )(ptr , oldsize );
148
- return UPB_PRIVATE (upb_Xsan_NewUnpoisonedRegion )(UPB_XSAN (a ), ret , size );
185
+ void * ret_final =
186
+ UPB_PRIVATE (upb_Xsan_NewUnpoisonedRegion )(UPB_XSAN (a ), ret , size );
187
+ exitTid (a , tid );
188
+ return ret_final ;
149
189
}
150
190
151
191
#ifdef __cplusplus
0 commit comments