xref: /freebsd/contrib/libarchive/libarchive/archive_integer.h (revision 185becb1e1bd2657c156f78aeb52edac05ba5fb5)
1 /*-
2  * Copyright (c) 2026 Tobias Stoeckmann
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #ifndef ARCHIVE_INTEGER_H_INCLUDED
28 #define ARCHIVE_INTEGER_H_INCLUDED
29 
30 #include "archive_platform.h"
31 
32 /* Note:  This is a purely internal header! */
33 /* Do not use this outside of libarchive internal code! */
34 
35 #ifndef __LIBARCHIVE_BUILD
36 #error This header is only to be used internally to libarchive.
37 #endif
38 
39 #ifdef HAVE_INTSAFE_H
40 #define ENABLE_INTSAFE_SIGNED_FUNCTIONS
41 #include <intsafe.h>
42 #endif
43 #ifdef HAVE_LIMITS_H
44 #include <limits.h>
45 #endif
46 #ifdef HAVE_STDCKDINT_H
47 #include <stdckdint.h>
48 #endif
49 #ifdef HAVE_STDINT_H
50 #include <stdint.h>
51 #endif
52 #ifdef HAVE_TIME_H
53 #include <time.h>
54 #endif
55 #ifdef HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif
58 
59 #ifndef __has_builtin
60 #define __has_builtin(x) 0
61 #endif
62 
63 #ifdef HAVE_STDCKDINT_H
64 #define USE_STDCKDINT 1
65 #elif (__GNUC__ >= 5 && !defined(__INTEL_COMPILER))
66 #define USE_BUILTIN 1
67 #elif __has_builtin(__builtin_add_overflow)
68 #define USE_BUILTIN 1
69 #elif defined HAVE_INTSAFE_H
70 #define USE_INTSAFE 1
71 #endif
72 
73 /*
74  * Disabling inline keyword for compilers known to choke on it:
75  * - Watcom C++ in C code.  (For any version?)
76  * - SGI MIPSpro
77  * - Microsoft Visual C++ 6.0 (supposedly newer versions too)
78  * - IBM VisualAge 6 (XL v6)
79  * - Sun WorkShop C (SunPro) before 5.9
80  */
81 #if defined(__WATCOMC__) || defined(__sgi) || defined(__hpux) || defined(__BORLANDC__)
82 #define	inline
83 #elif defined(__IBMC__) && __IBMC__ < 700
84 #define	inline
85 #elif defined(__SUNPRO_C) && __SUNPRO_C < 0x590
86 #define inline
87 #elif defined(_MSC_VER) || defined(__osf__)
88 #define inline __inline
89 #endif
90 
91 /* Returns 0 on success, a non-zero value otherwise. */
92 static inline int
archive_ckd_add_i64(int64_t * result,int64_t a,int64_t b)93 archive_ckd_add_i64(int64_t *result, int64_t a, int64_t b)
94 {
95 #if USE_STDCKDINT
96 	return ckd_add(result, a, b);
97 #elif USE_BUILTIN
98 	return __builtin_add_overflow(a, b, result);
99 #elif USE_INTSAFE
100 	LONGLONG res;
101 	int ret;
102 
103 	ret = LongLongAdd(a, b, &res);
104 	*result = (int64_t)res;
105 	return ret;
106 #else
107 	if ((b > 0 && a > INT64_MAX - b) ||
108 	    (b < 0 && a < INT64_MIN - b))
109 		return 1;
110 
111 	*result = a + b;
112 	return 0;
113 #endif
114 }
115 
116 /* Returns 0 on success, a non-zero value otherwise. */
117 static inline int
archive_ckd_add_size(size_t * result,size_t a,size_t b)118 archive_ckd_add_size(size_t *result, size_t a, size_t b)
119 {
120 #if USE_STDCKDINT
121 	return ckd_add(result, a, b);
122 #elif USE_BUILTIN
123 	return __builtin_add_overflow(a, b, result);
124 #elif USE_INTSAFE
125 	return SizeTAdd(a, b, result);
126 #else
127 	if (a > SIZE_MAX - b)
128 		return 1;
129 	*result = a + b;
130 	return 0;
131 #endif
132 }
133 
134 /* Returns 0 on success, a non-zero value otherwise. */
135 static inline int
archive_ckd_add_u64(uint64_t * result,uint64_t a,uint64_t b)136 archive_ckd_add_u64(uint64_t *result, uint64_t a, uint64_t b)
137 {
138 #if USE_STDCKDINT
139 	return ckd_add(result, a, b);
140 #elif USE_BUILTIN
141 	return __builtin_add_overflow(a, b, result);
142 #elif USE_INTSAFE
143 	ULONGLONG res;
144 	int ret;
145 
146 	ret = ULongLongAdd(a, b, &res);
147 	*result = (uint64_t)res;
148 	return ret;
149 #else
150 	if (a > UINT64_MAX - b)
151 		return 1;
152 	*result = a + b;
153 	return 0;
154 #endif
155 }
156 
157 /* Returns 0 on success, a non-zero value otherwise. */
158 static inline int
archive_ckd_mul_i64(int64_t * result,int64_t a,int64_t b)159 archive_ckd_mul_i64(int64_t *result, int64_t a, int64_t b)
160 {
161 #if USE_STDCKDINT
162 	return ckd_mul(result, a, b);
163 #elif USE_BUILTIN
164 	return __builtin_mul_overflow(a, b, result);
165 #elif USE_INTSAFE
166 	LONGLONG res;
167 	int ret;
168 
169 	ret = LongLongMult(a, b, &res);
170 	*result = (int64_t)res;
171 	return ret;
172 #else
173 	if ((a > 0 && b > 0 && a > INT64_MAX / b) ||
174 	    (a < 0 && b > 0 && a < INT64_MIN / b) ||
175 	    (a > 0 && b < 0 && b < INT64_MIN / a) ||
176 	    (a < 0 && b < 0 && a < INT64_MAX / b))
177 		return 1;
178 
179 	*result = a * b;
180 	return 0;
181 #endif
182 }
183 
184 /* Returns 0 on success, a non-zero value otherwise. */
185 static inline int
archive_ckd_mul_size(size_t * result,size_t a,size_t b)186 archive_ckd_mul_size(size_t *result, size_t a, size_t b)
187 {
188 #if USE_STDCKDINT
189 	return ckd_mul(result, a, b);
190 #elif USE_BUILTIN
191 	return __builtin_mul_overflow(a, b, result);
192 #elif USE_INTSAFE
193 	return SizeTMult(a, b, result);
194 #else
195 	if (b != 0 && a > SIZE_MAX / b)
196 		return 1;
197 	*result = a * b;
198 	return 0;
199 #endif
200 }
201 
202 /* Returns 0 on success, a non-zero value otherwise. */
203 static inline int
archive_ckd_mul_u64(uint64_t * result,uint64_t a,uint64_t b)204 archive_ckd_mul_u64(uint64_t *result, uint64_t a, uint64_t b)
205 {
206 #if USE_STDCKDINT
207 	return ckd_mul(result, a, b);
208 #elif USE_BUILTIN
209 	return __builtin_mul_overflow(a, b, result);
210 #elif USE_INTSAFE
211 	ULONGLONG res;
212 	int ret;
213 
214 	ret = ULongLongMult(a, b, &res);
215 	*result = (uint64_t)res;
216 	return ret;
217 #else
218 	if (b != 0 && a > UINT64_MAX / b)
219 		return 1;
220 	*result = a * b;
221 	return 0;
222 #endif
223 }
224 
225 /* Returns 0 on success, a non-zero value otherwise. */
226 static inline int
archive_ckd_sub_i64(int64_t * result,int64_t a,int64_t b)227 archive_ckd_sub_i64(int64_t *result, int64_t a, int64_t b)
228 {
229 #if USE_STDCKDINT
230 	return ckd_sub(result, a, b);
231 #elif USE_BUILTIN
232 	return __builtin_sub_overflow(a, b, result);
233 #elif USE_INTSAFE
234 	LONGLONG res;
235 	int ret;
236 
237 	ret = LongLongSub(a, b, &res);
238 	*result = (int64_t)res;
239 	return ret;
240 #else
241 	if ((b > 0 && a < INT64_MIN + b) ||
242 	    (b < 0 && a > INT64_MAX + b))
243 		return 1;
244 
245 	*result = a - b;
246 	return 0;
247 #endif
248 }
249 
250 #if !defined(TIME_MAX)
251 #define TIME_MAX (((time_t)0 < (time_t)-1) ? (time_t)~0 :		\
252 	    sizeof(time_t) == sizeof(long long) ? (time_t)LLONG_MAX :	\
253 	    sizeof(time_t) == sizeof(long) ? (time_t)LONG_MAX :		\
254 	    sizeof(time_t) == sizeof(int) ? (time_t)INT_MAX :		\
255 	    sizeof(time_t) == sizeof(short) ? (time_t)SHRT_MAX :	\
256 	    1 /* I give up */)
257 #endif
258 #if !defined(TIME_MIN)
259 #define TIME_MIN (((time_t)0 < (time_t)-1) ? (time_t)0 :		\
260 	    sizeof(time_t) == sizeof(long long) ? (time_t)LLONG_MIN :	\
261 	    sizeof(time_t) == sizeof(long) ? (time_t)LONG_MIN :		\
262 	    sizeof(time_t) == sizeof(int) ? (time_t)INT_MIN :		\
263 	    sizeof(time_t) == sizeof(short) ? (time_t)SHRT_MIN :	\
264 	    -1 /* I give up */)
265 #endif
266 
267 #endif
268