summaryrefslogtreecommitdiff
path: root/lib/xalloc-oversized.h
blob: bd94e289d9222d9b42051460372d76e0b120cf2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* xalloc-oversized.h -- memory allocation size checking

   Copyright (C) 1990-2000, 2003-2004, 2006-2017 Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or
   modify it under the terms of either:

     * the GNU Lesser General Public License as published by the Free
       Software Foundation; either version 3 of the License, or (at your
       option) any later version.

   or

     * the GNU General Public License as published by the Free
       Software Foundation; either version 2 of the License, or (at your
       option) any later version.

   or both in parallel, as here.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */

#ifndef XALLOC_OVERSIZED_H_
#define XALLOC_OVERSIZED_H_

#include <stddef.h>
#include <stdint.h>

/* True if N * S would overflow in a size_t calculation,
   or would generate a value larger than PTRDIFF_MAX.
   This expands to a constant expression if N and S are both constants.
   By gnulib convention, SIZE_MAX represents overflow in size
   calculations, so the conservative size_t-based dividend to use here
   is SIZE_MAX - 1.  */
#define __xalloc_oversized(n, s) \
  ((size_t) (PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX - 1) / (s) < (n))

#if PTRDIFF_MAX < SIZE_MAX
typedef ptrdiff_t __xalloc_count_type;
#else
typedef size_t __xalloc_count_type;
#endif

/* Return 1 if an array of N objects, each of size S, cannot exist
   reliably due to size or ptrdiff_t arithmetic overflow.  S must be
   positive and N must be nonnegative.  This is a macro, not a
   function, so that it works correctly even when SIZE_MAX < N.  */

#if 7 <= __GNUC__
# define xalloc_oversized(n, s) \
   __builtin_mul_overflow_p (n, s, (__xalloc_count_type) 1)
#elif 5 <= __GNUC__ && !defined __ICC && !__STRICT_ANSI__
# define xalloc_oversized(n, s) \
   (__builtin_constant_p (n) && __builtin_constant_p (s) \
    ? __xalloc_oversized (n, s) \
    : ({ __xalloc_count_type __xalloc_count; \
         __builtin_mul_overflow (n, s, &__xalloc_count); }))

/* Other compilers use integer division; this may be slower but is
   more portable.  */
#else
# define xalloc_oversized(n, s) __xalloc_oversized (n, s)
#endif

#endif /* !XALLOC_OVERSIZED_H_ */