Skip to content

Commit c6677e8

Browse files
Internal change
PiperOrigin-RevId: 756459725
1 parent f9727e8 commit c6677e8

File tree

2 files changed

+49
-4
lines changed

2 files changed

+49
-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: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#include <stddef.h>
1212
#include <stdint.h>
1313
#include <string.h>
14+
#ifndef __STDC_NO_THREADS__
15+
#include <threads.h>
16+
#endif
1417

1518
#include "upb/port/sanitizers.h"
1619

@@ -22,13 +25,16 @@
2225
//
2326
// We need this because the decoder inlines a upb_Arena for performance but
2427
// 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))
28+
#define UPB_ARENA_SIZE_HACK (10 + (UPB_XSAN_STRUCT_SIZE * 2))
2629

2730
// LINT.IfChange(upb_Arena)
2831

2932
struct upb_Arena {
3033
char* UPB_ONLYBITS(ptr);
3134
char* UPB_ONLYBITS(end);
35+
#ifndef __STDC_NO_THREADS__
36+
UPB_ATOMIC(thrd_t) tid;
37+
#endif
3238
UPB_XSAN_MEMBER
3339
};
3440

@@ -38,6 +44,32 @@ struct upb_Arena {
3844
extern "C" {
3945
#endif
4046

47+
// enterTid() and exitTid() are used to compare the current thread ID to the
48+
// thread ID stored in the arena during allocations. If they are not the same
49+
// during arena malloc/realloc, the arena is being used by another thread and
50+
// should crash.
51+
#ifndef __STDC_NO_THREADS__
52+
static thrd_t enterTid(struct upb_Arena* a) {
53+
thrd_t t = thrd_current();
54+
thrd_t old = upb_Atomic_Exchange(&a->tid, t, memory_order_relaxed);
55+
if (old != t && old != 0) {
56+
__builtin_trap();
57+
}
58+
return old;
59+
}
60+
61+
static void exitTid(struct upb_Arena* a, uintptr_t tid) {
62+
thrd_t old = upb_Atomic_Exchange(&a->tid, tid, memory_order_relaxed);
63+
if (old != thrd_current()) {
64+
__builtin_trap();
65+
}
66+
}
67+
#else
68+
// No-op for non-threaded builds.
69+
static uintptr_t enterTid(struct upb_Arena* a) { return 0; }
70+
static void exitTid(struct upb_Arena* a, uintptr_t tid) {}
71+
#endif
72+
4173
void UPB_PRIVATE(_upb_Arena_SwapIn)(struct upb_Arena* des,
4274
const struct upb_Arena* src);
4375
void UPB_PRIVATE(_upb_Arena_SwapOut)(struct upb_Arena* des,
@@ -63,21 +95,24 @@ UPB_INLINE bool UPB_PRIVATE(_upb_Arena_IsAligned)(const void* ptr) {
6395
}
6496

6597
UPB_API_INLINE void* upb_Arena_Malloc(struct upb_Arena* a, size_t size) {
98+
uintptr_t tid = enterTid(a);
6699
UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a));
67100

68101
size_t span = UPB_PRIVATE(_upb_Arena_AllocSpan)(size);
69102

70103
if (UPB_UNLIKELY(UPB_PRIVATE(_upb_ArenaHas)(a) < span)) {
71104
void* UPB_PRIVATE(_upb_Arena_SlowMalloc)(struct upb_Arena * a, size_t size);
72-
return UPB_PRIVATE(_upb_Arena_SlowMalloc)(a, span);
105+
void* ret = UPB_PRIVATE(_upb_Arena_SlowMalloc)(a, span);
106+
exitTid(a, tid);
107+
return ret;
73108
}
74109

75110
// We have enough space to do a fast malloc.
76111
void* ret = a->UPB_ONLYBITS(ptr);
77112
a->UPB_ONLYBITS(ptr) += span;
78113
UPB_ASSERT(UPB_PRIVATE(_upb_Arena_IsAligned)(ret));
79114
UPB_ASSERT(UPB_PRIVATE(_upb_Arena_IsAligned)(a->UPB_ONLYBITS(ptr)));
80-
115+
exitTid(a, tid);
81116
return UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)(UPB_XSAN(a), ret, size);
82117
}
83118

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

124159
UPB_API_INLINE void* upb_Arena_Realloc(struct upb_Arena* a, void* ptr,
125160
size_t oldsize, size_t size) {
161+
uintptr_t tid = enterTid(a);
126162
UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a));
127163

128164
void* ret;
@@ -145,7 +181,10 @@ UPB_API_INLINE void* upb_Arena_Realloc(struct upb_Arena* a, void* ptr,
145181
// We want to invalidate pointers to the old region if hwasan is enabled, so
146182
// we poison and unpoison even if ptr == ret.
147183
UPB_PRIVATE(upb_Xsan_PoisonRegion)(ptr, oldsize);
148-
return UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)(UPB_XSAN(a), ret, size);
184+
void* ret_final =
185+
UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)(UPB_XSAN(a), ret, size);
186+
exitTid(a, tid);
187+
return ret_final;
149188
}
150189

151190
#ifdef __cplusplus

0 commit comments

Comments
 (0)