Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-13 08:34:20

0001 // Protocol Buffers - Google's data interchange format
0002 // Copyright 2025 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_PORT_SANITIZERS_H_
0009 #define UPB_PORT_SANITIZERS_H_
0010 
0011 #include <stddef.h>
0012 #include <stdint.h>
0013 #include <stdio.h>
0014 
0015 // Must be last.
0016 #include "upb/port/def.inc"
0017 
0018 // Must be inside def.inc/undef.inc
0019 #if UPB_HWASAN
0020 #include <sanitizer/hwasan_interface.h>
0021 #endif
0022 
0023 #ifdef __cplusplus
0024 extern "C" {
0025 #endif
0026 
0027 // UPB_ARENA_SIZE_HACK depends on this struct having size 1.
0028 typedef struct {
0029   uint8_t state;
0030 } upb_Xsan;
0031 
0032 UPB_INLINE uint8_t _upb_Xsan_NextTag(upb_Xsan *xsan) {
0033 #if UPB_HWASAN
0034   xsan->state++;
0035   if (xsan->state <= UPB_HWASAN_POISON_TAG) {
0036     xsan->state = UPB_HWASAN_POISON_TAG + 1;
0037   }
0038   return xsan->state;
0039 #else
0040   return 0;
0041 #endif
0042 }
0043 
0044 enum {
0045 #if UPB_ASAN
0046   UPB_PRIVATE(kUpb_Asan_GuardSize) = 32,
0047 #else
0048   UPB_PRIVATE(kUpb_Asan_GuardSize) = 0,
0049 #endif
0050 };
0051 
0052 UPB_INLINE uint8_t UPB_PRIVATE(_upb_Xsan_GetTag)(const void *addr) {
0053 #if UPB_HWASAN
0054   return __hwasan_get_tag_from_pointer(addr);
0055 #else
0056   return 0;
0057 #endif
0058 }
0059 
0060 UPB_INLINE void UPB_PRIVATE(upb_Xsan_Init)(upb_Xsan *xsan) {
0061 #if UPB_HWASAN || UPB_TSAN
0062   xsan->state = 0;
0063 #endif
0064 }
0065 
0066 // Marks the given region as poisoned, meaning that it is not accessible until
0067 // it is unpoisoned.
0068 UPB_INLINE void UPB_PRIVATE(upb_Xsan_PoisonRegion)(const void *addr,
0069                                                    size_t size) {
0070 #if UPB_ASAN
0071   void __asan_poison_memory_region(void const volatile *addr, size_t size);
0072   __asan_poison_memory_region(addr, size);
0073 #elif UPB_HWASAN
0074   __hwasan_tag_memory(addr, UPB_HWASAN_POISON_TAG, UPB_ALIGN_MALLOC(size));
0075 #endif
0076 }
0077 
0078 UPB_INLINE void *UPB_PRIVATE(_upb_Xsan_UnpoisonRegion)(void *addr, size_t size,
0079                                                        uint8_t tag) {
0080 #if UPB_ASAN
0081   UPB_UNUSED(tag);
0082   void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
0083   __asan_unpoison_memory_region(addr, size);
0084   return addr;
0085 #elif UPB_HWASAN
0086   __hwasan_tag_memory(addr, tag, UPB_ALIGN_MALLOC(size));
0087   return __hwasan_tag_pointer(addr, tag);
0088 #else
0089   UPB_UNUSED(size);
0090   UPB_UNUSED(tag);
0091 
0092   // `addr` is the pointer that will be returned from arena alloc/realloc
0093   // functions.  In this code-path we know it must be non-NULL, but the compiler
0094   // doesn't know this unless we add a UPB_ASSUME() annotation.
0095   //
0096   // This will let the optimizer optimize away NULL-checks if it can see that
0097   // this path was taken.
0098   UPB_ASSUME(addr);
0099   return addr;
0100 #endif
0101 }
0102 
0103 // Allows users to read and write to the given region, which will be considered
0104 // distinct from other regions and may only be accessed through the returned
0105 // pointer.
0106 //
0107 // `addr` must be aligned to the malloc alignment.  Size may be unaligned,
0108 // and with ASAN we can respect `size` precisely, but with HWASAN we must
0109 // round `size` up to the next multiple of the malloc alignment, so the caller
0110 // must guarantee that rounding up `size` will not cause overlap with other
0111 // regions.
0112 UPB_INLINE void *UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)(upb_Xsan *xsan,
0113                                                            void *addr,
0114                                                            size_t size) {
0115   return UPB_PRIVATE(_upb_Xsan_UnpoisonRegion)(addr, size,
0116                                                _upb_Xsan_NextTag(xsan));
0117 }
0118 
0119 // Resizes the given region to a new size, *without* invalidating any existing
0120 // pointers to the region.
0121 //
0122 // `tagged_addr` must be a pointer that was previously returned from
0123 // `upb_Xsan_NewUnpoisonedRegion`.  `old_size` must be the size that was
0124 // originally passed to `upb_Xsan_NewUnpoisonedRegion`.
0125 UPB_INLINE void *UPB_PRIVATE(upb_Xsan_ResizeUnpoisonedRegion)(void *tagged_addr,
0126                                                               size_t old_size,
0127                                                               size_t new_size) {
0128   UPB_PRIVATE(upb_Xsan_PoisonRegion)(tagged_addr, old_size);
0129   return UPB_PRIVATE(_upb_Xsan_UnpoisonRegion)(
0130       tagged_addr, new_size, UPB_PRIVATE(_upb_Xsan_GetTag)(tagged_addr));
0131 }
0132 
0133 // Compares two pointers and returns true if they are equal. This returns the
0134 // correct result even if one or both of the pointers are tagged.
0135 UPB_INLINE bool UPB_PRIVATE(upb_Xsan_PtrEq)(const void *a, const void *b) {
0136 #if UPB_HWASAN
0137   return __hwasan_tag_pointer(a, 0) == __hwasan_tag_pointer(b, 0);
0138 #else
0139   return a == b;
0140 #endif
0141 }
0142 
0143 // These annotations improve TSAN's ability to detect data races.  By
0144 // proactively accessing a non-atomic variable at the point where it is
0145 // "logically" accessed, we can trigger TSAN diagnostics that might have
0146 // otherwise been masked by subsequent atomic operations.
0147 
0148 UPB_INLINE void UPB_PRIVATE(upb_Xsan_AccessReadOnly)(upb_Xsan *xsan) {
0149 #if UPB_TSAN
0150   // For performance we avoid using a volatile variable.
0151   __asm__ volatile("" ::"r"(xsan->state));
0152 #endif
0153 }
0154 
0155 UPB_INLINE void UPB_PRIVATE(upb_Xsan_AccessReadWrite)(upb_Xsan *xsan) {
0156 #if UPB_TSAN
0157   // For performance we avoid using a volatile variable.
0158   __asm__ volatile("" : "+r"(xsan->state));
0159 #endif
0160 }
0161 
0162 #ifdef __cplusplus
0163 } /* extern "C" */
0164 #endif
0165 
0166 #include "upb/port/undef.inc"
0167 
0168 #endif  // UPB_PORT_SANITIZERS_H_