diff --git a/libc/src/string/memory_utils/elements.h b/libc/src/string/memory_utils/elements.h --- a/libc/src/string/memory_utils/elements.h +++ b/libc/src/string/memory_utils/elements.h @@ -348,11 +348,30 @@ // `_inline` versions of all the builtins. Theoretically, Clang can still turn // them into calls to the C library leading to reentrancy problems. namespace builtin { + +// __builtin_memcpy_inline guarantees to never call external functions. +// Unfortunately it is not widely available. +#ifdef __clang__ +#if __has_builtin(__builtin_memcpy_inline) +#define USE_BUILTIN_MEMCPY_INLINE +#endif +#elif defined(__GNUC__) +#define USE_BUILTIN_MEMCPY +#endif + template struct Builtin { static constexpr size_t kSize = Size; static void Copy(char *__restrict dst, const char *__restrict src) { +#if LLVM_LIBC_HAVE_MEMORY_SANITIZER || LLVM_LIBC_HAVE_ADDRESS_SANITIZER + ForLoopCopy(dst, src); +#elif defined(USE_BUILTIN_MEMCPY_INLINE) __builtin_memcpy_inline(dst, src, kSize); +#elif defined(USE_BUILTIN_MEMCPY) + __builtin_memcpy(dst, src, kSize); +#else + ForLoopCopy(dst, src); +#endif } static bool Equals(const char *lhs, const char *rhs) { @@ -366,8 +385,21 @@ static void SplatSet(char *dst, const unsigned char value) { __builtin_memset(dst, value, kSize); } + +private: + // Copies `kBlockSize` bytes from `src` to `dst` using a for loop. + // This code requires the use of `-fno-buitin-memcpy` to prevent the compiler + // from turning the for-loop back into `__builtin_memcpy`. + template + static void ForLoopCopy(char *__restrict dst, const char *__restrict src) { + for (size_t i = 0; i < kBlockSize; ++i) + dst[i] = src[i]; + } }; +#undef USE_BUILTIN_MEMCPY_INLINE +#undef USE_BUILTIN_MEMCPY + using _1 = Builtin<1>; using _2 = Builtin<2>; using _3 = Builtin<3>; @@ -407,11 +439,11 @@ private: static T Load(const char *ptr) { T value; - __builtin_memcpy_inline(&value, ptr, kSize); + builtin::Builtin::Copy(reinterpret_cast(&value), ptr); return value; } static void Store(char *ptr, T value) { - __builtin_memcpy_inline(ptr, &value, kSize); + builtin::Builtin::Copy(ptr, reinterpret_cast(&value)); } static T GetSplattedValue(const unsigned char value) { return T(~0) / T(0xFF) * T(value); diff --git a/libc/test/src/string/memory_utils/CMakeLists.txt b/libc/test/src/string/memory_utils/CMakeLists.txt --- a/libc/test/src/string/memory_utils/CMakeLists.txt +++ b/libc/test/src/string/memory_utils/CMakeLists.txt @@ -12,9 +12,3 @@ COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE} ) - -target_compile_definitions( - libc.test.src.string.memory_utils.utils_test - PRIVATE - LLVM_LIBC_MEMCPY_MONITOR=memcpy_monitor -)