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