xalloc-oversized.h 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. /* xalloc-oversized.h -- memory allocation size checking
  2. Copyright (C) 1990-2000, 2003-2004, 2006-2022 Free Software Foundation, Inc.
  3. This file is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as
  5. published by the Free Software Foundation; either version 2.1 of the
  6. License, or (at your option) any later version.
  7. This file is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. #ifndef XALLOC_OVERSIZED_H_
  14. #define XALLOC_OVERSIZED_H_
  15. #include <stddef.h>
  16. #include <stdint.h>
  17. /* True if N * S does not fit into both ptrdiff_t and size_t.
  18. N and S should be nonnegative and free of side effects.
  19. This expands to a constant expression if N and S are both constants.
  20. By gnulib convention, SIZE_MAX represents overflow in size_t
  21. calculations, so the conservative size_t-based dividend to use here
  22. is SIZE_MAX - 1. */
  23. #define __xalloc_oversized(n, s) \
  24. ((s) != 0 \
  25. && ((size_t) (PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX - 1) / (s) \
  26. < (n)))
  27. /* Return 1 if and only if an array of N objects, each of size S,
  28. cannot exist reliably because its total size in bytes would exceed
  29. MIN (PTRDIFF_MAX, SIZE_MAX - 1).
  30. N and S should be nonnegative and free of side effects.
  31. Warning: (xalloc_oversized (N, S) ? NULL : malloc (N * S)) can
  32. misbehave if N and S are both narrower than ptrdiff_t and size_t,
  33. and can be rewritten as (xalloc_oversized (N, S) ? NULL
  34. : malloc (N * (size_t) S)).
  35. This is a macro, not a function, so that it works even if an
  36. argument exceeds MAX (PTRDIFF_MAX, SIZE_MAX). */
  37. #if 7 <= __GNUC__ && !defined __clang__ && PTRDIFF_MAX < SIZE_MAX
  38. # define xalloc_oversized(n, s) \
  39. __builtin_mul_overflow_p (n, s, (ptrdiff_t) 1)
  40. #elif (5 <= __GNUC__ && !defined __ICC && !__STRICT_ANSI__ \
  41. && PTRDIFF_MAX < SIZE_MAX)
  42. # define xalloc_oversized(n, s) \
  43. (__builtin_constant_p (n) && __builtin_constant_p (s) \
  44. ? __xalloc_oversized (n, s) \
  45. : ({ ptrdiff_t __xalloc_count; \
  46. __builtin_mul_overflow (n, s, &__xalloc_count); }))
  47. /* Other compilers use integer division; this may be slower but is
  48. more portable. */
  49. #else
  50. # define xalloc_oversized(n, s) __xalloc_oversized (n, s)
  51. #endif
  52. #endif /* !XALLOC_OVERSIZED_H_ */