diff options
author | Abseil Team <absl-team@google.com> | 2023-12-28 11:32:04 -0800 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-12-28 11:32:54 -0800 |
commit | 1ac355bbb7e1e3c7916d812976127cf15c411bd3 (patch) | |
tree | 5a0de1ad8ce94aa23f61036becd82490ab4f07b9 | |
parent | f9228ec834edef9b623d4824dd006890c203adc3 (diff) |
Add compile-checks to ensure the parameter to absl::numbers_internal::FastIntToBuffer isn't provably insufficient
This performance-sensitive API is internal, and should not be used directly. Nevertheless, some do use it, so it's worth trying to block incorrect uses where we can.
PiperOrigin-RevId: 594289730
Change-Id: Ib5df39b450ef2ceda795082cde10ec2ba2642172
-rw-r--r-- | absl/base/macros.h | 12 | ||||
-rw-r--r-- | absl/strings/numbers.h | 18 |
2 files changed, 24 insertions, 6 deletions
diff --git a/absl/base/macros.h b/absl/base/macros.h index f33cd192..cd7cf498 100644 --- a/absl/base/macros.h +++ b/absl/base/macros.h @@ -138,4 +138,16 @@ ABSL_NAMESPACE_END #define ABSL_INTERNAL_RETHROW do {} while (false) #endif // ABSL_HAVE_EXCEPTIONS +// Requires the compiler to prove that the size of the given object is at least +// the expected amount. +#if ABSL_HAVE_ATTRIBUTE(diagnose_if) && ABSL_HAVE_BUILTIN(__builtin_object_size) +#define ABSL_INTERNAL_NEED_MIN_SIZE(Obj, N) \ + __attribute__((diagnose_if(__builtin_object_size(Obj, 0) < N, \ + "object size provably too small " \ + "(this would corrupt memory)", \ + "error"))) +#else +#define ABSL_INTERNAL_NEED_MIN_SIZE(Obj, N) +#endif + #endif // ABSL_BASE_MACROS_H_ diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h index 1d929de9..d2a89b98 100644 --- a/absl/strings/numbers.h +++ b/absl/strings/numbers.h @@ -166,18 +166,24 @@ static const int kSixDigitsToBufferSize = 16; // Required buffer size is `kSixDigitsToBufferSize`. size_t SixDigitsToBuffer(double d, absl::Nonnull<char*> buffer); -// These functions are intended for speed. All functions take an output buffer +// WARNING: These functions may write more characters than necessary, because +// they are intended for speed. All functions take an output buffer // as an argument and return a pointer to the last byte they wrote, which is the // terminating '\0'. At most `kFastToBufferSize` bytes are written. -absl::Nonnull<char*> FastIntToBuffer(int32_t, absl::Nonnull<char*>); -absl::Nonnull<char*> FastIntToBuffer(uint32_t, absl::Nonnull<char*>); -absl::Nonnull<char*> FastIntToBuffer(int64_t, absl::Nonnull<char*>); -absl::Nonnull<char*> FastIntToBuffer(uint64_t, absl::Nonnull<char*>); +absl::Nonnull<char*> FastIntToBuffer(int32_t i, absl::Nonnull<char*> buffer) + ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize); +absl::Nonnull<char*> FastIntToBuffer(uint32_t i, absl::Nonnull<char*> buffer) + ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize); +absl::Nonnull<char*> FastIntToBuffer(int64_t i, absl::Nonnull<char*> buffer) + ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize); +absl::Nonnull<char*> FastIntToBuffer(uint64_t i, absl::Nonnull<char*> buffer) + ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize); // For enums and integer types that are not an exact match for the types above, // use templates to call the appropriate one of the four overloads above. template <typename int_type> -absl::Nonnull<char*> FastIntToBuffer(int_type i, absl::Nonnull<char*> buffer) { +absl::Nonnull<char*> FastIntToBuffer(int_type i, absl::Nonnull<char*> buffer) + ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize) { static_assert(sizeof(i) <= 64 / 8, "FastIntToBuffer works only with 64-bit-or-less integers."); // TODO(jorg): This signed-ness check is used because it works correctly |