Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * int.h
4 : * Routines to perform integer math, while checking for overflows.
5 : *
6 : * The routines in this file are intended to be well defined C, without
7 : * relying on compiler flags like -fwrapv.
8 : *
9 : * To reduce the overhead of these routines try to use compiler intrinsics
10 : * where available. That's not that important for the 16, 32 bit cases, but
11 : * the 64 bit cases can be considerably faster with intrinsics. In case no
12 : * intrinsics are available 128 bit math is used where available.
13 : *
14 : * Copyright (c) 2017-2023, PostgreSQL Global Development Group
15 : *
16 : * src/include/common/int.h
17 : *
18 : *-------------------------------------------------------------------------
19 : */
20 : #ifndef COMMON_INT_H
21 : #define COMMON_INT_H
22 :
23 :
24 : /*---------
25 : * The following guidelines apply to all the routines:
26 : * - If a + b overflows, return true, otherwise store the result of a + b
27 : * into *result. The content of *result is implementation defined in case of
28 : * overflow.
29 : * - If a - b overflows, return true, otherwise store the result of a - b
30 : * into *result. The content of *result is implementation defined in case of
31 : * overflow.
32 : * - If a * b overflows, return true, otherwise store the result of a * b
33 : * into *result. The content of *result is implementation defined in case of
34 : * overflow.
35 : *---------
36 : */
37 :
38 : /*------------------------------------------------------------------------
39 : * Overflow routines for signed integers
40 : *------------------------------------------------------------------------
41 : */
42 :
43 : /*
44 : * INT16
45 : */
46 : static inline bool
1988 andres 47 CBC 27 : pg_add_s16_overflow(int16 a, int16 b, int16 *result)
48 : {
49 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
50 27 : return __builtin_add_overflow(a, b, result);
51 : #else
52 : int32 res = (int32) a + (int32) b;
53 :
54 : if (res > PG_INT16_MAX || res < PG_INT16_MIN)
55 : {
56 : *result = 0x5EED; /* to avoid spurious warnings */
57 : return true;
58 : }
59 : *result = (int16) res;
60 : return false;
61 : #endif
62 : }
63 :
64 : static inline bool
65 609 : pg_sub_s16_overflow(int16 a, int16 b, int16 *result)
66 : {
67 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
68 609 : return __builtin_sub_overflow(a, b, result);
69 : #else
70 : int32 res = (int32) a - (int32) b;
71 :
72 : if (res > PG_INT16_MAX || res < PG_INT16_MIN)
73 : {
74 : *result = 0x5EED; /* to avoid spurious warnings */
75 : return true;
76 : }
77 : *result = (int16) res;
78 : return false;
79 : #endif
80 : }
81 :
82 : static inline bool
83 27 : pg_mul_s16_overflow(int16 a, int16 b, int16 *result)
84 : {
85 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
86 27 : return __builtin_mul_overflow(a, b, result);
87 : #else
88 : int32 res = (int32) a * (int32) b;
89 :
90 : if (res > PG_INT16_MAX || res < PG_INT16_MIN)
91 : {
92 : *result = 0x5EED; /* to avoid spurious warnings */
93 : return true;
94 : }
95 : *result = (int16) res;
96 : return false;
97 : #endif
98 : }
99 :
100 : /*
101 : * INT32
102 : */
103 : static inline bool
104 10565990 : pg_add_s32_overflow(int32 a, int32 b, int32 *result)
105 : {
106 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
107 10565990 : return __builtin_add_overflow(a, b, result);
108 : #else
109 : int64 res = (int64) a + (int64) b;
110 :
111 : if (res > PG_INT32_MAX || res < PG_INT32_MIN)
112 : {
113 : *result = 0x5EED; /* to avoid spurious warnings */
114 : return true;
115 : }
116 : *result = (int32) res;
117 : return false;
118 : #endif
119 : }
120 :
121 : static inline bool
122 713393 : pg_sub_s32_overflow(int32 a, int32 b, int32 *result)
123 : {
124 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
125 713393 : return __builtin_sub_overflow(a, b, result);
126 : #else
127 : int64 res = (int64) a - (int64) b;
128 :
129 : if (res > PG_INT32_MAX || res < PG_INT32_MIN)
130 : {
131 : *result = 0x5EED; /* to avoid spurious warnings */
132 : return true;
133 : }
134 : *result = (int32) res;
135 : return false;
136 : #endif
137 : }
138 :
139 : static inline bool
140 1847938 : pg_mul_s32_overflow(int32 a, int32 b, int32 *result)
141 : {
142 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
143 1847938 : return __builtin_mul_overflow(a, b, result);
144 : #else
145 : int64 res = (int64) a * (int64) b;
146 :
147 : if (res > PG_INT32_MAX || res < PG_INT32_MIN)
148 : {
149 : *result = 0x5EED; /* to avoid spurious warnings */
150 : return true;
151 : }
152 : *result = (int32) res;
153 : return false;
154 : #endif
155 : }
156 :
157 : /*
158 : * INT64
159 : */
160 : static inline bool
161 9287990 : pg_add_s64_overflow(int64 a, int64 b, int64 *result)
162 : {
163 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
164 9287990 : return __builtin_add_overflow(a, b, result);
165 : #elif defined(HAVE_INT128)
166 : int128 res = (int128) a + (int128) b;
167 :
168 : if (res > PG_INT64_MAX || res < PG_INT64_MIN)
169 : {
170 : *result = 0x5EED; /* to avoid spurious warnings */
171 : return true;
172 : }
173 : *result = (int64) res;
174 : return false;
175 : #else
176 : if ((a > 0 && b > 0 && a > PG_INT64_MAX - b) ||
177 : (a < 0 && b < 0 && a < PG_INT64_MIN - b))
178 : {
179 : *result = 0x5EED; /* to avoid spurious warnings */
180 : return true;
181 : }
182 : *result = a + b;
183 : return false;
184 : #endif
185 : }
186 :
187 : static inline bool
188 154420 : pg_sub_s64_overflow(int64 a, int64 b, int64 *result)
189 : {
190 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
191 154420 : return __builtin_sub_overflow(a, b, result);
192 : #elif defined(HAVE_INT128)
193 : int128 res = (int128) a - (int128) b;
194 :
195 : if (res > PG_INT64_MAX || res < PG_INT64_MIN)
196 : {
197 : *result = 0x5EED; /* to avoid spurious warnings */
198 : return true;
199 : }
200 : *result = (int64) res;
201 : return false;
202 : #else
203 : if ((a < 0 && b > 0 && a < PG_INT64_MIN + b) ||
204 : (a > 0 && b < 0 && a > PG_INT64_MAX + b))
205 : {
206 : *result = 0x5EED; /* to avoid spurious warnings */
207 : return true;
208 : }
209 : *result = a - b;
210 : return false;
211 : #endif
212 : }
213 :
214 : static inline bool
215 38141 : pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
216 : {
217 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
218 38141 : return __builtin_mul_overflow(a, b, result);
219 : #elif defined(HAVE_INT128)
220 : int128 res = (int128) a * (int128) b;
221 :
222 : if (res > PG_INT64_MAX || res < PG_INT64_MIN)
223 : {
224 : *result = 0x5EED; /* to avoid spurious warnings */
225 : return true;
226 : }
227 : *result = (int64) res;
228 : return false;
229 : #else
230 : /*
231 : * Overflow can only happen if at least one value is outside the range
232 : * sqrt(min)..sqrt(max) so check that first as the division can be quite a
233 : * bit more expensive than the multiplication.
234 : *
235 : * Multiplying by 0 or 1 can't overflow of course and checking for 0
236 : * separately avoids any risk of dividing by 0. Be careful about dividing
237 : * INT_MIN by -1 also, note reversing the a and b to ensure we're always
238 : * dividing it by a positive value.
239 : *
240 : */
241 : if ((a > PG_INT32_MAX || a < PG_INT32_MIN ||
242 : b > PG_INT32_MAX || b < PG_INT32_MIN) &&
243 : a != 0 && a != 1 && b != 0 && b != 1 &&
244 : ((a > 0 && b > 0 && a > PG_INT64_MAX / b) ||
245 : (a > 0 && b < 0 && b < PG_INT64_MIN / a) ||
246 : (a < 0 && b > 0 && a < PG_INT64_MIN / b) ||
247 : (a < 0 && b < 0 && a < PG_INT64_MAX / b)))
248 : {
249 : *result = 0x5EED; /* to avoid spurious warnings */
250 : return true;
251 : }
252 : *result = a * b;
253 : return false;
254 : #endif
255 : }
256 :
257 : /*------------------------------------------------------------------------
258 : * Overflow routines for unsigned integers
259 : *------------------------------------------------------------------------
260 : */
261 :
262 : /*
263 : * UINT16
264 : */
265 : static inline bool
266 : pg_add_u16_overflow(uint16 a, uint16 b, uint16 *result)
267 : {
268 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
269 : return __builtin_add_overflow(a, b, result);
270 : #else
271 : uint16 res = a + b;
272 :
273 : if (res < a)
274 : {
275 : *result = 0x5EED; /* to avoid spurious warnings */
276 : return true;
277 : }
278 : *result = res;
279 : return false;
280 : #endif
281 : }
282 :
283 : static inline bool
284 : pg_sub_u16_overflow(uint16 a, uint16 b, uint16 *result)
285 : {
286 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
287 : return __builtin_sub_overflow(a, b, result);
288 : #else
289 : if (b > a)
290 : {
291 : *result = 0x5EED; /* to avoid spurious warnings */
292 : return true;
293 : }
294 : *result = a - b;
295 : return false;
296 : #endif
297 : }
298 :
299 : static inline bool
300 : pg_mul_u16_overflow(uint16 a, uint16 b, uint16 *result)
301 : {
302 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
303 : return __builtin_mul_overflow(a, b, result);
304 : #else
305 : uint32 res = (uint32) a * (uint32) b;
306 :
307 : if (res > PG_UINT16_MAX)
308 : {
309 : *result = 0x5EED; /* to avoid spurious warnings */
310 : return true;
311 : }
312 : *result = (uint16) res;
313 : return false;
314 : #endif
315 : }
316 :
317 : /*
318 : * INT32
319 : */
320 : static inline bool
321 : pg_add_u32_overflow(uint32 a, uint32 b, uint32 *result)
322 : {
323 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
324 : return __builtin_add_overflow(a, b, result);
325 : #else
326 : uint32 res = a + b;
327 :
328 : if (res < a)
329 : {
330 : *result = 0x5EED; /* to avoid spurious warnings */
331 : return true;
332 : }
333 : *result = res;
334 : return false;
335 : #endif
336 : }
337 :
338 : static inline bool
339 : pg_sub_u32_overflow(uint32 a, uint32 b, uint32 *result)
340 : {
341 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
342 : return __builtin_sub_overflow(a, b, result);
343 : #else
344 : if (b > a)
345 : {
346 : *result = 0x5EED; /* to avoid spurious warnings */
347 : return true;
348 : }
349 : *result = a - b;
350 : return false;
351 : #endif
352 : }
353 :
354 : static inline bool
355 : pg_mul_u32_overflow(uint32 a, uint32 b, uint32 *result)
356 : {
357 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
358 : return __builtin_mul_overflow(a, b, result);
359 : #else
360 : uint64 res = (uint64) a * (uint64) b;
361 :
362 : if (res > PG_UINT32_MAX)
363 : {
364 : *result = 0x5EED; /* to avoid spurious warnings */
365 : return true;
366 : }
367 : *result = (uint32) res;
368 : return false;
369 : #endif
370 : }
371 :
372 : /*
373 : * UINT64
374 : */
375 : static inline bool
1315 michael 376 74 : pg_add_u64_overflow(uint64 a, uint64 b, uint64 *result)
377 : {
378 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
379 74 : return __builtin_add_overflow(a, b, result);
380 : #else
381 : uint64 res = a + b;
382 :
383 : if (res < a)
384 : {
385 : *result = 0x5EED; /* to avoid spurious warnings */
386 : return true;
387 : }
388 : *result = res;
389 : return false;
390 : #endif
391 : }
392 :
393 : static inline bool
394 : pg_sub_u64_overflow(uint64 a, uint64 b, uint64 *result)
395 : {
396 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
397 : return __builtin_sub_overflow(a, b, result);
398 : #else
399 : if (b > a)
400 : {
401 : *result = 0x5EED; /* to avoid spurious warnings */
402 : return true;
403 : }
404 : *result = a - b;
405 : return false;
406 : #endif
407 : }
408 :
409 : static inline bool
410 74 : pg_mul_u64_overflow(uint64 a, uint64 b, uint64 *result)
411 : {
412 : #if defined(HAVE__BUILTIN_OP_OVERFLOW)
413 74 : return __builtin_mul_overflow(a, b, result);
414 : #elif defined(HAVE_INT128)
415 : uint128 res = (uint128) a * (uint128) b;
416 :
417 : if (res > PG_UINT64_MAX)
418 : {
419 : *result = 0x5EED; /* to avoid spurious warnings */
420 : return true;
421 : }
422 : *result = (uint64) res;
423 : return false;
424 : #else
425 : uint64 res = a * b;
426 :
427 : if (a != 0 && b != res / a)
428 : {
429 : *result = 0x5EED; /* to avoid spurious warnings */
430 : return true;
431 : }
432 : *result = res;
433 : return false;
434 : #endif
435 : }
436 :
437 : #endif /* COMMON_INT_H */
|