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-2021, 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
pg_add_s16_overflow(int16 a,int16 b,int16 * result)47 pg_add_s16_overflow(int16 a, int16 b, int16 *result)
48 {
49 #if defined(HAVE__BUILTIN_OP_OVERFLOW)
50 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
pg_sub_s16_overflow(int16 a,int16 b,int16 * result)65 pg_sub_s16_overflow(int16 a, int16 b, int16 *result)
66 {
67 #if defined(HAVE__BUILTIN_OP_OVERFLOW)
68 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
pg_mul_s16_overflow(int16 a,int16 b,int16 * result)83 pg_mul_s16_overflow(int16 a, int16 b, int16 *result)
84 {
85 #if defined(HAVE__BUILTIN_OP_OVERFLOW)
86 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
pg_add_s32_overflow(int32 a,int32 b,int32 * result)104 pg_add_s32_overflow(int32 a, int32 b, int32 *result)
105 {
106 #if defined(HAVE__BUILTIN_OP_OVERFLOW)
107 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
pg_sub_s32_overflow(int32 a,int32 b,int32 * result)122 pg_sub_s32_overflow(int32 a, int32 b, int32 *result)
123 {
124 #if defined(HAVE__BUILTIN_OP_OVERFLOW)
125 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
pg_mul_s32_overflow(int32 a,int32 b,int32 * result)140 pg_mul_s32_overflow(int32 a, int32 b, int32 *result)
141 {
142 #if defined(HAVE__BUILTIN_OP_OVERFLOW)
143 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
pg_add_s64_overflow(int64 a,int64 b,int64 * result)161 pg_add_s64_overflow(int64 a, int64 b, int64 *result)
162 {
163 #if defined(HAVE__BUILTIN_OP_OVERFLOW)
164 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
pg_sub_s64_overflow(int64 a,int64 b,int64 * result)188 pg_sub_s64_overflow(int64 a, int64 b, int64 *result)
189 {
190 #if defined(HAVE__BUILTIN_OP_OVERFLOW)
191 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
pg_mul_s64_overflow(int64 a,int64 b,int64 * result)215 pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
216 {
217 #if defined(HAVE__BUILTIN_OP_OVERFLOW)
218 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
pg_add_u16_overflow(uint16 a,uint16 b,uint16 * result)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
pg_sub_u16_overflow(uint16 a,uint16 b,uint16 * result)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
pg_mul_u16_overflow(uint16 a,uint16 b,uint16 * result)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
pg_add_u32_overflow(uint32 a,uint32 b,uint32 * result)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
pg_sub_u32_overflow(uint32 a,uint32 b,uint32 * result)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
pg_mul_u32_overflow(uint32 a,uint32 b,uint32 * result)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
pg_add_u64_overflow(uint64 a,uint64 b,uint64 * result)376 pg_add_u64_overflow(uint64 a, uint64 b, uint64 *result)
377 {
378 #if defined(HAVE__BUILTIN_OP_OVERFLOW)
379 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
pg_sub_u64_overflow(uint64 a,uint64 b,uint64 * result)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
pg_mul_u64_overflow(uint64 a,uint64 b,uint64 * result)410 pg_mul_u64_overflow(uint64 a, uint64 b, uint64 *result)
411 {
412 #if defined(HAVE__BUILTIN_OP_OVERFLOW)
413 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 */
438