// Protocol Buffers - Google's data interchange format // Copyright 2023 Google LLC. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd /* * This is where we define internal portability macros used across upb. * * All of these macros are undef'd in undef.inc to avoid leaking them to users. * * The correct usage is: * * #include "upb/foobar.h" * #include "upb/baz.h" * * // MUST be last included header. * #include "upb/port/def.inc" * * // Code for this file. * // <...> * * // Can be omitted for .c files, required for .h. * #include "upb/port/undef.inc" * * This file is private and must not be included by users! */ #if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ (defined(__cplusplus) && __cplusplus >= 201402L) || \ (defined(_MSC_VER) && _MSC_VER >= 1900)) #error upb requires C99 or C++14 or MSVC >= 2015. #endif // Portable check for GCC minimum version: // https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html #if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) #define UPB_GNUC_MIN(x, y) \ (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) #else #define UPB_GNUC_MIN(x, y) 0 #endif #include #include #include #include #include #ifndef UINTPTR_MAX Error, UINTPTR_MAX is undefined #endif #if UINTPTR_MAX == 0xffffffff #define UPB_SIZE(size32, size64) size32 #else #define UPB_SIZE(size32, size64) size64 #endif /* If we always read/write as a consistent type to each address, this shouldn't * violate aliasing. */ #define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs))) #define UPB_MAPTYPE_STRING 0 // UPB_EXPORT: always generate a public symbol. #if defined(__GNUC__) || defined(__clang__) #define UPB_EXPORT __attribute__((visibility("default"))) __attribute__((used)) #else #define UPB_EXPORT #endif // UPB_INLINE: inline if possible, emit standalone code if required. #ifdef __cplusplus #define UPB_INLINE inline #elif defined (__GNUC__) || defined(__clang__) #define UPB_INLINE static __inline__ #else #define UPB_INLINE static #endif #ifdef UPB_BUILD_API #define UPB_API UPB_EXPORT #define UPB_API_INLINE UPB_EXPORT #else #define UPB_API #define UPB_API_INLINE UPB_INLINE #endif #define UPB_MALLOC_ALIGN 8 #define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) #define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) #define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) #ifdef __clang__ #define UPB_ALIGN_OF(type) _Alignof(type) #else #define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) #endif #ifdef _MSC_VER // Some versions of our Windows compiler don't support the C11 syntax. #define UPB_ALIGN_AS(x) __declspec(align(x)) #else #define UPB_ALIGN_AS(x) _Alignas(x) #endif // Hints to the compiler about likely/unlikely branches. #if defined (__GNUC__) || defined(__clang__) #define UPB_LIKELY(x) __builtin_expect((bool)(x), 1) #define UPB_UNLIKELY(x) __builtin_expect((bool)(x), 0) #else #define UPB_LIKELY(x) (x) #define UPB_UNLIKELY(x) (x) #endif // Macros for function attributes on compilers that support them. #ifdef __GNUC__ #define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) static #define UPB_NOINLINE __attribute__((noinline)) #define UPB_NORETURN __attribute__((__noreturn__)) #define UPB_PRINTF(str, first_vararg) __attribute__((format (printf, str, first_vararg))) #elif defined(_MSC_VER) #define UPB_NOINLINE #define UPB_FORCEINLINE static #define UPB_NORETURN __declspec(noreturn) #define UPB_PRINTF(str, first_vararg) #else /* !defined(__GNUC__) */ #define UPB_FORCEINLINE static #define UPB_NOINLINE #define UPB_NORETURN #define UPB_PRINTF(str, first_vararg) #endif #define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) #define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) #define UPB_UNUSED(var) (void)var // UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. #ifdef NDEBUG #ifdef __GNUC__ #define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable() #elif defined _MSC_VER #define UPB_ASSUME(expr) if (!(expr)) __assume(0) #else #define UPB_ASSUME(expr) do {} while (false && (expr)) #endif #else #define UPB_ASSUME(expr) assert(expr) #endif /* UPB_ASSERT(): in release mode, we use the expression without letting it be * evaluated. This prevents "unused variable" warnings. */ #ifdef NDEBUG #define UPB_ASSERT(expr) do {} while (false && (expr)) #else #define UPB_ASSERT(expr) assert(expr) #endif #if defined(__GNUC__) || defined(__clang__) #define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0) #elif defined(_MSC_VER) #define UPB_UNREACHABLE() \ do { \ assert(0); \ __assume(0); \ } while (0) #else #define UPB_UNREACHABLE() do { assert(0); } while(0) #endif /* UPB_SETJMP() / UPB_LONGJMP(): avoid setting/restoring signal mask. */ #ifdef __APPLE__ #define UPB_SETJMP(buf) _setjmp(buf) #define UPB_LONGJMP(buf, val) _longjmp(buf, val) #else #define UPB_SETJMP(buf) setjmp(buf) #define UPB_LONGJMP(buf, val) longjmp(buf, val) #endif #ifdef __GNUC__ #define UPB_USE_C11_ATOMICS #define UPB_ATOMIC(T) _Atomic(T) #else #define UPB_ATOMIC(T) T #endif /* UPB_PTRADD(ptr, ofs): add pointer while avoiding "NULL + 0" UB */ #define UPB_PTRADD(ptr, ofs) ((ofs) ? (ptr) + (ofs) : (ptr)) #define UPB_PRIVATE(x) x##_dont_copy_me__upb_internal_use_only #ifdef UPB_ALLOW_PRIVATE_ACCESS__FOR_BITS_ONLY #define UPB_ONLYBITS(x) x #else #define UPB_ONLYBITS(x) UPB_PRIVATE(x) #endif /* Configure whether fasttable is switched on or not. *************************/ #ifdef __has_attribute #define UPB_HAS_ATTRIBUTE(x) __has_attribute(x) #else #define UPB_HAS_ATTRIBUTE(x) 0 #endif #if UPB_HAS_ATTRIBUTE(musttail) #define UPB_MUSTTAIL __attribute__((musttail)) #else #define UPB_MUSTTAIL #endif #undef UPB_HAS_ATTRIBUTE /* This check is not fully robust: it does not require that we have "musttail" * support available. We need tail calls to avoid consuming arbitrary amounts * of stack space. * * GCC/Clang can mostly be trusted to generate tail calls as long as * optimization is enabled, but, debug builds will not generate tail calls * unless "musttail" is available. * * We should probably either: * 1. require that the compiler supports musttail. * 2. add some fallback code for when musttail isn't available (ie. return * instead of tail calling). This is safe and portable, but this comes at * a CPU cost. */ #if (defined(__x86_64__) || defined(__aarch64__)) && defined(__GNUC__) #define UPB_FASTTABLE_SUPPORTED 1 #else #define UPB_FASTTABLE_SUPPORTED 0 #endif /* define UPB_ENABLE_FASTTABLE to force fast table support. * This is useful when we want to ensure we are really getting fasttable, * for example for testing or benchmarking. */ #if defined(UPB_ENABLE_FASTTABLE) #if !UPB_FASTTABLE_SUPPORTED #error fasttable is x86-64/ARM64 only and requires GCC or Clang. #endif #define UPB_FASTTABLE 1 /* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible. * This is useful for releasing code that might be used on multiple platforms, * for example the PHP or Ruby C extensions. */ #elif defined(UPB_TRY_ENABLE_FASTTABLE) #define UPB_FASTTABLE UPB_FASTTABLE_SUPPORTED #else #define UPB_FASTTABLE 0 #endif /* UPB_FASTTABLE_INIT() allows protos compiled for fasttable to gracefully * degrade to non-fasttable if the runtime or platform do not support it. */ #if !UPB_FASTTABLE #define UPB_FASTTABLE_INIT(...) #define UPB_FASTTABLE_MASK(mask) -1 #else #define UPB_FASTTABLE_INIT(...) __VA_ARGS__ #define UPB_FASTTABLE_MASK(mask) mask #endif #undef UPB_FASTTABLE_SUPPORTED /* ASAN poisoning (for arena). * If using UPB from an interpreted language like Ruby, a build of the * interpreter compiled with ASAN enabled must be used in order to get sane and * expected behavior. */ /* Due to preprocessor limitations, the conditional logic for setting * UPN_CLANG_ASAN below cannot be consolidated into a portable one-liner. * See https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fattribute.html. */ #if defined(__has_feature) #if __has_feature(address_sanitizer) #define UPB_CLANG_ASAN 1 #else #define UPB_CLANG_ASAN 0 #endif #else #define UPB_CLANG_ASAN 0 #endif #if defined(__SANITIZE_ADDRESS__) || UPB_CLANG_ASAN #define UPB_ASAN 1 #define UPB_ASAN_GUARD_SIZE 32 #ifdef __cplusplus extern "C" { #endif void __asan_poison_memory_region(void const volatile *addr, size_t size); void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #ifdef __cplusplus } /* extern "C" */ #endif #define UPB_POISON_MEMORY_REGION(addr, size) \ __asan_poison_memory_region((addr), (size)) #define UPB_UNPOISON_MEMORY_REGION(addr, size) \ __asan_unpoison_memory_region((addr), (size)) #else #define UPB_ASAN 0 #define UPB_ASAN_GUARD_SIZE 0 #define UPB_POISON_MEMORY_REGION(addr, size) \ ((void)(addr), (void)(size)) #define UPB_UNPOISON_MEMORY_REGION(addr, size) \ ((void)(addr), (void)(size)) #endif /* Disable proto2 arena behavior (TEMPORARY) **********************************/ #ifdef UPB_DISABLE_CLOSED_ENUM_CHECKING #define UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN 1 #else #define UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN 0 #endif #if defined(__cplusplus) #if defined(__clang__) || UPB_GNUC_MIN(6, 0) // https://gcc.gnu.org/gcc-6/changes.html #if __cplusplus >= 201402L #define UPB_DEPRECATED [[deprecated]] #else #define UPB_DEPRECATED __attribute__((deprecated)) #endif #else #define UPB_DEPRECATED #endif #else #define UPB_DEPRECATED #endif // begin:google_only // #define UPB_IS_GOOGLE3 // end:google_only #if defined(UPB_IS_GOOGLE3) && !defined(UPB_BOOTSTRAP_STAGE0) #define UPB_DESC(sym) proto2_##sym #define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init #elif defined(UPB_BOOTSTRAP_STAGE0) #define UPB_DESC(sym) google_protobuf_##sym #define UPB_DESC_MINITABLE(sym) google__protobuf__##sym##_msg_init() #else #define UPB_DESC(sym) google_protobuf_##sym #define UPB_DESC_MINITABLE(sym) &google__protobuf__##sym##_msg_init #endif // Linker arrays combine elements from multiple translation units into a single // array that can be iterated over at runtime. // // It is an alternative to pre-main "registration" functions. // // Usage: // // // In N translation units. // UPB_LINKARR_APPEND(foo_array) static int elems[3] = {1, 2, 3}; // // // At runtime: // UPB_LINKARR_DECLARE(foo_array, int); // // void f() { // const int* start = UPB_LINKARR_START(foo_array); // const int* stop = UPB_LINKARR_STOP(foo_array); // for (const int* p = start; p < stop; p++) { // // Windows can introduce zero padding, so we have to skip zeroes. // if (*p != 0) { // vec.push_back(*p); // } // } // } #if defined(__ELF__) || defined(__wasm__) #define UPB_LINKARR_APPEND(name) \ __attribute__((retain, used, section("linkarr_" #name))) #define UPB_LINKARR_DECLARE(name, type) \ extern type const __start_linkarr_##name; \ extern type const __stop_linkarr_##name; \ UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] #define UPB_LINKARR_START(name) (&__start_linkarr_##name) #define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) #elif defined(__MACH__) /* As described in: https://stackoverflow.com/a/22366882 */ #define UPB_LINKARR_APPEND(name) \ __attribute__((retain, used, section("__DATA,__la_" #name))) #define UPB_LINKARR_DECLARE(name, type) \ extern type const __start_linkarr_##name __asm( \ "section$start$__DATA$__la_" #name); \ extern type const __stop_linkarr_##name __asm( \ "section$end$__DATA$" \ "__la_" #name); \ UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] #define UPB_LINKARR_START(name) (&__start_linkarr_##name) #define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) #elif defined(_MSC_VER) && defined(__clang__) /* See: * https://devblogs.microsoft.com/oldnewthing/20181107-00/?p=100155 * https://devblogs.microsoft.com/oldnewthing/20181108-00/?p=100165 * https://devblogs.microsoft.com/oldnewthing/20181109-00/?p=100175 */ // Usage of __attribute__ here probably means this is Clang-specific, and would // not work on MSVC. #define UPB_LINKARR_APPEND(name) \ __declspec(allocate("la_" #name "$j")) __attribute__((retain, used)) #define UPB_LINKARR_DECLARE(name, type) \ __declspec(allocate("la_" #name "$a")) type __start_linkarr_##name; \ __declspec(allocate("la_" #name "$z")) type __stop_linkarr_##name; \ UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] = {0} #define UPB_LINKARR_START(name) (&__start_linkarr_##name) #define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) #else // Linker arrays are not supported on this platform. Make appends a no-op but // don't define the other macros. #define UPB_LINKARR_APPEND(name) #endif