[BASESRV-CONSRV-WINSRV]
[reactos.git] / 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(UINT_PTR) == sizeof(ULONG_PTR));
123
124 /* Undefine these to avoid conflicts with limits.h */
125 #undef CHAR_MIN
126 #undef CHAR_MAX
127 #undef INT_MIN
128 #undef INT_MAX
129 #undef LONG_MIN
130 #undef LONG_MAX
131 #undef UCHAR_MAX
132 #undef UINT_MAX
133 #undef ULONG_MAX
134
135 /* Integer range margins (use (x-1) to prevent warnings) */
136 #define INT8_MIN (-127 - 1)
137 #define SHORT_MIN (-32767 - 1)
138 #define INT16_MIN (-32767 - 1)
139 #define INT_MIN (-2147483647 - 1)
140 #define INT32_MIN (-2147483647 - 1)
141 #define LONG_MIN (-2147483647L - 1)
142 #define LONGLONG_MIN (-9223372036854775807LL - 1)
143 #define LONG64_MIN (-9223372036854775807LL - 1)
144 #define INT64_MIN (-9223372036854775807LL - 1)
145 //#define INT128_MIN (-170141183460469231731687303715884105728)
146 #ifdef _WIN64
147 #define INT_PTR_MIN INT64_MIN
148 #define LONG_PTR_MIN LONG64_MIN
149 #define PTRDIFF_T_MIN INT64_MIN
150 #define SSIZE_T_MIN INT64_MIN
151 #else // _WIN64
152 #define INT_PTR_MIN INT_MIN
153 #define LONG_PTR_MIN LONG_MIN
154 #define PTRDIFF_T_MIN INT_MIN
155 #define SSIZE_T_MIN INT_MIN
156 #endif // _WIN64
157
158 #define INT8_MAX 127
159 #define UINT8_MAX 0xff
160 #define UCHAR_MAX 0xff
161 #define BYTE_MAX 0xff
162 #define SHORT_MAX 32767
163 #define INT16_MAX 32767
164 #define USHORT_MAX 0xffff
165 #define UINT16_MAX 0xffff
166 #define WORD_MAX 0xffff
167 #define INT_MAX 2147483647
168 #define INT32_MAX 2147483647
169 #define UINT_MAX 0xffffffff
170 #define UINT32_MAX 0xffffffff
171 #define LONG_MAX 2147483647L
172 #define ULONG_MAX 0xffffffffUL
173 #define DWORD_MAX 0xffffffffUL
174 #define LONGLONG_MAX 9223372036854775807LL
175 #define LONG64_MAX 9223372036854775807LL
176 #define INT64_MAX 9223372036854775807LL
177 #define ULONGLONG_MAX 0xffffffffffffffffULL
178 #define DWORDLONG_MAX 0xffffffffffffffffULL
179 #define ULONG64_MAX 0xffffffffffffffffULL
180 #define DWORD64_MAX 0xffffffffffffffffULL
181 #define UINT64_MAX 0xffffffffffffffffULL
182 #define INT128_MAX 170141183460469231731687303715884105727
183 #define UINT128_MAX 0xffffffffffffffffffffffffffffffff
184 #undef SIZE_T_MAX
185 #ifdef _WIN64
186 #define INT_PTR_MAX INT64_MAX
187 #define UINT_PTR_MAX UINT64_MAX
188 #define LONG_PTR_MAX LONG64_MAX
189 #define ULONG_PTR_MAX ULONG64_MAX
190 #define DWORD_PTR_MAX DWORD64_MAX
191 #define PTRDIFF_T_MAX INT64_MAX
192 #define SIZE_T_MAX UINT64_MAX
193 #define SSIZE_T_MAX INT64_MAX
194 #define _SIZE_T_MAX UINT64_MAX
195 #else // _WIN64
196 #define INT_PTR_MAX INT_MAX
197 #define UINT_PTR_MAX UINT_MAX
198 #define LONG_PTR_MAX LONG_MAX
199 #define ULONG_PTR_MAX ULONG_MAX
200 #define DWORD_PTR_MAX DWORD_MAX
201 #define PTRDIFF_T_MAX INT_MAX
202 #define SIZE_T_MAX UINT_MAX
203 #define SSIZE_T_MAX INT_MAX
204 #define _SIZE_T_MAX UINT_MAX
205 #endif // _WIN64
206
207 #ifndef CHAR_MIN
208 #ifdef _CHAR_UNSIGNED
209 #define CHAR_MIN 0
210 #define CHAR_MAX 0xff
211 #else
212 #define CHAR_MIN (-128)
213 #define CHAR_MAX 127
214 #endif
215 #endif
216
217 /* Error values */
218 #define INT8_ERROR (-1)
219 #define UINT8_ERROR 0xff
220 #define BYTE_ERROR 0xff
221 #define SHORT_ERROR (-1)
222 #define INT16_ERROR (-1)
223 #define USHORT_ERROR 0xffff
224 #define UINT16_ERROR 0xffff
225 #define WORD_ERROR 0xffff
226 #define INT_ERROR (-1)
227 #define INT32_ERROR (-1)
228 #define UINT_ERROR 0xffffffff
229 #define UINT32_ERROR 0xffffffff
230 #define LONG_ERROR (-1L)
231 #define ULONG_ERROR 0xffffffffUL
232 #define DWORD_ERROR 0xffffffffUL
233 #define LONGLONG_ERROR (-1LL)
234 #define LONG64_ERROR (-1LL)
235 #define INT64_ERROR (-1LL)
236 #define ULONGLONG_ERROR 0xffffffffffffffffULL
237 #define DWORDLONG_ERROR 0xffffffffffffffffULL
238 #define ULONG64_ERROR 0xffffffffffffffffULL
239 #define UINT64_ERROR 0xffffffffffffffffULL
240 #ifdef _WIN64
241 #define INT_PTR_ERROR (-1LL)
242 #define UINT_PTR_ERROR 0xffffffffffffffffULL
243 #define LONG_PTR_ERROR (-1LL)
244 #define ULONG_PTR_ERROR 0xffffffffffffffffULL
245 #define DWORD_PTR_ERROR 0xffffffffffffffffULL
246 #define PTRDIFF_T_ERROR (-1LL)
247 #define SIZE_T_ERROR 0xffffffffffffffffULL
248 #define SSIZE_T_ERROR (-1LL)
249 #define _SIZE_T_ERROR 0xffffffffffffffffULL
250 #else // _WIN64
251 #define INT_PTR_ERROR (-1)
252 #define UINT_PTR_ERROR 0xffffffff
253 #define LONG_PTR_ERROR (-1L)
254 #define ULONG_PTR_ERROR 0xffffffffUL
255 #define DWORD_PTR_ERROR 0xffffffffUL
256 #define PTRDIFF_T_ERROR (-1)
257 #define SIZE_T_ERROR 0xffffffff
258 #define SSIZE_T_ERROR (-1L)
259 #define _SIZE_T_ERROR 0xffffffffUL
260 #endif // _WIN64
261
262 #define size_t_ERROR SIZE_T_ERROR
263 #define UCHAR_ERROR '\0'
264 #define CHAR_ERROR '\0'
265
266
267 /* 32 bit x 32 bit to 64 bit unsigned multiplication */
268 #ifndef UInt32x32To64
269 #define UInt32x32To64(a,b) ((DWORDLONG)(a)*(DWORDLONG)(b))
270 #endif
271
272
273 #define DEFINE_SAFE_CONVERT_UTOX(_Name, _TypeFrom, _TypeTo) \
274 _Must_inspect_result_ \
275 __forceinline \
276 INTSAFE_RESULT \
277 INTSAFE_NAME(_Name)( \
278 _In_ _TypeFrom Input, \
279 _Out_ _Deref_out_range_(==, Input) _TypeTo *pOutput) \
280 { \
281 if (Input <= _TypeTo ## _MAX) \
282 { \
283 *pOutput = (_TypeTo)Input; \
284 return INTSAFE_SUCCESS; \
285 } \
286 else \
287 { \
288 *pOutput = _TypeTo ## _ERROR; \
289 return INTSAFE_E_ARITHMETIC_OVERFLOW; \
290 } \
291 }
292
293 DEFINE_SAFE_CONVERT_UTOX(ByteToChar, BYTE, CHAR)
294 DEFINE_SAFE_CONVERT_UTOX(ByteToInt8, BYTE, INT8)
295 DEFINE_SAFE_CONVERT_UTOX(UInt8ToChar, UINT8, CHAR)
296 DEFINE_SAFE_CONVERT_UTOX(UInt8ToInt8, UINT8, INT8)
297 DEFINE_SAFE_CONVERT_UTOX(UShortToChar, USHORT, CHAR)
298 DEFINE_SAFE_CONVERT_UTOX(UShortToUChar, USHORT, UCHAR)
299 DEFINE_SAFE_CONVERT_UTOX(UShortToInt8, USHORT, INT8)
300 DEFINE_SAFE_CONVERT_UTOX(UShortToUInt8, USHORT, UINT8)
301 DEFINE_SAFE_CONVERT_UTOX(UShortToShort, USHORT, SHORT)
302 DEFINE_SAFE_CONVERT_UTOX(UIntToUChar, UINT, UCHAR)
303 DEFINE_SAFE_CONVERT_UTOX(UIntToInt8, UINT, INT8)
304 DEFINE_SAFE_CONVERT_UTOX(UIntToUInt8, UINT, UINT8)
305 DEFINE_SAFE_CONVERT_UTOX(UIntToShort, UINT, SHORT)
306 DEFINE_SAFE_CONVERT_UTOX(UIntToUShort, UINT, USHORT)
307 DEFINE_SAFE_CONVERT_UTOX(UIntToInt, UINT, INT)
308 DEFINE_SAFE_CONVERT_UTOX(UIntToLong, UINT, LONG)
309 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToUChar, UINT_PTR, UCHAR)
310 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToInt8, UINT_PTR, INT8)
311 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToUInt8, UINT_PTR, UINT8)
312 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToShort, UINT_PTR, SHORT)
313 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToUShort, UINT_PTR, USHORT)
314 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToInt16, UINT_PTR, INT16)
315 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToUInt16, UINT_PTR, UINT16)
316 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToInt, UINT_PTR, INT)
317 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToLong, UINT_PTR, LONG)
318 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToIntPtr, UINT_PTR, INT_PTR)
319 DEFINE_SAFE_CONVERT_UTOX(UIntPtrToLongPtr, UINT_PTR, LONG_PTR)
320 DEFINE_SAFE_CONVERT_UTOX(ULongToUChar, ULONG, UCHAR)
321 DEFINE_SAFE_CONVERT_UTOX(ULongToUInt8, ULONG, UINT8)
322 DEFINE_SAFE_CONVERT_UTOX(ULongToShort, ULONG, SHORT)
323 DEFINE_SAFE_CONVERT_UTOX(ULongToUShort, ULONG, USHORT)
324 DEFINE_SAFE_CONVERT_UTOX(ULongToInt, ULONG, INT)
325 DEFINE_SAFE_CONVERT_UTOX(ULongToUInt, ULONG, UINT)
326 DEFINE_SAFE_CONVERT_UTOX(ULongToIntPtr, ULONG, INT_PTR)
327 DEFINE_SAFE_CONVERT_UTOX(ULongToUIntPtr, ULONG, UINT_PTR)
328 DEFINE_SAFE_CONVERT_UTOX(ULongToLongPtr, ULONG, LONG_PTR)
329 DEFINE_SAFE_CONVERT_UTOX(ULongPtrToULong, ULONG_PTR, ULONGLONG)
330 DEFINE_SAFE_CONVERT_UTOX(ULongLongToUInt, ULONGLONG, UINT)
331 DEFINE_SAFE_CONVERT_UTOX(ULongLongToULong, ULONGLONG, ULONG)
332 DEFINE_SAFE_CONVERT_UTOX(ULongLongToULongPtr, ULONGLONG, ULONG_PTR)
333
334
335 #define DEFINE_SAFE_CONVERT_ITOU(_Name, _TypeFrom, _TypeTo) \
336 _Must_inspect_result_ \
337 __forceinline \
338 INTSAFE_RESULT \
339 INTSAFE_NAME(_Name)( \
340 _In_ _TypeFrom Input, \
341 _Out_ _Deref_out_range_(==, Input) _TypeTo *pOutput) \
342 { \
343 if ((Input >= 0) && (Input <= _TypeTo ## _MAX)) \
344 { \
345 *pOutput = (_TypeTo)Input; \
346 return INTSAFE_SUCCESS; \
347 } \
348 else \
349 { \
350 *pOutput = _TypeTo ## _ERROR; \
351 return INTSAFE_E_ARITHMETIC_OVERFLOW; \
352 } \
353 }
354
355 DEFINE_SAFE_CONVERT_ITOU(Int8ToUChar, INT8, UCHAR)
356 DEFINE_SAFE_CONVERT_ITOU(Int8ToUInt8, INT8, UINT8)
357 DEFINE_SAFE_CONVERT_ITOU(Int8ToUShort, INT8, USHORT)
358 DEFINE_SAFE_CONVERT_ITOU(Int8ToUInt, INT8, UINT)
359 DEFINE_SAFE_CONVERT_ITOU(Int8ToULong, INT8, ULONG)
360 DEFINE_SAFE_CONVERT_ITOU(Int8ToUIntPtr, INT8, UINT_PTR)
361 DEFINE_SAFE_CONVERT_ITOU(Int8ToULongPtr, INT8, ULONG_PTR)
362 DEFINE_SAFE_CONVERT_ITOU(Int8ToULongLong, INT8, ULONGLONG)
363 DEFINE_SAFE_CONVERT_ITOU(ShortToUChar, SHORT, UCHAR)
364 DEFINE_SAFE_CONVERT_ITOU(ShortToUInt8, SHORT, UINT8)
365 DEFINE_SAFE_CONVERT_ITOU(ShortToUShort, SHORT, USHORT)
366 DEFINE_SAFE_CONVERT_ITOU(ShortToUInt, SHORT, UINT)
367 DEFINE_SAFE_CONVERT_ITOU(ShortToULong, SHORT, ULONG)
368 DEFINE_SAFE_CONVERT_ITOU(ShortToUIntPtr, SHORT, UINT_PTR)
369 DEFINE_SAFE_CONVERT_ITOU(ShortToULongPtr, SHORT, ULONG_PTR)
370 DEFINE_SAFE_CONVERT_ITOU(ShortToDWordPtr, SHORT, DWORD_PTR)
371 DEFINE_SAFE_CONVERT_ITOU(ShortToULongLong, SHORT, ULONGLONG)
372 DEFINE_SAFE_CONVERT_ITOU(IntToUChar, INT, UCHAR)
373 DEFINE_SAFE_CONVERT_ITOU(IntToUInt8, INT, UINT8)
374 DEFINE_SAFE_CONVERT_ITOU(IntToUShort, INT, USHORT)
375 DEFINE_SAFE_CONVERT_ITOU(IntToUInt, INT, UINT)
376 DEFINE_SAFE_CONVERT_ITOU(IntToULong, INT, ULONG)
377 DEFINE_SAFE_CONVERT_ITOU(IntToULongLong, INT, ULONGLONG)
378 DEFINE_SAFE_CONVERT_ITOU(LongToUChar, LONG, UCHAR)
379 DEFINE_SAFE_CONVERT_ITOU(LongToUInt8, LONG, UINT8)
380 DEFINE_SAFE_CONVERT_ITOU(LongToUShort, LONG, USHORT)
381 DEFINE_SAFE_CONVERT_ITOU(LongToUInt, LONG, UINT)
382 DEFINE_SAFE_CONVERT_ITOU(LongToULong, LONG, ULONG)
383 DEFINE_SAFE_CONVERT_ITOU(LongToUIntPtr, LONG, UINT_PTR)
384 DEFINE_SAFE_CONVERT_ITOU(LongToULongPtr, LONG, ULONG_PTR)
385 DEFINE_SAFE_CONVERT_ITOU(LongToULongLong, LONG, ULONGLONG)
386 DEFINE_SAFE_CONVERT_ITOU(IntPtrToUChar, INT_PTR, UCHAR)
387 DEFINE_SAFE_CONVERT_ITOU(IntPtrToUInt8, INT_PTR, UINT8)
388 DEFINE_SAFE_CONVERT_ITOU(IntPtrToUShort, INT_PTR, USHORT)
389 DEFINE_SAFE_CONVERT_ITOU(IntPtrToUInt, INT_PTR, UINT)
390 DEFINE_SAFE_CONVERT_ITOU(IntPtrToULong, INT_PTR, ULONG)
391 DEFINE_SAFE_CONVERT_ITOU(IntPtrToUIntPtr, INT_PTR, UINT_PTR)
392 DEFINE_SAFE_CONVERT_ITOU(IntPtrToULongPtr, INT_PTR, ULONG_PTR)
393 DEFINE_SAFE_CONVERT_ITOU(IntPtrToULongLong, INT_PTR, ULONGLONG)
394 DEFINE_SAFE_CONVERT_ITOU(LongPtrToUChar, LONG_PTR, UCHAR)
395 DEFINE_SAFE_CONVERT_ITOU(LongPtrToUInt8, LONG_PTR, UINT8)
396 DEFINE_SAFE_CONVERT_ITOU(LongPtrToUShort, LONG_PTR, USHORT)
397 DEFINE_SAFE_CONVERT_ITOU(LongPtrToUInt, LONG_PTR, UINT)
398 DEFINE_SAFE_CONVERT_ITOU(LongPtrToULong, LONG_PTR, ULONG)
399 DEFINE_SAFE_CONVERT_ITOU(LongPtrToUIntPtr, LONG_PTR, UINT_PTR)
400 DEFINE_SAFE_CONVERT_ITOU(LongPtrToULongPtr, LONG_PTR, ULONG_PTR)
401 DEFINE_SAFE_CONVERT_ITOU(LongPtrToULongLong, LONG_PTR, ULONGLONG)
402 #ifdef _CHAR_UNSIGNED
403 DEFINE_SAFE_CONVERT_ITOU(ShortToChar, SHORT, UCHAR)
404 DEFINE_SAFE_CONVERT_ITOU(LongPtrToChar, LONG_PTR, UCHAR)
405 #endif
406
407
408 #define DEFINE_SAFE_CONVERT_ITOI(_Name, _TypeFrom, _TypeTo) \
409 _Must_inspect_result_ \
410 __forceinline \
411 INTSAFE_RESULT \
412 INTSAFE_NAME(_Name)( \
413 _In_ _TypeFrom Input, \
414 _Out_ _Deref_out_range_(==, Input) _TypeTo *pOutput) \
415 { \
416 if ((Input >= _TypeTo ## _MIN) && (Input <= _TypeTo ## _MAX)) \
417 { \
418 *pOutput = (_TypeTo)Input; \
419 return INTSAFE_SUCCESS; \
420 } \
421 else \
422 { \
423 *pOutput = _TypeTo ## _ERROR; \
424 return INTSAFE_E_ARITHMETIC_OVERFLOW; \
425 } \
426 }
427
428 DEFINE_SAFE_CONVERT_ITOI(ShortToInt8, SHORT, INT8)
429 DEFINE_SAFE_CONVERT_ITOI(IntToInt8, INT, INT8)
430 DEFINE_SAFE_CONVERT_ITOI(IntToShort, INT, SHORT)
431 DEFINE_SAFE_CONVERT_ITOI(LongToInt8, LONG, INT8)
432 DEFINE_SAFE_CONVERT_ITOI(LongToShort, LONG, SHORT)
433 DEFINE_SAFE_CONVERT_ITOI(LongToInt, LONG, INT)
434 DEFINE_SAFE_CONVERT_ITOI(IntPtrToInt8, INT_PTR, INT8)
435 DEFINE_SAFE_CONVERT_ITOI(IntPtrToShort, INT_PTR, SHORT)
436 DEFINE_SAFE_CONVERT_ITOI(IntPtrToInt, INT_PTR, INT)
437 DEFINE_SAFE_CONVERT_ITOI(IntPtrToLong, INT_PTR, LONG)
438 DEFINE_SAFE_CONVERT_ITOI(IntPtrToLongPtr, INT_PTR, LONG_PTR)
439 DEFINE_SAFE_CONVERT_ITOI(LongPtrToInt8, LONG_PTR, INT8)
440 DEFINE_SAFE_CONVERT_ITOI(LongPtrToShort, LONG_PTR, SHORT)
441 DEFINE_SAFE_CONVERT_ITOI(LongPtrToInt, LONG_PTR, INT)
442 DEFINE_SAFE_CONVERT_ITOI(LongPtrToLong, LONG_PTR, LONG)
443 DEFINE_SAFE_CONVERT_ITOI(LongPtrToIntPtr, LONG_PTR, INT_PTR)
444 DEFINE_SAFE_CONVERT_ITOI(LongLongToLong, LONGLONG, LONG)
445 DEFINE_SAFE_CONVERT_ITOI(LongLongToIntPtr, LONGLONG, INT_PTR)
446 DEFINE_SAFE_CONVERT_ITOI(LongLongToLongPtr, LONGLONG, LONG_PTR)
447 #ifndef _CHAR_UNSIGNED
448 DEFINE_SAFE_CONVERT_ITOI(ShortToChar, SHORT, CHAR)
449 DEFINE_SAFE_CONVERT_ITOI(LongPtrToChar, LONG_PTR, CHAR)
450 #endif
451
452
453 #ifdef _NTINTSAFE_H_INCLUDED_
454
455 #define RtlInt8ToByte RtlInt8ToUInt8
456 #define RtlInt8ToUInt16 RtlInt8ToUShort
457 #define RtlInt8ToWord RtlInt8ToUShort
458 #define RtlInt8ToUInt32 RtlInt8ToUInt
459 #define RtlInt8ToDWord RtlInt8ToULong
460 #define RtlInt8ToDWordPtr RtlInt8ToULongPtr
461 #define RtlInt8ToDWordLong RtlInt8ToULongLong
462 #define RtlInt8ToULong64 RtlInt8ToULongLong
463 #define RtlInt8ToDWord64 RtlInt8ToULongLong
464 #define RtlInt8ToUInt64 RtlInt8ToULongLong
465 #define RtlInt8ToSizeT RtlInt8ToUIntPtr
466 #define RtlInt8ToSIZET RtlInt8ToULongPtr
467 #define RtlIntToSizeT RtlIntToUIntPtr
468 #define RtlIntToSIZET RtlIntToULongPtr
469 #define RtlULongToByte RtlULongToUInt8
470 #define RtlULongLongToInt64 RtlULongLongToLongLong
471 #define RtlULongLongToLong64 RtlULongLongToLongLong
472 #define RtlULongLongToPtrdiffT RtlULongLongToIntPtr
473 #define RtlULongLongToSizeT RtlULongLongToUIntPtr
474 #define RtlULongLongToSSIZET RtlULongLongToLongPtr
475 #define RtlULongLongToSIZET RtlULongLongToULongPtr
476 #define RtlSIZETToULong RtlULongPtrToULong
477 #define RtlSSIZETToULongLong RtlLongPtrToULongLong
478 #define RtlSSIZETToULong RtlLongPtrToULong
479 #ifdef _WIN64
480 #define RtlIntToUIntPtr RtlIntToULongLong
481 #define RtlULongLongToIntPtr RtlULongLongToLongLong
482 #else
483 #define RtlIntToUIntPtr RtlIntToUInt
484 #define RtlULongLongToIntPtr RtlULongLongToInt
485 #define RtlULongLongToUIntPtr RtlULongLongToUInt
486 #define RtlULongLongToULongPtr RtlULongLongToULong
487 #endif
488
489 #else // _NTINTSAFE_H_INCLUDED_
490
491 #define Int8ToByte Int8ToUInt8
492 #define Int8ToUInt16 Int8ToUShort
493 #define Int8ToWord Int8ToUShort
494 #define Int8ToUInt32 Int8ToUInt
495 #define Int8ToDWord Int8ToULong
496 #define Int8ToDWordPtr Int8ToULongPtr
497 #define Int8ToDWordLong Int8ToULongLong
498 #define Int8ToULong64 Int8ToULongLong
499 #define Int8ToDWord64 Int8ToULongLong
500 #define Int8ToUInt64 Int8ToULongLong
501 #define Int8ToSizeT Int8ToUIntPtr
502 #define Int8ToSIZET Int8ToULongPtr
503 #define IntToSizeT IntToUIntPtr
504 #define IntToSIZET IntToULongPtr
505 #define ULongToByte ULongToUInt8
506 #define ULongLongToInt64 ULongLongToLongLong
507 #define ULongLongToLong64 ULongLongToLongLong
508 #define ULongLongToPtrdiffT ULongLongToIntPtr
509 #define ULongLongToSizeT ULongLongToUIntPtr
510 #define ULongLongToSSIZET ULongLongToLongPtr
511 #define ULongLongToSIZET ULongLongToULongPtr
512 #define SIZETToULong ULongPtrToULong
513 #define SSIZETToULongLong LongPtrToULongLong
514 #define SSIZETToULong LongPtrToULong
515 #ifdef _WIN64
516 #define IntToUIntPtr IntToULongLong
517 #define ULongLongToIntPtr ULongLongToLongLong
518 #else
519 #define IntToUIntPtr IntToUInt
520 #define ULongLongToIntPtr ULongLongToInt
521 #define ULongLongToUIntPtr ULongLongToUInt
522 #define ULongLongToULongPtr ULongLongToULong
523 #endif
524
525 #endif // _NTINTSAFE_H_INCLUDED_
526
527
528 #define DEFINE_SAFE_ADD(_Name, _Type) \
529 _Must_inspect_result_ \
530 __forceinline \
531 INTSAFE_RESULT \
532 INTSAFE_NAME(_Name)( \
533 _In_ _Type Augend, \
534 _In_ _Type Addend, \
535 _Out_ _Deref_out_range_(==, Augend + Addend) _Type *pOutput) \
536 { \
537 if ((Augend + Addend) >= Augend) \
538 { \
539 *pOutput = Augend + Addend; \
540 return INTSAFE_SUCCESS; \
541 } \
542 else \
543 { \
544 *pOutput = _Type ## _ERROR; \
545 return INTSAFE_E_ARITHMETIC_OVERFLOW; \
546 } \
547 }
548
549 DEFINE_SAFE_ADD(UInt8Add, UINT8)
550 DEFINE_SAFE_ADD(UShortAdd, USHORT)
551 DEFINE_SAFE_ADD(UIntAdd, UINT)
552 DEFINE_SAFE_ADD(ULongAdd, ULONG)
553 DEFINE_SAFE_ADD(UIntPtrAdd, UINT_PTR)
554 DEFINE_SAFE_ADD(ULongPtrAdd, ULONG_PTR)
555 DEFINE_SAFE_ADD(DWordPtrAdd, DWORD_PTR)
556 DEFINE_SAFE_ADD(SizeTAdd, size_t)
557 DEFINE_SAFE_ADD(SIZETAdd, SIZE_T)
558 DEFINE_SAFE_ADD(ULongLongAdd, ULONGLONG)
559
560
561 #define DEFINE_SAFE_SUB(_Name, _Type) \
562 _Must_inspect_result_ \
563 __forceinline \
564 INTSAFE_RESULT \
565 INTSAFE_NAME(_Name)( \
566 _In_ _Type Minuend, \
567 _In_ _Type Subtrahend, \
568 _Out_ _Deref_out_range_(==, Minuend - Subtrahend) _Type* pOutput) \
569 { \
570 if (Minuend >= Subtrahend) \
571 { \
572 *pOutput = Minuend - Subtrahend; \
573 return INTSAFE_SUCCESS; \
574 } \
575 else \
576 { \
577 *pOutput = _Type ## _ERROR; \
578 return INTSAFE_E_ARITHMETIC_OVERFLOW; \
579 } \
580 }
581
582 DEFINE_SAFE_SUB(UInt8Sub, UINT8)
583 DEFINE_SAFE_SUB(UShortSub, USHORT)
584 DEFINE_SAFE_SUB(UIntSub, UINT)
585 DEFINE_SAFE_SUB(UIntPtrSub, UINT_PTR)
586 DEFINE_SAFE_SUB(ULongSub, ULONG)
587 DEFINE_SAFE_SUB(ULongPtrSub, ULONG_PTR)
588 DEFINE_SAFE_SUB(DWordPtrSub, DWORD_PTR)
589 DEFINE_SAFE_SUB(SizeTSub, size_t)
590 DEFINE_SAFE_SUB(SIZETSub, SIZE_T)
591 DEFINE_SAFE_SUB(ULongLongSub, ULONGLONG)
592
593
594 _Must_inspect_result_
595 __forceinline
596 INTSAFE_RESULT
597 INTSAFE_NAME(LongLongSub)(
598 _In_ LONGLONG Minuend,
599 _In_ LONGLONG Subtrahend,
600 _Out_ _Deref_out_range_(==, Minuend - Subtrahend) LONGLONG* pResult)
601 {
602 LONGLONG Result = Minuend - Subtrahend;
603
604 /* The only way the result can overflow, is when the sign of the minuend
605 and the subtrahend differ. In that case the result is expected to
606 have the same sign as the minuend, otherwise it overflowed.
607 Sign equality is checked with a binary xor operation. */
608 if ( ((Minuend ^ Subtrahend) < 0) && ((Minuend ^ Result) < 0) )
609 {
610 *pResult = LONGLONG_ERROR;
611 return INTSAFE_E_ARITHMETIC_OVERFLOW;
612 }
613 else
614 {
615 *pResult = Result;
616 return INTSAFE_SUCCESS;
617 }
618 }
619
620
621 #define DEFINE_SAFE_SUB_S(_Name, _Type1, _Type2, _Convert) \
622 _Must_inspect_result_ \
623 __forceinline \
624 INTSAFE_RESULT \
625 INTSAFE_NAME(_Name)( \
626 _In_ _Type1 Minuend, \
627 _In_ _Type1 Subtrahend, \
628 _Out_ _Deref_out_range_(==, Minuend - Subtrahend) _Type1* pOutput) \
629 { \
630 return INTSAFE_NAME(_Convert)(((_Type2)Minuend) - ((_Type2)Subtrahend), pOutput); \
631 }
632
633 DEFINE_SAFE_SUB_S(LongSub, LONG, LONGLONG, LongLongToLong)
634 #ifndef _WIN64
635 DEFINE_SAFE_SUB_S(IntPtrSub, INT_PTR, LONGLONG, LongLongToIntPtr)
636 DEFINE_SAFE_SUB_S(LongPtrSub, LONG_PTR, LONGLONG, LongLongToLongPtr)
637 #endif
638
639
640 _Must_inspect_result_
641 __forceinline
642 INTSAFE_RESULT
643 INTSAFE_NAME(ULongLongMult)(
644 _In_ ULONGLONG Multiplicand,
645 _In_ ULONGLONG Multiplier,
646 _Out_ _Deref_out_range_(==, Multiplicand * Multiplier) ULONGLONG* pOutput)
647 {
648 /* We can split the 64 bit numbers in low and high parts:
649 M1 = M1Low + M1Hi * 0x100000000
650 M2 = M2Low + M2Hi * 0x100000000
651
652 Then the multiplication looks like this:
653 M1 * M2 = (M1Low + M1Hi * 0x100000000) + (M2Low + M2Hi * 0x100000000)
654 = M1Low * M2Low
655 + M1Low * M2Hi * 0x100000000
656 + M2Low * M1Hi * 0x100000000
657 + M1Hi * M2Hi * 0x100000000 * 0x100000000
658
659 We get an overflow when
660 a) M1Hi * M2Hi != 0, so when M1Hi or M2Hi are not 0
661 b) The product of the nonzero high part and the other low part
662 is larger than 32 bits.
663 c) The addition of the product from b) shifted left by 32 and
664 M1Low * M2Low is larger than 64 bits
665 */
666 ULONG M1Low = Multiplicand & 0xffffffff;
667 ULONG M2Low = Multiplier & 0xffffffff;
668 ULONG M1Hi = Multiplicand >> 32;
669 ULONG M2Hi = Multiplier >> 32;
670 ULONGLONG Temp;
671
672 if (M1Hi == 0)
673 {
674 Temp = UInt32x32To64(M1Low, M2Hi);
675 }
676 else if (M2Hi == 0)
677 {
678 Temp = UInt32x32To64(M1Hi, M2Low);
679 }
680 else
681 {
682 *pOutput = LONGLONG_ERROR;
683 return INTSAFE_E_ARITHMETIC_OVERFLOW;
684 }
685
686 if (Temp > ULONG_MAX)
687 {
688 *pOutput = LONGLONG_ERROR;
689 return INTSAFE_E_ARITHMETIC_OVERFLOW;
690 }
691
692 return INTSAFE_NAME(ULongLongAdd)(Temp << 32, UInt32x32To64(M1Low, M2Low), pOutput);
693 }
694
695
696 #define DEFINE_SAFE_MULT_U32(_Name, _Type, _Convert) \
697 __checkReturn \
698 __forceinline \
699 INTSAFE_RESULT \
700 INTSAFE_NAME(_Name)( \
701 _In_ _Type Multiplicand, \
702 _In_ _Type Multiplier, \
703 _Out_ _Deref_out_range_(==, Multiplicand * Multiplier) _Type* pOutput) \
704 { \
705 ULONGLONG Result = UInt32x32To64(Multiplicand, Multiplier); \
706 return INTSAFE_NAME(_Convert)(Result, pOutput); \
707 }
708
709 DEFINE_SAFE_MULT_U32(ULongMult, ULONG, ULongLongToULong)
710 #ifndef _WIN64
711 DEFINE_SAFE_MULT_U32(SizeTMult, size_t, ULongLongToSizeT)
712 DEFINE_SAFE_MULT_U32(SIZETMult, SIZE_T, ULongLongToSIZET)
713 #endif
714
715
716 #ifdef _NTINTSAFE_H_INCLUDED_
717
718 #define RtlUInt16Add RtlUShortAdd
719 #define RtlWordAdd RtlUShortAdd
720 #define RtlUInt32Add RtlUIntAdd
721 #define RtlDWordAdd RtlULongAdd
722 #define RtlDWordLongAdd RtlULongLongAdd
723 #define RtlULong64Add RtlULongLongAdd
724 #define RtlDWord64Add RtlULongLongAdd
725 #define RtlUInt64Add RtlULongLongAdd
726 #define RtlUInt16Sub RtlUShortSub
727 #define RtlWordSub RtlUShortSub
728 #define RtlUInt32Sub RtlUIntSub
729 #define RtlDWordSub RtlULongSub
730 #define RtlDWordLongSub RtlULongLongSub
731 #define RtlULong64Sub RtlULongLongSub
732 #define RtlDWord64Sub RtlULongLongSub
733 #define RtlUInt64Sub RtlULongLongSub
734 #ifdef _WIN64
735 #define RtlIntPtrSub RtlLongLongSub
736 #define RtlLongPtrSub RtlLongLongSub
737 #define RtlSizeTMult RtlULongLongMult
738 #define RtlSIZETMult RtlULongLongMult
739 #else
740 #endif
741
742 #else // _NTINTSAFE_H_INCLUDED_
743
744 #define UInt16Add UShortAdd
745 #define WordAdd UShortAdd
746 #define UInt32Add UIntAdd
747 #define DWordAdd ULongAdd
748 #define DWordLongAdd ULongLongAdd
749 #define ULong64Add ULongLongAdd
750 #define DWord64Add ULongLongAdd
751 #define UInt64Add ULongLongAdd
752 #define UInt16Sub UShortSub
753 #define WordSub UShortSub
754 #define UInt32Sub UIntSub
755 #define DWordSub ULongSub
756 #define DWordLongSub ULongLongSub
757 #define ULong64Sub ULongLongSub
758 #define DWord64Sub ULongLongSub
759 #define UInt64Sub ULongLongSub
760 #ifdef _WIN64
761 #define IntPtrSub LongLongSub
762 #define LongPtrSub LongLongSub
763 #define SizeTMult ULongLongMult
764 #define SIZETMult ULongLongMult
765 #else
766 #endif
767
768 #endif // _NTINTSAFE_H_INCLUDED_
769
770 #endif // !_INTSAFE_H_INCLUDED_