Skip to content

Commit c8e7181

Browse files
Internal change
PiperOrigin-RevId: 756459725
1 parent 480de87 commit c8e7181

File tree

2 files changed

+50
-4
lines changed

2 files changed

+50
-4
lines changed

upb/mem/arena.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,9 @@ static upb_Arena* _upb_Arena_InitSlow(upb_alloc* alloc, size_t first_size) {
441441
upb_Atomic_Init(&a->body.space_allocated, actual_block_size);
442442
a->body.blocks = NULL;
443443
a->body.upb_alloc_cleanup = NULL;
444+
#ifndef __STDC_NO_THREADS__
445+
a->head.tid = 0;
446+
#endif
444447
UPB_PRIVATE(upb_Xsan_Init)(UPB_XSAN(&a->body));
445448

446449
_upb_Arena_AddBlock(&a->head, mem, first_block_overhead, actual_block_size);
@@ -479,6 +482,9 @@ upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) {
479482
a->body.block_alloc = _upb_Arena_MakeBlockAlloc(alloc, 1);
480483
a->head.UPB_PRIVATE(ptr) = (void*)UPB_ALIGN_MALLOC((uintptr_t)(a + 1));
481484
a->head.UPB_PRIVATE(end) = UPB_PTR_AT(mem, n, char);
485+
#ifndef __STDC_NO_THREADS__
486+
a->head.tid = 0;
487+
#endif
482488
UPB_PRIVATE(upb_Xsan_Init)(UPB_XSAN(&a->body));
483489
#ifdef UPB_TRACING_ENABLED
484490
upb_Arena_LogInit(&a->head, n);

upb/mem/internal/arena.h

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
#include <stddef.h>
1212
#include <stdint.h>
1313
#include <string.h>
14+
#ifndef __STDC_NO_THREADS__
15+
#include <threads.h>
16+
#endif
1417

18+
#include "upb/port/atomic.h"
1519
#include "upb/port/sanitizers.h"
1620

1721
// Must be last.
@@ -22,13 +26,16 @@
2226
//
2327
// We need this because the decoder inlines a upb_Arena for performance but
2428
// 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))
2630

2731
// LINT.IfChange(upb_Arena)
2832

2933
struct upb_Arena {
3034
char* UPB_ONLYBITS(ptr);
3135
char* UPB_ONLYBITS(end);
36+
#ifndef __STDC_NO_THREADS__
37+
UPB_ATOMIC(thrd_t) tid;
38+
#endif
3239
UPB_XSAN_MEMBER
3340
};
3441

@@ -38,6 +45,32 @@ struct upb_Arena {
3845
extern "C" {
3946
#endif
4047

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+
4174
void UPB_PRIVATE(_upb_Arena_SwapIn)(struct upb_Arena* des,
4275
const struct upb_Arena* src);
4376
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) {
6396
}
6497

6598
UPB_API_INLINE void* upb_Arena_Malloc(struct upb_Arena* a, size_t size) {
99+
uintptr_t tid = enterTid(a);
66100
UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a));
67101

68102
size_t span = UPB_PRIVATE(_upb_Arena_AllocSpan)(size);
69103

70104
if (UPB_UNLIKELY(UPB_PRIVATE(_upb_ArenaHas)(a) < span)) {
71105
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;
73109
}
74110

75111
// We have enough space to do a fast malloc.
76112
void* ret = a->UPB_ONLYBITS(ptr);
77113
a->UPB_ONLYBITS(ptr) += span;
78114
UPB_ASSERT(UPB_PRIVATE(_upb_Arena_IsAligned)(ret));
79115
UPB_ASSERT(UPB_PRIVATE(_upb_Arena_IsAligned)(a->UPB_ONLYBITS(ptr)));
80-
116+
exitTid(a, tid);
81117
return UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)(UPB_XSAN(a), ret, size);
82118
}
83119

@@ -123,6 +159,7 @@ UPB_API_INLINE bool upb_Arena_TryExtend(struct upb_Arena* a, void* ptr,
123159

124160
UPB_API_INLINE void* upb_Arena_Realloc(struct upb_Arena* a, void* ptr,
125161
size_t oldsize, size_t size) {
162+
uintptr_t tid = enterTid(a);
126163
UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a));
127164

128165
void* ret;
@@ -145,7 +182,10 @@ UPB_API_INLINE void* upb_Arena_Realloc(struct upb_Arena* a, void* ptr,
145182
// We want to invalidate pointers to the old region if hwasan is enabled, so
146183
// we poison and unpoison even if ptr == ret.
147184
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;
149189
}
150190

151191
#ifdef __cplusplus

0 commit comments

Comments
 (0)