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