Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-18 09:32:11

0001 // Protocol Buffers - Google's data interchange format
0002 // Copyright 2023 Google LLC.  All rights reserved.
0003 //
0004 // Use of this source code is governed by a BSD-style
0005 // license that can be found in the LICENSE file or at
0006 // https://developers.google.com/open-source/licenses/bsd
0007 
0008 #ifndef UPB_MEM_INTERNAL_ARENA_H_
0009 #define UPB_MEM_INTERNAL_ARENA_H_
0010 
0011 #include <stddef.h>
0012 #include <stdint.h>
0013 #include <string.h>
0014 
0015 #include "upb/port/sanitizers.h"
0016 
0017 // Must be last.
0018 #include "upb/port/def.inc"
0019 
0020 // This is QUITE an ugly hack, which specifies the number of pointers needed
0021 // to equal (or exceed) the storage required for one upb_Arena.
0022 //
0023 // We need this because the decoder inlines a upb_Arena for performance but
0024 // the full struct is not visible outside of arena.c. Yes, I know, it's awful.
0025 #define UPB_ARENA_SIZE_HACK (10 + (UPB_XSAN_STRUCT_SIZE * 2))
0026 
0027 // LINT.IfChange(upb_Arena)
0028 
0029 struct upb_Arena {
0030   char* UPB_ONLYBITS(ptr);
0031   const UPB_NODEREF char* UPB_ONLYBITS(end);
0032   UPB_XSAN_MEMBER
0033 };
0034 
0035 // LINT.ThenChange(//depot/google3/third_party/upb/bits/typescript/arena.ts:upb_Arena)
0036 
0037 #ifdef __cplusplus
0038 extern "C" {
0039 #endif
0040 
0041 void UPB_PRIVATE(_upb_Arena_SwapIn)(struct upb_Arena* des,
0042                                     const struct upb_Arena* src);
0043 void UPB_PRIVATE(_upb_Arena_SwapOut)(struct upb_Arena* des,
0044                                      const struct upb_Arena* src);
0045 
0046 UPB_INLINE size_t UPB_PRIVATE(_upb_ArenaHas)(const struct upb_Arena* a) {
0047   return (size_t)(a->UPB_ONLYBITS(end) - a->UPB_ONLYBITS(ptr));
0048 }
0049 
0050 UPB_INLINE size_t UPB_PRIVATE(_upb_Arena_AllocSpan)(size_t size) {
0051   return UPB_ALIGN_MALLOC(size) + UPB_PRIVATE(kUpb_Asan_GuardSize);
0052 }
0053 
0054 UPB_INLINE bool UPB_PRIVATE(_upb_Arena_WasLastAllocFromCurrentBlock)(
0055     const struct upb_Arena* a, void* ptr, size_t size) {
0056   return UPB_PRIVATE(upb_Xsan_PtrEq)(
0057       (char*)ptr + UPB_PRIVATE(_upb_Arena_AllocSpan)(size),
0058       a->UPB_ONLYBITS(ptr));
0059 }
0060 
0061 UPB_INLINE bool UPB_PRIVATE(_upb_Arena_IsAligned)(const void* ptr) {
0062   return (uintptr_t)ptr % UPB_MALLOC_ALIGN == 0;
0063 }
0064 
0065 UPB_API_INLINE void* upb_Arena_Malloc(struct upb_Arena* a, size_t size) {
0066   UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a));
0067 
0068   size_t span = UPB_PRIVATE(_upb_Arena_AllocSpan)(size);
0069 
0070   if (UPB_UNLIKELY(UPB_PRIVATE(_upb_ArenaHas)(a) < span)) {
0071     void* UPB_PRIVATE(_upb_Arena_SlowMalloc)(struct upb_Arena * a, size_t size);
0072     return UPB_PRIVATE(_upb_Arena_SlowMalloc)(a, span);
0073   }
0074 
0075   // We have enough space to do a fast malloc.
0076   void* ret = a->UPB_ONLYBITS(ptr);
0077   a->UPB_ONLYBITS(ptr) += span;
0078   UPB_ASSERT(UPB_PRIVATE(_upb_Arena_IsAligned)(ret));
0079   UPB_ASSERT(UPB_PRIVATE(_upb_Arena_IsAligned)(a->UPB_ONLYBITS(ptr)));
0080 
0081   return UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)(UPB_XSAN(a), ret, size);
0082 }
0083 
0084 UPB_API_INLINE void upb_Arena_ShrinkLast(struct upb_Arena* a, void* ptr,
0085                                          size_t oldsize, size_t size) {
0086   UPB_ASSERT(ptr);
0087   UPB_ASSERT(size <= oldsize);
0088 
0089   UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a));
0090   UPB_PRIVATE(upb_Xsan_ResizeUnpoisonedRegion)(ptr, oldsize, size);
0091 
0092   if (UPB_PRIVATE(_upb_Arena_WasLastAllocFromCurrentBlock)(a, ptr, oldsize)) {
0093     // We can reclaim some memory.
0094     a->UPB_ONLYBITS(ptr) -= UPB_ALIGN_MALLOC(oldsize) - UPB_ALIGN_MALLOC(size);
0095   } else {
0096     // We can't reclaim any memory, but we need to verify that `ptr` really
0097     // does represent the most recent allocation.
0098 #ifndef NDEBUG
0099     bool _upb_Arena_WasLastAlloc(struct upb_Arena * a, void* ptr,
0100                                  size_t oldsize);
0101     UPB_ASSERT(_upb_Arena_WasLastAlloc(a, ptr, oldsize));
0102 #endif
0103   }
0104 }
0105 
0106 UPB_API_INLINE bool upb_Arena_TryExtend(struct upb_Arena* a, void* ptr,
0107                                         size_t oldsize, size_t size) {
0108   UPB_ASSERT(ptr);
0109   UPB_ASSERT(size > oldsize);
0110 
0111   UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a));
0112   size_t extend = UPB_ALIGN_MALLOC(size) - UPB_ALIGN_MALLOC(oldsize);
0113 
0114   if (UPB_PRIVATE(_upb_Arena_WasLastAllocFromCurrentBlock)(a, ptr, oldsize) &&
0115       UPB_PRIVATE(_upb_ArenaHas)(a) >= extend) {
0116     a->UPB_ONLYBITS(ptr) += extend;
0117     UPB_PRIVATE(upb_Xsan_ResizeUnpoisonedRegion)(ptr, oldsize, size);
0118     return true;
0119   }
0120 
0121   return false;
0122 }
0123 
0124 UPB_API_INLINE void* upb_Arena_Realloc(struct upb_Arena* a, void* ptr,
0125                                        size_t oldsize, size_t size) {
0126   UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a));
0127 
0128   void* ret;
0129 
0130   if (ptr && (size <= oldsize || upb_Arena_TryExtend(a, ptr, oldsize, size))) {
0131     // We can extend or shrink in place.
0132     if (size <= oldsize &&
0133         UPB_PRIVATE(_upb_Arena_WasLastAllocFromCurrentBlock)(a, ptr, oldsize)) {
0134       upb_Arena_ShrinkLast(a, ptr, oldsize, size);
0135     }
0136     ret = ptr;
0137   } else {
0138     // We need to copy into a new allocation.
0139     ret = upb_Arena_Malloc(a, size);
0140     if (ret && oldsize > 0) {
0141       memcpy(ret, ptr, UPB_MIN(oldsize, size));
0142     }
0143   }
0144 
0145   // We want to invalidate pointers to the old region if hwasan is enabled, so
0146   // we poison and unpoison even if ptr == ret.
0147   UPB_PRIVATE(upb_Xsan_PoisonRegion)(ptr, oldsize);
0148   return UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)(UPB_XSAN(a), ret, size);
0149 }
0150 
0151 #ifdef __cplusplus
0152 } /* extern "C" */
0153 #endif
0154 
0155 #include "upb/port/undef.inc"
0156 
0157 #endif /* UPB_MEM_INTERNAL_ARENA_H_ */