blob: ae204845113031d0a356d544aec14ae5bfa639f6 [file]
// Protocol Buffers - Google's data interchange format
// Copyright 2026 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
#ifndef UPB_PORT_OVERFLOW_H_
#define UPB_PORT_OVERFLOW_H_
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
// Must be last
#include "upb/port/def.inc"
#if ((UPB_HAS_BUILTIN(__builtin_add_overflow) && \
UPB_HAS_BUILTIN(__builtin_mul_overflow)) || \
(defined(__GNUC__) && __GNUC__ >= 5)) && \
!defined(UPB_DISABLE_BUILTIN_OVERFLOW)
#define UPB_USE_BUILTIN_OVERFLOW
#endif
UPB_NODISCARD UPB_INLINE bool upb_AddOverflow_size_t_size_t(size_t a, size_t b,
size_t* out) {
#ifdef UPB_USE_BUILTIN_OVERFLOW
return __builtin_add_overflow(a, b, out);
#else
if (b > SIZE_MAX - a) return true;
*out = a + b;
return false;
#endif
}
UPB_NODISCARD UPB_INLINE bool upb_AddOverflow_size_t_uint32_t(size_t a,
uint32_t b,
size_t* out) {
#ifdef UPB_USE_BUILTIN_OVERFLOW
return __builtin_add_overflow(a, b, out);
#else
return upb_AddOverflow_size_t_size_t(a, (size_t)b, out);
#endif
}
UPB_NODISCARD UPB_INLINE bool upb_AddOverflow_uint32_t_size_t(uint32_t a,
size_t b,
size_t* out) {
#ifdef UPB_USE_BUILTIN_OVERFLOW
return __builtin_add_overflow(a, b, out);
#else
return upb_AddOverflow_size_t_size_t((size_t)a, b, out);
#endif
}
UPB_NODISCARD UPB_INLINE bool upb_MulOverflow_size_t_size_t(size_t a, size_t b,
size_t* out) {
#ifdef UPB_USE_BUILTIN_OVERFLOW
return __builtin_mul_overflow(a, b, out);
#else
if (b != 0 && a > SIZE_MAX / b) return true;
*out = a * b;
return false;
#endif
}
UPB_NODISCARD UPB_INLINE bool upb_MulOverflow_size_t_uint32_t(size_t a,
uint32_t b,
size_t* out) {
#ifdef UPB_USE_BUILTIN_OVERFLOW
return __builtin_mul_overflow(a, b, out);
#else
return upb_MulOverflow_size_t_size_t(a, (size_t)b, out);
#endif
}
UPB_NODISCARD UPB_INLINE bool upb_MulOverflow_uint32_t_size_t(uint32_t a,
size_t b,
size_t* out) {
#ifdef UPB_USE_BUILTIN_OVERFLOW
return __builtin_mul_overflow(a, b, out);
#else
return upb_MulOverflow_size_t_size_t((size_t)a, b, out);
#endif
}
#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus)
#if SIZE_MAX > 0xffffffffULL
#define upb_AddOverflow(a, b, out) \
_Generic((a), \
size_t: _Generic((b), \
size_t: upb_AddOverflow_size_t_size_t(a, b, out), \
uint32_t: upb_AddOverflow_size_t_uint32_t(a, b, out)), \
uint32_t: _Generic((b), \
size_t: upb_AddOverflow_uint32_t_size_t(a, b, out)))
#define upb_MulOverflow(a, b, out) \
_Generic((a), \
size_t: _Generic((b), \
size_t: upb_MulOverflow_size_t_size_t(a, b, out), \
uint32_t: upb_MulOverflow_size_t_uint32_t(a, b, out)), \
uint32_t: _Generic((b), \
size_t: upb_MulOverflow_uint32_t_size_t(a, b, out)))
#else
// On 32-bit platforms, size_t and uint32_t might be the same type.
// We fallback to direct calls without _Generic to avoid duplicate association
// errors.
#define upb_AddOverflow(a, b, out) upb_AddOverflow_size_t_size_t(a, b, out)
#define upb_MulOverflow(a, b, out) upb_MulOverflow_size_t_size_t(a, b, out)
#endif
#else
// Fallback for C++ or older C.
#define upb_AddOverflow(a, b, out) upb_AddOverflow_size_t_size_t(a, b, out)
#define upb_MulOverflow(a, b, out) upb_MulOverflow_size_t_size_t(a, b, out)
#endif
#include "upb/port/undef.inc"
#endif // UPB_PORT_OVERFLOW_H_