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