File Coverage

deps/libgit2/src/util/integer.h
Criterion Covered Total %
statement 0 3 0.0
branch n/a
condition n/a
subroutine n/a
pod n/a
total 0 3 0.0


line stmt bran cond sub pod time code
1             /*
2             * Copyright (C) the libgit2 contributors. All rights reserved.
3             *
4             * This file is part of libgit2, distributed under the GNU GPL v2 with
5             * a Linking Exception. For full terms see the included COPYING file.
6             */
7             #ifndef INCLUDE_integer_h__
8             #define INCLUDE_integer_h__
9              
10             /** @return true if p fits into the range of a size_t */
11 0           GIT_INLINE(int) git__is_sizet(int64_t p)
12             {
13 0           size_t r = (size_t)p;
14 0           return p == (int64_t)r;
15             }
16              
17             /** @return true if p fits into the range of an ssize_t */
18             GIT_INLINE(int) git__is_ssizet(size_t p)
19             {
20             ssize_t r = (ssize_t)p;
21             return p == (size_t)r;
22             }
23              
24             /** @return true if p fits into the range of a uint16_t */
25             GIT_INLINE(int) git__is_uint16(size_t p)
26             {
27             uint16_t r = (uint16_t)p;
28             return p == (size_t)r;
29             }
30              
31             /** @return true if p fits into the range of a uint32_t */
32             GIT_INLINE(int) git__is_uint32(size_t p)
33             {
34             uint32_t r = (uint32_t)p;
35             return p == (size_t)r;
36             }
37              
38             /** @return true if p fits into the range of an unsigned long */
39             GIT_INLINE(int) git__is_ulong(int64_t p)
40             {
41             unsigned long r = (unsigned long)p;
42             return p == (int64_t)r;
43             }
44              
45             /** @return true if p fits into the range of an int */
46             GIT_INLINE(int) git__is_int(int64_t p)
47             {
48             int r = (int)p;
49             return p == (int64_t)r;
50             }
51              
52             /* Use clang/gcc compiler intrinsics whenever possible */
53             #if (__has_builtin(__builtin_add_overflow) || \
54             (defined(__GNUC__) && (__GNUC__ >= 5)))
55              
56             # if (SIZE_MAX == UINT_MAX)
57             # define git__add_sizet_overflow(out, one, two) \
58             __builtin_uadd_overflow(one, two, out)
59             # define git__multiply_sizet_overflow(out, one, two) \
60             __builtin_umul_overflow(one, two, out)
61             # elif (SIZE_MAX == ULONG_MAX)
62             # define git__add_sizet_overflow(out, one, two) \
63             __builtin_uaddl_overflow(one, two, out)
64             # define git__multiply_sizet_overflow(out, one, two) \
65             __builtin_umull_overflow(one, two, out)
66             # elif (SIZE_MAX == ULLONG_MAX)
67             # define git__add_sizet_overflow(out, one, two) \
68             __builtin_uaddll_overflow(one, two, out)
69             # define git__multiply_sizet_overflow(out, one, two) \
70             __builtin_umulll_overflow(one, two, out)
71             # else
72             # error compiler has add with overflow intrinsics but SIZE_MAX is unknown
73             # endif
74              
75             # define git__add_int_overflow(out, one, two) \
76             __builtin_sadd_overflow(one, two, out)
77             # define git__sub_int_overflow(out, one, two) \
78             __builtin_ssub_overflow(one, two, out)
79              
80             # define git__add_int64_overflow(out, one, two) \
81             __builtin_add_overflow(one, two, out)
82              
83             /* clang on 32-bit systems produces an undefined reference to `__mulodi4`. */
84             # if !defined(__clang__) || !defined(GIT_ARCH_32)
85             # define git__multiply_int64_overflow(out, one, two) \
86             __builtin_mul_overflow(one, two, out)
87             # endif
88              
89             /* Use Microsoft's safe integer handling functions where available */
90             #elif defined(_MSC_VER)
91              
92             # define ENABLE_INTSAFE_SIGNED_FUNCTIONS
93             # include
94              
95             # define git__add_sizet_overflow(out, one, two) \
96             (SizeTAdd(one, two, out) != S_OK)
97             # define git__multiply_sizet_overflow(out, one, two) \
98             (SizeTMult(one, two, out) != S_OK)
99              
100             #define git__add_int_overflow(out, one, two) \
101             (IntAdd(one, two, out) != S_OK)
102             #define git__sub_int_overflow(out, one, two) \
103             (IntSub(one, two, out) != S_OK)
104              
105             #define git__add_int64_overflow(out, one, two) \
106             (LongLongAdd(one, two, out) != S_OK)
107             #define git__multiply_int64_overflow(out, one, two) \
108             (LongLongMult(one, two, out) != S_OK)
109              
110             #else
111              
112             /**
113             * Sets `one + two` into `out`, unless the arithmetic would overflow.
114             * @return false if the result fits in a `size_t`, true on overflow.
115             */
116             GIT_INLINE(bool) git__add_sizet_overflow(size_t *out, size_t one, size_t two)
117             {
118             if (SIZE_MAX - one < two)
119             return true;
120             *out = one + two;
121             return false;
122             }
123              
124             /**
125             * Sets `one * two` into `out`, unless the arithmetic would overflow.
126             * @return false if the result fits in a `size_t`, true on overflow.
127             */
128             GIT_INLINE(bool) git__multiply_sizet_overflow(size_t *out, size_t one, size_t two)
129             {
130             if (one && SIZE_MAX / one < two)
131             return true;
132             *out = one * two;
133             return false;
134             }
135              
136             GIT_INLINE(bool) git__add_int_overflow(int *out, int one, int two)
137             {
138             if ((two > 0 && one > (INT_MAX - two)) ||
139             (two < 0 && one < (INT_MIN - two)))
140             return true;
141             *out = one + two;
142             return false;
143             }
144              
145             GIT_INLINE(bool) git__sub_int_overflow(int *out, int one, int two)
146             {
147             if ((two > 0 && one < (INT_MIN + two)) ||
148             (two < 0 && one > (INT_MAX + two)))
149             return true;
150             *out = one - two;
151             return false;
152             }
153              
154             GIT_INLINE(bool) git__add_int64_overflow(int64_t *out, int64_t one, int64_t two)
155             {
156             if ((two > 0 && one > (INT64_MAX - two)) ||
157             (two < 0 && one < (INT64_MIN - two)))
158             return true;
159             *out = one + two;
160             return false;
161             }
162              
163             #endif
164              
165             /* If we could not provide an intrinsic implementation for this, provide a (slow) fallback. */
166             #if !defined(git__multiply_int64_overflow)
167             GIT_INLINE(bool) git__multiply_int64_overflow(int64_t *out, int64_t one, int64_t two)
168             {
169             /*
170             * Detects whether `INT64_MAX < (one * two) || INT64_MIN > (one * two)`,
171             * without incurring in undefined behavior. That is done by performing the
172             * comparison with a division instead of a multiplication, which translates
173             * to `INT64_MAX / one < two || INT64_MIN / one > two`. Some caveats:
174             *
175             * - The comparison sign is inverted when both sides of the inequality are
176             * multiplied/divided by a negative number, so if `one < 0` the comparison
177             * needs to be flipped.
178             * - `INT64_MAX / -1` itself overflows (or traps), so that case should be
179             * avoided.
180             * - Since the overflow flag is defined as the discrepance between the result
181             * of performing the multiplication in a signed integer at twice the width
182             * of the operands, and the truncated+sign-extended version of that same
183             * result, there are four cases where the result is the opposite of what
184             * would be expected:
185             * * `INT64_MIN * -1` / `-1 * INT64_MIN`
186             * * `INT64_MIN * 1 / `1 * INT64_MIN`
187             */
188             if (one && two) {
189             if (one > 0 && two > 0) {
190             if (INT64_MAX / one < two)
191             return true;
192             } else if (one < 0 && two < 0) {
193             if ((one == -1 && two == INT64_MIN) ||
194             (two == -1 && one == INT64_MIN)) {
195             *out = INT64_MIN;
196             return false;
197             }
198             if (INT64_MAX / one > two)
199             return true;
200             } else if (one > 0 && two < 0) {
201             if ((one == 1 && two == INT64_MIN) ||
202             (INT64_MIN / one > two))
203             return true;
204             } else if (one == -1) {
205             if (INT64_MIN / two > one)
206             return true;
207             } else {
208             if ((one == INT64_MIN && two == 1) ||
209             (INT64_MIN / one < two))
210             return true;
211             }
212             }
213             *out = one * two;
214             return false;
215             }
216             #endif
217              
218             #endif