1 /*!
2 * \file intsafe.h
3 *
4 * \brief Windows helper functions for integer overflow prevention
5 *
6 * \package This file is part of the ReactOS PSDK package.
7 *
8 * \author
9 * Timo Kreuzer (timo.kreuzer@reactos.org)
10 *
11 * \copyright THIS SOFTWARE IS NOT COPYRIGHTED
12 *
13 * This source code is offered for use in the public domain. You may
14 * use, modify or distribute it freely.
15 *
16 * This code is distributed in the hope that it will be useful but
17 * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
18 * DISCLAIMED. This includes but is not limited to warranties of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * \todo
22 * - missing conversion functions
23 * - multiplication functions
24 * - signed add, sub and multiply functions
25 */
26 #pragma once
27
28 #ifndef _INTSAFE_H_INCLUDED_
29 #define _INTSAFE_H_INCLUDED_
30
31 #include <specstrings.h>
32
33 /* Handle ntintsafe here too */
34 #ifdef _NTINTSAFE_H_INCLUDED_
35 #ifndef _NTDEF_ /* Guard agains redefinition from ntstatus.h */
36 typedef _Return_type_success_(return >= 0) long NTSTATUS;
37 #endif
38 #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
39 #define STATUS_SUCCESS ((NTSTATUS)0x00000000)
40 #define STATUS_INTEGER_OVERFLOW ((NTSTATUS)0xC0000095)
41 #define INTSAFE_RESULT NTSTATUS
42 #define INTSAFE_SUCCESS STATUS_SUCCESS
43 #define INTSAFE_E_ARITHMETIC_OVERFLOW STATUS_INTEGER_OVERFLOW
44 #define INTSAFE_NAME(name) Rtl##name
45 #else // _NTINTSAFE_H_INCLUDED_
46 #ifndef _HRESULT_DEFINED
47 typedef _Return_type_success_(return >= 0) long HRESULT;
48 #endif
49 #ifndef SUCCEEDED
50 #define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
51 #define FAILED(hr) (((HRESULT)(hr)) < 0)
52 #define S_OK ((HRESULT)0L)
53 #endif
54 #define INTSAFE_RESULT HRESULT
55 #define INTSAFE_SUCCESS S_OK
56 #define INTSAFE_E_ARITHMETIC_OVERFLOW ((HRESULT)0x80070216L)
57 #define INTSAFE_NAME(name) name
58 #endif // _NTINTSAFE_H_INCLUDED_
59
60 #if !defined(_W64)
61 #if defined(_MSC_VER) && !defined(__midl) && (defined(_M_IX86) || defined(_M_ARM))
62 #define _W64 __w64
63 #else
64 #define _W64
65 #endif
66 #endif
67
68 /* Static assert */
69 #ifndef C_ASSERT
70 #ifdef _MSC_VER
71 # define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
72 #else
73 # define C_ASSERT(e) extern void __C_ASSERT__(int [(e)?1:-1])
74 #endif
75 #endif /* C_ASSERT */
76
77 /* Typedefs */
78 #ifndef _WINNT_
79 #ifndef _NTDEF_
80 typedef char CHAR;
81 typedef unsigned char UCHAR, UINT8;
82 typedef signed char INT8;
83 typedef short SHORT;
84 typedef signed short INT16;
85 typedef unsigned short USHORT, UINT16;
86 typedef int INT;
87 typedef unsigned int UINT32;
88 typedef signed int INT32;
89 typedef long LONG;
90 typedef unsigned long ULONG;
91 typedef long long LONGLONG, LONG64;
92 typedef signed long long INT64;
93 typedef unsigned long long ULONGLONG, DWORDLONG, ULONG64, DWORD64, UINT64;
94 #ifdef _WIN64
95 typedef long long INT_PTR, LONG_PTR, SSIZE_T, ptrdiff_t;
96 typedef unsigned long long UINT_PTR, ULONG_PTR, DWORD_PTR, SIZE_T, size_t;
97 #else // _WIN64
98 typedef _W64 int INT_PTR, ptrdiff_t;
99 typedef _W64 unsigned int UINT_PTR, size_t;
100 typedef _W64 long LONG_PTR, SSIZE_T;
101 typedef _W64 unsigned long ULONG_PTR, DWORD_PTR, SIZE_T;
102 #endif // _WIN64
103 #endif
104 typedef unsigned char BYTE;
105 typedef unsigned short WORD;
106 typedef unsigned int UINT;
107 typedef unsigned long DWORD;
108 #endif // _WINNT_
109
110 /* Just to be sure! */
111 C_ASSERT(sizeof(USHORT) == 2);
112 C_ASSERT(sizeof(INT) == 4);
113 C_ASSERT(sizeof(UINT) == 4);
114 C_ASSERT(sizeof(LONG) == 4);
115 C_ASSERT(sizeof(ULONG) == 4);
116 C_ASSERT(sizeof(DWORD) == 4);
117 C_ASSERT(sizeof(UINT_PTR) == sizeof(ULONG_PTR));
118
119 /* Integer range margins (use (x-1) to prevent warnings) */
120 #define INT8_MIN ((signed char)(-127 - 1))
121 #define SHORT_MIN (-32768)
122 #define INT16_MIN ((short)(-32767 - 1))
123 #define INT_MIN (-2147483647 - 1)
124 #define INT32_MIN (-2147483647 - 1)
125 #define LONG_MIN (-2147483647L - 1)
126 #define LONGLONG_MIN (-9223372036854775807LL - 1)
127 #define LONG64_MIN (-9223372036854775807LL - 1)
128 #define INT64_MIN (-9223372036854775807LL - 1)
129 #define INT128_MIN (-170141183460469231731687303715884105727i128 - 1)
130 #ifdef _WIN64
131 #define INT_PTR_MIN (-9223372036854775807LL - 1)
132 #define LONG_PTR_MIN (-9223372036854775807LL - 1)
133 #define PTRDIFF_T_MIN (-9223372036854775807LL - 1)
134 #define SSIZE_T_MIN (-9223372036854775807LL - 1)
135 #else /* _WIN64 */
136 #define INT_PTR_MIN (-2147483647 - 1)
137 #define LONG_PTR_MIN (-2147483647L - 1)
138 #define PTRDIFF_T_MIN (-2147483647 - 1)
139 #define SSIZE_T_MIN (-2147483647L - 1)
140 #endif /* _WIN64 */
141
142 #define INT8_MAX ((signed char)127)
143 #define UINT8_MAX ((unsigned char)0xffU)
144 #define BYTE_MAX ((unsigned char)0xff)
145 #define SHORT_MAX ((short)32767)
146 #define INT16_MAX ((short)32767)
147 #define USHORT_MAX ((unsigned short)0xffff)
148 #define UINT16_MAX ((unsigned short)0xffff)
149 #define WORD_MAX ((unsigned short)0xffff)
150 #define INT_MAX 2147483647
151 #define INT32_MAX 2147483647
152 #define UINT_MAX 0xffffffff
153 #define UINT32_MAX 0xffffffffU
154 #define LONG_MAX 2147483647L
155 #define ULONG_MAX 0xffffffffUL
156 #define DWORD_MAX 0xffffffffUL
157 #define LONGLONG_MAX 9223372036854775807LL
158 #define LONG64_MAX 9223372036854775807LL
159 #define INT64_MAX 9223372036854775807LL
160 #define ULONGLONG_MAX 0xffffffffffffffffULL
161 #define DWORDLONG_MAX 0xffffffffffffffffULL
162 #define ULONG64_MAX 0xffffffffffffffffULL
163 #define DWORD64_MAX 0xffffffffffffffffULL
164 #define UINT64_MAX 0xffffffffffffffffULL
165 #define INT128_MAX 170141183460469231731687303715884105727i128
166 #define UINT128_MAX 0xffffffffffffffffffffffffffffffffui128
167 #undef SIZE_T_MAX
168 #ifdef _WIN64
169 #define INT_PTR_MAX 9223372036854775807LL
170 #define UINT_PTR_MAX 0xffffffffffffffffULL
171 #define LONG_PTR_MAX 9223372036854775807LL
172 #define ULONG_PTR_MAX 0xffffffffffffffffULL
173 #define DWORD_PTR_MAX 0xffffffffffffffffULL
174 #define PTRDIFF_T_MAX 9223372036854775807LL
175 #define SIZE_T_MAX 0xffffffffffffffffULL
176 #define SSIZE_T_MAX 9223372036854775807LL
177 #define _SIZE_T_MAX 0xffffffffffffffffULL
178 #else /* _WIN64 */
179 #define INT_PTR_MAX 2147483647
180 #define UINT_PTR_MAX 0xffffffff
181 #define LONG_PTR_MAX 2147483647L
182 #define ULONG_PTR_MAX 0xffffffffUL
183 #define DWORD_PTR_MAX 0xffffffffUL
184 #define PTRDIFF_T_MAX 2147483647
185 #define SIZE_T_MAX 0xffffffff
186 #define SSIZE_T_MAX 2147483647L
187 #define _SIZE_T_MAX 0xffffffffUL
188 #endif /* _WIN64 */
189
190 /* Error values */
191 #define INT8_ERROR ((signed char)(-1))
192 #define UINT8_ERROR ((unsigned char)0xff)
193 #define BYTE_ERROR ((unsigned char)0xff)
194 #define SHORT_ERROR ((short)(-1))
195 #define INT16_ERROR ((short)(-1))
196 #define USHORT_ERROR ((unsigned short)0xffff)
197 #define UINT16_ERROR ((unsigned short)0xffff)
198 #define WORD_ERROR ((unsigned short)0xffff)
199 #define INT_ERROR (-1)
200 #define INT32_ERROR (-1)
201 #define UINT_ERROR 0xffffffffU
202 #define UINT32_ERROR 0xffffffffU
203 #define LONG_ERROR (-1L)
204 #define ULONG_ERROR 0xffffffffUL
205 #define DWORD_ERROR 0xffffffffUL
206 #define LONGLONG_ERROR (-1LL)
207 #define LONG64_ERROR (-1LL)
208 #define INT64_ERROR (-1LL)
209 #define ULONGLONG_ERROR 0xffffffffffffffffULL
210 #define DWORDLONG_ERROR 0xffffffffffffffffULL
211 #define ULONG64_ERROR 0xffffffffffffffffULL
212 #define UINT64_ERROR 0xffffffffffffffffULL
213 #ifdef _WIN64
214 #define INT_PTR_ERROR (-1LL)
215 #define UINT_PTR_ERROR 0xffffffffffffffffULL
216 #define LONG_PTR_ERROR (-1LL)
217 #define ULONG_PTR_ERROR 0xffffffffffffffffULL
218 #define DWORD_PTR_ERROR 0xffffffffffffffffULL
219 #define PTRDIFF_T_ERROR (-1LL)
220 #define SIZE_T_ERROR 0xffffffffffffffffULL
221 #define SSIZE_T_ERROR (-1LL)
222 #define _SIZE_T_ERROR 0xffffffffffffffffULL
223 #else /* _WIN64 */
224 #define INT_PTR_ERROR (-1)
225 #define UINT_PTR_ERROR 0xffffffffU
226 #define LONG_PTR_ERROR (-1L)
227 #define ULONG_PTR_ERROR 0xffffffffUL
228 #define DWORD_PTR_ERROR 0xffffffffUL
229 #define PTRDIFF_T_ERROR (-1)
230 #define SIZE_T_ERROR 0xffffffffU
231 #define SSIZE_T_ERROR (-1L)
232 #define _SIZE_T_ERROR 0xffffffffUL
233 #endif /* _WIN64 */
234
235 /* special definitons (the CHAR ones should not be defined here!) */
236 #define _INTSAFE_CHAR CHAR
237 #define _INTSAFE_CHAR_ERROR ((signed char)(-1))
238 #ifdef _CHAR_UNSIGNED
239 #define _INTSAFE_CHAR_MIN ((unsigned char)0)
240 #define _INTSAFE_CHAR_MAX ((unsigned char)0xff)
241 #else
242 #define _INTSAFE_CHAR_MIN ((signed char)(-128))
243 #define _INTSAFE_CHAR_MAX ((signed char)127)
244 #endif /* _CHAR_UNSIGNED */
245
246 #define size_t_ERROR SIZE_T_ERROR
247 #define UCHAR_ERROR '\0'
248 #define CHAR_ERROR '\0'
249
250 /* 32 bit x 32 bit to 64 bit unsigned multiplication */
251 #ifndef UInt32x32To64
252 #define UInt32x32To64(a,b) ((unsigned __int64)(unsigned int)(a)*(unsigned __int64)(unsigned int)(b))
253 #endif
254
255 /* Convert unsigned to signed or unsigned */
256 #define DEFINE_SAFE_CONVERT_UTOX(_Name, _TypeFrom, _TypeTo) \
257 _Must_inspect_result_ \
258 __forceinline \
259 INTSAFE_RESULT \
260 INTSAFE_NAME(_Name)( \
261 _In_ _TypeFrom Input, \
262 _Out_ _Deref_out_range_(==, Input) _TypeTo *pOutput) \
263 { \
264 if ((sizeof(_TypeFrom) < sizeof(_TypeTo)) || (Input <= _TypeTo ## _MAX)) \
265 { \
266 *pOutput = (_TypeTo)Input; \
267 return INTSAFE_SUCCESS; \
268 } \
269 else \
270 { \
271 *pOutput = _TypeTo ## _ERROR; \
272 return INTSAFE_E_ARITHMETIC_OVERFLOW; \
273 } \
274 }
275
DEFINE_SAFE_CONVERT_UTOX(ByteToChar,BYTE,_INTSAFE_CHAR)276 DEFINE_SAFE_CONVERT_UTOX(ByteToChar, BYTE, _INTSAFE_CHAR)
277 DEFINE_SAFE_CONVERT_UTOX(ByteToInt8, BYTE, INT8)
278 DEFINE_SAFE_CONVERT_UTOX(UInt8ToChar, UINT8, _INTSAFE_CHAR)
279 DEFINE_SAFE_CONVERT_UTOX(UInt8ToInt8, UINT8, INT8)
280 DEFINE_SAFE_CONVERT_UTOX(UShortToChar, USHORT, _INTSAFE_CHAR)
281 DEFINE_SAFE_CONVERT_UTOX(UShortToUChar, USHORT, UINT8)
282 DEFINE_SAFE_CONVERT_UTOX(UShortToInt8, USHORT, INT8)
283 DEFINE_SAFE_CONVERT_UTOX(UShortToUInt8, USHORT, UINT8)
284 DEFINE_SAFE_CONVERT_UTOX(UShortToShort, USHORT, SHORT)
285 DEFINE_SAFE_CONVERT_UTOX(UIntToUChar, UINT, UINT8)
286 DEFINE_SAFE_CONVERT_UTOX(UIntToInt8, UINT, INT8)
287 DEFINE_SAFE_CONVERT_UTOX(UIntToUInt8, UINT, UINT8)
288 DEFINE_SAFE_CONVERT_UTOX(UIntToShort, UINT, SHORT)
289 DEFINE_SAFE_CONVERT_UTOX(UIntToUShort, UINT, USHORT)
290 DEFINE_SAFE_CONVERT_UTOX(UIntToInt, UINT, INT)
291 DEFINE_SAFE_CONVERT_UTOX(UIntToLong, UINT, LONG)
292 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToUChar, UINT_PTR, UINT8)
293 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToInt8, UINT_PTR, INT8)
294 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToUInt8, UINT_PTR, UINT8)
295 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToShort, UINT_PTR, SHORT)
296 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToUShort, UINT_PTR, USHORT)
297 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToInt16, UINT_PTR, INT16)
298 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToUInt16, UINT_PTR, UINT16)
299 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToInt, UINT_PTR, INT)
300 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToLong, UINT_PTR, LONG)
301 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToIntPtr, UINT_PTR, INT_PTR)
302 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToLongPtr, UINT_PTR, LONG_PTR)
303 DEFINE_SAFE_CONVERT_UTOX(ULongToUChar, ULONG, UINT8)
304 DEFINE_SAFE_CONVERT_UTOX(ULongToUInt8, ULONG, UINT8)
305 DEFINE_SAFE_CONVERT_UTOX(ULongToShort, ULONG, SHORT)
306 DEFINE_SAFE_CONVERT_UTOX(ULongToUShort, ULONG, USHORT)
307 DEFINE_SAFE_CONVERT_UTOX(ULongToInt, ULONG, INT)
308 DEFINE_SAFE_CONVERT_UTOX(ULongToUInt, ULONG, UINT)
309 DEFINE_SAFE_CONVERT_UTOX(ULongToIntPtr, ULONG, INT_PTR)
310 DEFINE_SAFE_CONVERT_UTOX(ULongToUIntPtr, ULONG, UINT_PTR)
311 DEFINE_SAFE_CONVERT_UTOX(ULongToLongPtr, ULONG, LONG_PTR)
312 DEFINE_SAFE_CONVERT_UTOX(ULongPtrToULong, ULONG_PTR, ULONG)
313 DEFINE_SAFE_CONVERT_UTOX(ULongLongToUInt, ULONGLONG, UINT)
314 DEFINE_SAFE_CONVERT_UTOX(ULongLongToULong, ULONGLONG, ULONG)
315 DEFINE_SAFE_CONVERT_UTOX(ULongLongToULongPtr, ULONGLONG, ULONG_PTR)
316
317
318 /* Convert signed to unsigned */
319 #define DEFINE_SAFE_CONVERT_STOU(_Name, _TypeFrom, _TypeTo) \
320 _Must_inspect_result_ \
321 __forceinline \
322 INTSAFE_RESULT \
323 INTSAFE_NAME(_Name)( \
324 _In_ _TypeFrom Input, \
325 _Out_ _Deref_out_range_(==, Input) _TypeTo *pOutput) \
326 { \
327 if ((Input >= 0) && \
328 ((sizeof(_TypeFrom) <= sizeof(_TypeTo)) || (Input <= (_TypeFrom)_TypeTo ## _MAX))) \
329 { \
330 *pOutput = (_TypeTo)Input; \
331 return INTSAFE_SUCCESS; \
332 } \
333 else \
334 { \
335 *pOutput = _TypeTo ## _ERROR; \
336 return INTSAFE_E_ARITHMETIC_OVERFLOW; \
337 } \
338 }
339
340 DEFINE_SAFE_CONVERT_STOU(Int8ToUChar, INT8, UINT8)
341 DEFINE_SAFE_CONVERT_STOU(Int8ToUInt8, INT8, UINT8)
342 DEFINE_SAFE_CONVERT_STOU(Int8ToUShort, INT8, USHORT)
343 DEFINE_SAFE_CONVERT_STOU(Int8ToUInt, INT8, UINT)
344 DEFINE_SAFE_CONVERT_STOU(Int8ToULong, INT8, ULONG)
345 DEFINE_SAFE_CONVERT_STOU(Int8ToUIntPtr, INT8, UINT_PTR)
346 DEFINE_SAFE_CONVERT_STOU(Int8ToULongPtr, INT8, ULONG_PTR)
347 DEFINE_SAFE_CONVERT_STOU(Int8ToULongLong, INT8, ULONGLONG)
348 DEFINE_SAFE_CONVERT_STOU(ShortToUChar, SHORT, UINT8)
349 DEFINE_SAFE_CONVERT_STOU(ShortToUInt8, SHORT, UINT8)
350 DEFINE_SAFE_CONVERT_STOU(ShortToUShort, SHORT, USHORT)
351 DEFINE_SAFE_CONVERT_STOU(ShortToUInt, SHORT, UINT)
352 DEFINE_SAFE_CONVERT_STOU(ShortToULong, SHORT, ULONG)
353 DEFINE_SAFE_CONVERT_STOU(ShortToUIntPtr, SHORT, UINT_PTR)
354 DEFINE_SAFE_CONVERT_STOU(ShortToULongPtr, SHORT, ULONG_PTR)
355 DEFINE_SAFE_CONVERT_STOU(ShortToDWordPtr, SHORT, DWORD_PTR)
356 DEFINE_SAFE_CONVERT_STOU(ShortToULongLong, SHORT, ULONGLONG)
357 DEFINE_SAFE_CONVERT_STOU(IntToUChar, INT, UINT8)
358 DEFINE_SAFE_CONVERT_STOU(IntToUInt8, INT, UINT8)
359 DEFINE_SAFE_CONVERT_STOU(IntToUShort, INT, USHORT)
360 DEFINE_SAFE_CONVERT_STOU(IntToUInt, INT, UINT)
361 DEFINE_SAFE_CONVERT_STOU(IntToULong, INT, ULONG)
362 DEFINE_SAFE_CONVERT_STOU(IntToULongLong, INT, ULONGLONG)
363 DEFINE_SAFE_CONVERT_STOU(LongToUChar, LONG, UINT8)
364 DEFINE_SAFE_CONVERT_STOU(LongToUInt8, LONG, UINT8)
365 DEFINE_SAFE_CONVERT_STOU(LongToUShort, LONG, USHORT)
366 DEFINE_SAFE_CONVERT_STOU(LongToUInt, LONG, UINT)
367 DEFINE_SAFE_CONVERT_STOU(LongToULong, LONG, ULONG)
368 DEFINE_SAFE_CONVERT_STOU(LongToUIntPtr, LONG, UINT_PTR)
369 DEFINE_SAFE_CONVERT_STOU(LongToULongPtr, LONG, ULONG_PTR)
370 DEFINE_SAFE_CONVERT_STOU(LongToULongLong, LONG, ULONGLONG)
371 DEFINE_SAFE_CONVERT_STOU(IntPtrToUChar, INT_PTR, UINT8)
372 DEFINE_SAFE_CONVERT_STOU(IntPtrToUInt8, INT_PTR, UINT8)
373 DEFINE_SAFE_CONVERT_STOU(IntPtrToUShort, INT_PTR, USHORT)
374 DEFINE_SAFE_CONVERT_STOU(IntPtrToUInt, INT_PTR, UINT)
375 DEFINE_SAFE_CONVERT_STOU(IntPtrToULong, INT_PTR, ULONG)
376 DEFINE_SAFE_CONVERT_STOU(IntPtrToUIntPtr, INT_PTR, UINT_PTR)
377 DEFINE_SAFE_CONVERT_STOU(IntPtrToULongPtr, INT_PTR, ULONG_PTR)
378 DEFINE_SAFE_CONVERT_STOU(IntPtrToULongLong, INT_PTR, ULONGLONG)
379 DEFINE_SAFE_CONVERT_STOU(LongPtrToUChar, LONG_PTR, UINT8)
380 DEFINE_SAFE_CONVERT_STOU(LongPtrToUInt8, LONG_PTR, UINT8)
381 DEFINE_SAFE_CONVERT_STOU(LongPtrToUShort, LONG_PTR, USHORT)
382 DEFINE_SAFE_CONVERT_STOU(LongPtrToUInt, LONG_PTR, UINT)
383 DEFINE_SAFE_CONVERT_STOU(LongPtrToULong, LONG_PTR, ULONG)
384 DEFINE_SAFE_CONVERT_STOU(LongPtrToUIntPtr, LONG_PTR, UINT_PTR)
385 DEFINE_SAFE_CONVERT_STOU(LongPtrToULongPtr, LONG_PTR, ULONG_PTR)
386 DEFINE_SAFE_CONVERT_STOU(LongPtrToULongLong, LONG_PTR, ULONGLONG)
387 DEFINE_SAFE_CONVERT_STOU(LongLongToULong, LONGLONG, ULONG)
388 DEFINE_SAFE_CONVERT_STOU(LongLongToULongPtr, LONGLONG, ULONG_PTR)
389 #ifdef _CHAR_UNSIGNED
390 DEFINE_SAFE_CONVERT_STOU(ShortToChar, SHORT, UINT8)
391 DEFINE_SAFE_CONVERT_STOU(LongPtrToChar, LONG_PTR, UINT8)
392 #endif
393
394
395 /* Convert signed to signed */
396 #define DEFINE_SAFE_CONVERT_STOS(_Name, _TypeFrom, _TypeTo) \
397 _Must_inspect_result_ \
398 __forceinline \
399 INTSAFE_RESULT \
400 INTSAFE_NAME(_Name)( \
401 _In_ _TypeFrom Input, \
402 _Out_ _Deref_out_range_(==, Input) _TypeTo *pOutput) \
403 { \
404 if ((Input >= _TypeTo ## _MIN) && (Input <= _TypeTo ## _MAX)) \
405 { \
406 *pOutput = (_TypeTo)Input; \
407 return INTSAFE_SUCCESS; \
408 } \
409 else \
410 { \
411 *pOutput = _TypeTo ## _ERROR; \
412 return INTSAFE_E_ARITHMETIC_OVERFLOW; \
413 } \
414 }
415
416 DEFINE_SAFE_CONVERT_STOS(ShortToInt8, SHORT, INT8)
417 DEFINE_SAFE_CONVERT_STOS(IntToInt8, INT, INT8)
418 DEFINE_SAFE_CONVERT_STOS(IntToShort, INT, SHORT)
419 DEFINE_SAFE_CONVERT_STOS(LongToInt8, LONG, INT8)
420 DEFINE_SAFE_CONVERT_STOS(LongToShort, LONG, SHORT)
421 DEFINE_SAFE_CONVERT_STOS(LongToInt, LONG, INT)
422 DEFINE_SAFE_CONVERT_STOS(IntPtrToInt8, INT_PTR, INT8)
423 DEFINE_SAFE_CONVERT_STOS(IntPtrToShort, INT_PTR, SHORT)
424 DEFINE_SAFE_CONVERT_STOS(IntPtrToInt, INT_PTR, INT)
425 DEFINE_SAFE_CONVERT_STOS(IntPtrToLong, INT_PTR, LONG)
426 DEFINE_SAFE_CONVERT_STOS(IntPtrToLongPtr, INT_PTR, LONG_PTR)
427 DEFINE_SAFE_CONVERT_STOS(LongPtrToInt8, LONG_PTR, INT8)
428 DEFINE_SAFE_CONVERT_STOS(LongPtrToShort, LONG_PTR, SHORT)
429 DEFINE_SAFE_CONVERT_STOS(LongPtrToInt, LONG_PTR, INT)
430 DEFINE_SAFE_CONVERT_STOS(LongPtrToLong, LONG_PTR, LONG)
431 DEFINE_SAFE_CONVERT_STOS(LongPtrToIntPtr, LONG_PTR, INT_PTR)
432 DEFINE_SAFE_CONVERT_STOS(LongLongToInt, LONGLONG, INT)
433 DEFINE_SAFE_CONVERT_STOS(LongLongToLong, LONGLONG, LONG)
434 DEFINE_SAFE_CONVERT_STOS(LongLongToIntPtr, LONGLONG, INT_PTR)
435 DEFINE_SAFE_CONVERT_STOS(LongLongToLongPtr, LONGLONG, LONG_PTR)
436 DEFINE_SAFE_CONVERT_STOS(ShortToChar, SHORT, _INTSAFE_CHAR)
437 DEFINE_SAFE_CONVERT_STOS(LongPtrToChar, LONG_PTR, _INTSAFE_CHAR)
438
439
440 #ifdef _NTINTSAFE_H_INCLUDED_
441
442 #define RtlInt8ToByte RtlInt8ToUInt8
443 #define RtlInt8ToUInt16 RtlInt8ToUShort
444 #define RtlInt8ToWord RtlInt8ToUShort
445 #define RtlInt8ToUInt32 RtlInt8ToUInt
446 #define RtlInt8ToDWord RtlInt8ToULong
447 #define RtlInt8ToDWordPtr RtlInt8ToULongPtr
448 #define RtlInt8ToDWordLong RtlInt8ToULongLong
449 #define RtlInt8ToULong64 RtlInt8ToULongLong
450 #define RtlInt8ToDWord64 RtlInt8ToULongLong
451 #define RtlInt8ToUInt64 RtlInt8ToULongLong
452 #define RtlInt8ToSizeT RtlInt8ToUIntPtr
453 #define RtlInt8ToSIZET RtlInt8ToULongPtr
454 #define RtlIntToSizeT RtlIntToUIntPtr
455 #define RtlIntToSIZET RtlIntToULongPtr
456 #define RtlULongToSSIZET RtlULongToLongPtr
457 #define RtlULongToByte RtlULongToUInt8
458 #define RtlULongLongToInt64 RtlULongLongToLongLong
459 #define RtlULongLongToLong64 RtlULongLongToLongLong
460 #define RtlULongLongToPtrdiffT RtlULongLongToIntPtr
461 #define RtlULongLongToSizeT RtlULongLongToUIntPtr
462 #define RtlULongLongToSSIZET RtlULongLongToLongPtr
463 #define RtlULongLongToSIZET RtlULongLongToULongPtr
464 #define RtlSIZETToULong RtlULongPtrToULong
465 #define RtlSSIZETToULongLong RtlLongPtrToULongLong
466 #define RtlSSIZETToULong RtlLongPtrToULong
467 #define RtlLongLongToSizeT RtlLongLongToUIntPtr
468 #define RtlLongLongToSSIZET RtlLongLongToLongPtr
469 #define RtlLongLongToSIZET RtlLongLongToULongPtr
470 #ifdef _WIN64
471 #define RtlIntToUIntPtr RtlIntToULongLong
472 #define RtlULongLongToIntPtr RtlULongLongToLongLong
473 #else
474 #define RtlIntToUIntPtr RtlIntToUInt
475 #define RtlULongLongToIntPtr RtlULongLongToInt
476 #define RtlULongLongToUIntPtr RtlULongLongToUInt
477 #define RtlULongLongToULongPtr RtlULongLongToULong
478 #endif
479
480 #else // _NTINTSAFE_H_INCLUDED_
481
482 #define Int8ToByte Int8ToUInt8
483 #define Int8ToUInt16 Int8ToUShort
484 #define Int8ToWord Int8ToUShort
485 #define Int8ToUInt32 Int8ToUInt
486 #define Int8ToDWord Int8ToULong
487 #define Int8ToDWordPtr Int8ToULongPtr
488 #define Int8ToDWordLong Int8ToULongLong
489 #define Int8ToULong64 Int8ToULongLong
490 #define Int8ToDWord64 Int8ToULongLong
491 #define Int8ToUInt64 Int8ToULongLong
492 #define Int8ToSizeT Int8ToUIntPtr
493 #define Int8ToSIZET Int8ToULongPtr
494 #define IntToSizeT IntToUIntPtr
495 #define IntToSIZET IntToULongPtr
496 #define ULongToSSIZET ULongToLongPtr
497 #define ULongToByte ULongToUInt8
498 #define ULongLongToInt64 ULongLongToLongLong
499 #define ULongLongToLong64 ULongLongToLongLong
500 #define ULongLongToPtrdiffT ULongLongToIntPtr
501 #define ULongLongToSizeT ULongLongToUIntPtr
502 #define ULongLongToSSIZET ULongLongToLongPtr
503 #define ULongLongToSIZET ULongLongToULongPtr
504 #define SIZETToULong ULongPtrToULong
505 #define SSIZETToULongLong LongPtrToULongLong
506 #define SSIZETToULong LongPtrToULong
507 #define LongLongToSizeT LongLongToUIntPtr
508 #define LongLongToSSIZET LongLongToLongPtr
509 #define LongLongToSIZET LongLongToULongPtr
510 #ifdef _WIN64
511 #define IntToUIntPtr IntToULongLong
512 #define ULongLongToIntPtr ULongLongToLongLong
513 #else
514 #define IntToUIntPtr IntToUInt
515 #define ULongLongToIntPtr ULongLongToInt
516 #define ULongLongToUIntPtr ULongLongToUInt
517 #define ULongLongToULongPtr ULongLongToULong
518 #endif
519
520 #endif // _NTINTSAFE_H_INCLUDED_
521
522
523 #define DEFINE_SAFE_ADD(_Name, _Type) \
524 _Must_inspect_result_ \
525 __forceinline \
526 INTSAFE_RESULT \
527 INTSAFE_NAME(_Name)( \
528 _In_ _Type Augend, \
529 _In_ _Type Addend, \
530 _Out_ _Deref_out_range_(==, Augend + Addend) _Type *pOutput) \
531 { \
532 if ((_Type)(Augend + Addend) >= Augend) \
533 { \
534 *pOutput = Augend + Addend; \
535 return INTSAFE_SUCCESS; \
536 } \
537 else \
538 { \
539 *pOutput = _Type ## _ERROR; \
540 return INTSAFE_E_ARITHMETIC_OVERFLOW; \
541 } \
542 }
543
544 DEFINE_SAFE_ADD(UInt8Add, UINT8)
545 DEFINE_SAFE_ADD(UShortAdd, USHORT)
546 DEFINE_SAFE_ADD(UIntAdd, UINT)
547 DEFINE_SAFE_ADD(ULongAdd, ULONG)
548 DEFINE_SAFE_ADD(UIntPtrAdd, UINT_PTR)
549 DEFINE_SAFE_ADD(ULongPtrAdd, ULONG_PTR)
550 DEFINE_SAFE_ADD(DWordPtrAdd, DWORD_PTR)
551 DEFINE_SAFE_ADD(SizeTAdd, size_t)
552 DEFINE_SAFE_ADD(SIZETAdd, SIZE_T)
553 DEFINE_SAFE_ADD(ULongLongAdd, ULONGLONG)
554
555
556 #define DEFINE_SAFE_SUB(_Name, _Type) \
557 _Must_inspect_result_ \
558 __forceinline \
559 INTSAFE_RESULT \
560 INTSAFE_NAME(_Name)( \
561 _In_ _Type Minuend, \
562 _In_ _Type Subtrahend, \
563 _Out_ _Deref_out_range_(==, Minuend - Subtrahend) _Type* pOutput) \
564 { \
565 if (Minuend >= Subtrahend) \
566 { \
567 *pOutput = Minuend - Subtrahend; \
568 return INTSAFE_SUCCESS; \
569 } \
570 else \
571 { \
572 *pOutput = _Type ## _ERROR; \
573 return INTSAFE_E_ARITHMETIC_OVERFLOW; \
574 } \
575 }
576
577 DEFINE_SAFE_SUB(UInt8Sub, UINT8)
578 DEFINE_SAFE_SUB(UShortSub, USHORT)
579 DEFINE_SAFE_SUB(UIntSub, UINT)
580 DEFINE_SAFE_SUB(UIntPtrSub, UINT_PTR)
581 DEFINE_SAFE_SUB(ULongSub, ULONG)
582 DEFINE_SAFE_SUB(ULongPtrSub, ULONG_PTR)
583 DEFINE_SAFE_SUB(DWordPtrSub, DWORD_PTR)
584 DEFINE_SAFE_SUB(SizeTSub, size_t)
585 DEFINE_SAFE_SUB(SIZETSub, SIZE_T)
586 DEFINE_SAFE_SUB(ULongLongSub, ULONGLONG)
587
588 #ifdef ENABLE_INTSAFE_SIGNED_FUNCTIONS
589 _Must_inspect_result_
590 __forceinline
591 INTSAFE_RESULT
592 INTSAFE_NAME(LongLongAdd)(
593 _In_ LONGLONG Augend,
594 _In_ LONGLONG Addend,
595 _Out_ _Deref_out_range_(==, Augend + Addend) LONGLONG* pResult)
596 {
597 LONGLONG Result = Augend + Addend;
598
599 /* The only way the result can overflow, is when the sign of the augend
600 and the addend are the same. In that case the result is expected to
601 have the same sign as the two, otherwise it overflowed.
602 Sign equality is checked with a binary xor operation. */
603 if ( ((Augend ^ Addend) >= 0) && ((Augend ^ Result) < 0) )
604 {
605 *pResult = LONGLONG_ERROR;
606 return INTSAFE_E_ARITHMETIC_OVERFLOW;
607 }
608 else
609 {
610 *pResult = Result;
611 return INTSAFE_SUCCESS;
612 }
613 }
614
615
616 #define DEFINE_SAFE_ADD_S(_Name, _Type1, _Type2, _Convert) \
617 C_ASSERT(sizeof(_Type2) > sizeof(_Type1)); \
618 _Must_inspect_result_ \
619 __forceinline \
620 INTSAFE_RESULT \
621 INTSAFE_NAME(_Name)( \
622 _In_ _Type1 Augend, \
623 _In_ _Type1 Addend, \
624 _Out_ _Deref_out_range_(==, Augend + Addend) _Type1* pOutput) \
625 { \
626 return INTSAFE_NAME(_Convert)(((_Type2)Augend) + ((_Type2)Addend), pOutput); \
627 }
628
DEFINE_SAFE_ADD_S(Int8Add,INT8,SHORT,ShortToInt8)629 DEFINE_SAFE_ADD_S(Int8Add, INT8, SHORT, ShortToInt8)
630 DEFINE_SAFE_ADD_S(ShortAdd, SHORT, INT, IntToShort)
631 DEFINE_SAFE_ADD_S(IntAdd, INT, LONGLONG, LongLongToInt)
632 DEFINE_SAFE_ADD_S(LongAdd, LONG, LONGLONG, LongLongToLong)
633 #ifndef _WIN64
634 DEFINE_SAFE_ADD_S(IntPtrAdd, INT_PTR, LONGLONG, LongLongToIntPtr)
635 DEFINE_SAFE_ADD_S(LongPtrAdd, LONG_PTR, LONGLONG, LongLongToLongPtr)
636 #endif
637
638 _Must_inspect_result_
639 __forceinline
640 INTSAFE_RESULT
641 INTSAFE_NAME(LongLongSub)(
642 _In_ LONGLONG Minuend,
643 _In_ LONGLONG Subtrahend,
644 _Out_ _Deref_out_range_(==, Minuend - Subtrahend) LONGLONG* pResult)
645 {
646 LONGLONG Result = Minuend - Subtrahend;
647
648 /* The only way the result can overflow, is when the sign of the minuend
649 and the subtrahend differ. In that case the result is expected to
650 have the same sign as the minuend, otherwise it overflowed.
651 Sign equality is checked with a binary xor operation. */
652 if ( ((Minuend ^ Subtrahend) < 0) && ((Minuend ^ Result) < 0) )
653 {
654 *pResult = LONGLONG_ERROR;
655 return INTSAFE_E_ARITHMETIC_OVERFLOW;
656 }
657 else
658 {
659 *pResult = Result;
660 return INTSAFE_SUCCESS;
661 }
662 }
663
664
665 #define DEFINE_SAFE_SUB_S(_Name, _Type1, _Type2, _Convert) \
666 C_ASSERT(sizeof(_Type2) > sizeof(_Type1)); \
667 _Must_inspect_result_ \
668 __forceinline \
669 INTSAFE_RESULT \
670 INTSAFE_NAME(_Name)( \
671 _In_ _Type1 Minuend, \
672 _In_ _Type1 Subtrahend, \
673 _Out_ _Deref_out_range_(==, Minuend - Subtrahend) _Type1* pOutput) \
674 { \
675 return INTSAFE_NAME(_Convert)(((_Type2)Minuend) - ((_Type2)Subtrahend), pOutput); \
676 }
677
DEFINE_SAFE_SUB_S(LongSub,LONG,LONGLONG,LongLongToLong)678 DEFINE_SAFE_SUB_S(LongSub, LONG, LONGLONG, LongLongToLong)
679 #ifndef _WIN64
680 DEFINE_SAFE_SUB_S(IntPtrSub, INT_PTR, LONGLONG, LongLongToIntPtr)
681 DEFINE_SAFE_SUB_S(LongPtrSub, LONG_PTR, LONGLONG, LongLongToLongPtr)
682 #endif
683
684 #endif /* ENABLE_INTSAFE_SIGNED_FUNCTIONS */
685
686 _Must_inspect_result_
687 __forceinline
688 INTSAFE_RESULT
689 INTSAFE_NAME(ULongLongMult)(
690 _In_ ULONGLONG Multiplicand,
691 _In_ ULONGLONG Multiplier,
692 _Out_ _Deref_out_range_(==, Multiplicand * Multiplier) ULONGLONG* pOutput)
693 {
694 /* We can split the 64 bit numbers in low and high parts:
695 M1 = M1Low + M1Hi * 0x100000000
696 M2 = M2Low + M2Hi * 0x100000000
697
698 Then the multiplication looks like this:
699 M1 * M2 = (M1Low + M1Hi * 0x100000000) * (M2Low + M2Hi * 0x100000000)
700 = M1Low * M2Low
701 + M1Low * M2Hi * 0x100000000
702 + M2Low * M1Hi * 0x100000000
703 + M1Hi * M2Hi * 0x100000000 * 0x100000000
704
705 We get an overflow when
706 a) M1Hi * M2Hi != 0, so when M1Hi and M2Hi are both not 0
707 b) The product of the nonzero high part and the other low part
708 is larger than 32 bits.
709 c) The addition of the product from b) shifted left by 32 and
710 M1Low * M2Low is larger than 64 bits
711 */
712 ULONG M1Low = Multiplicand & 0xffffffff;
713 ULONG M2Low = Multiplier & 0xffffffff;
714 ULONG M1Hi = Multiplicand >> 32;
715 ULONG M2Hi = Multiplier >> 32;
716 ULONGLONG Temp;
717
718 if (M1Hi == 0)
719 {
720 Temp = UInt32x32To64(M1Low, M2Hi);
721 }
722 else if (M2Hi == 0)
723 {
724 Temp = UInt32x32To64(M1Hi, M2Low);
725 }
726 else
727 {
728 *pOutput = ULONGLONG_ERROR;
729 return INTSAFE_E_ARITHMETIC_OVERFLOW;
730 }
731
732 if (Temp > ULONG_MAX)
733 {
734 *pOutput = ULONGLONG_ERROR;
735 return INTSAFE_E_ARITHMETIC_OVERFLOW;
736 }
737
738 return INTSAFE_NAME(ULongLongAdd)(Temp << 32, UInt32x32To64(M1Low, M2Low), pOutput);
739 }
740
741
742 #define DEFINE_SAFE_MULT_U32(_Name, _Type, _Convert) \
743 _Must_inspect_result_ \
744 __forceinline \
745 INTSAFE_RESULT \
746 INTSAFE_NAME(_Name)( \
747 _In_ _Type Multiplicand, \
748 _In_ _Type Multiplier, \
749 _Out_ _Deref_out_range_(==, Multiplicand * Multiplier) _Type* pOutput) \
750 { \
751 ULONGLONG Result = UInt32x32To64(Multiplicand, Multiplier); \
752 return INTSAFE_NAME(_Convert)(Result, pOutput); \
753 }
754
755 DEFINE_SAFE_MULT_U32(ULongMult, ULONG, ULongLongToULong)
756 #ifndef _WIN64
757 DEFINE_SAFE_MULT_U32(SizeTMult, size_t, ULongLongToSizeT)
758 DEFINE_SAFE_MULT_U32(SIZETMult, SIZE_T, ULongLongToSIZET)
759 #endif
760
761 #define DEFINE_SAFE_MULT_U16(_Name, _Type, _Convert) \
762 _Must_inspect_result_ \
763 __forceinline \
764 INTSAFE_RESULT \
765 INTSAFE_NAME(_Name)( \
766 _In_ _Type Multiplicand, \
767 _In_ _Type Multiplier, \
768 _Out_ _Deref_out_range_(==, Multiplicand * Multiplier) _Type* pOutput) \
769 { \
770 ULONG Result = ((ULONG)Multiplicand) * ((ULONG)Multiplier); \
771 return INTSAFE_NAME(_Convert)(Result, pOutput); \
772 }
773
774 DEFINE_SAFE_MULT_U16(UShortMult, USHORT, ULongToUShort)
775
776
777 #ifdef _NTINTSAFE_H_INCLUDED_
778
779 #define RtlUInt16Add RtlUShortAdd
780 #define RtlWordAdd RtlUShortAdd
781 #define RtlUInt32Add RtlUIntAdd
782 #define RtlDWordAdd RtlULongAdd
783 #define RtlDWordLongAdd RtlULongLongAdd
784 #define RtlULong64Add RtlULongLongAdd
785 #define RtlDWord64Add RtlULongLongAdd
786 #define RtlUInt64Add RtlULongLongAdd
787 #define RtlUInt16Sub RtlUShortSub
788 #define RtlWordSub RtlUShortSub
789 #define RtlUInt32Sub RtlUIntSub
790 #define RtlDWordSub RtlULongSub
791 #define RtlDWordLongSub RtlULongLongSub
792 #define RtlULong64Sub RtlULongLongSub
793 #define RtlDWord64Sub RtlULongLongSub
794 #define RtlUInt64Sub RtlULongLongSub
795 #define RtlUInt16Mult RtlUShortMult
796 #define RtlWordMult RtlUShortMult
797 #ifdef _WIN64
798 #define RtlIntPtrAdd RtlLongLongAdd
799 #define RtlLongPtrAdd RtlLongLongAdd
800 #define RtlIntPtrSub RtlLongLongSub
801 #define RtlLongPtrSub RtlLongLongSub
802 #define RtlSizeTMult RtlULongLongMult
803 #define RtlSIZETMult RtlULongLongMult
804 #else
805 #endif
806
807 #else // _NTINTSAFE_H_INCLUDED_
808
809 #define UInt16Add UShortAdd
810 #define WordAdd UShortAdd
811 #define UInt32Add UIntAdd
812 #define DWordAdd ULongAdd
813 #define DWordLongAdd ULongLongAdd
814 #define ULong64Add ULongLongAdd
815 #define DWord64Add ULongLongAdd
816 #define UInt64Add ULongLongAdd
817 #define UInt16Sub UShortSub
818 #define WordSub UShortSub
819 #define UInt32Sub UIntSub
820 #define DWordSub ULongSub
821 #define DWordLongSub ULongLongSub
822 #define ULong64Sub ULongLongSub
823 #define DWord64Sub ULongLongSub
824 #define UInt64Sub ULongLongSub
825 #define UInt16Mult UShortMult
826 #define WordMult UShortMult
827 #ifdef _WIN64
828 #define IntPtrAdd LongLongAdd
829 #define LongPtrAdd LongLongAdd
830 #define IntPtrSub LongLongSub
831 #define LongPtrSub LongLongSub
832 #define SizeTMult ULongLongMult
833 #define SIZETMult ULongLongMult
834 #else
835 #endif
836
837 #undef _INTSAFE_CHAR_MIN
838 #undef _INTSAFE_CHAR_MAX
839 #undef _INTSAFE_CHAR_ERROR
840
841 #endif // _NTINTSAFE_H_INCLUDED_
842
843 #endif // !_INTSAFE_H_INCLUDED_
844