1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 #ifndef INCLUDE_integer_h__
8 #define INCLUDE_integer_h__
9 
10 /** @return true if p fits into the range of a size_t */
git__is_sizet(int64_t p)11 GIT_INLINE(int) git__is_sizet(int64_t p)
12 {
13 	size_t r = (size_t)p;
14 	return p == (int64_t)r;
15 }
16 
17 /** @return true if p fits into the range of an ssize_t */
git__is_ssizet(size_t p)18 GIT_INLINE(int) git__is_ssizet(size_t p)
19 {
20 	ssize_t r = (ssize_t)p;
21 	return p == (size_t)r;
22 }
23 
24 /** @return true if p fits into the range of a uint16_t */
git__is_uint16(size_t p)25 GIT_INLINE(int) git__is_uint16(size_t p)
26 {
27 	uint16_t r = (uint16_t)p;
28 	return p == (size_t)r;
29 }
30 
31 /** @return true if p fits into the range of a uint32_t */
git__is_uint32(size_t p)32 GIT_INLINE(int) git__is_uint32(size_t p)
33 {
34 	uint32_t r = (uint32_t)p;
35 	return p == (size_t)r;
36 }
37 
38 /** @return true if p fits into the range of an unsigned long */
git__is_ulong(int64_t p)39 GIT_INLINE(int) git__is_ulong(int64_t p)
40 {
41 	unsigned long r = (unsigned long)p;
42 	return p == (int64_t)r;
43 }
44 
45 /** @return true if p fits into the range of an int */
git__is_int(long long p)46 GIT_INLINE(int) git__is_int(long long p)
47 {
48 	int r = (int)p;
49 	return p == (long long)r;
50 }
51 
52 /* Use clang/gcc compiler intrinsics whenever possible */
53 #if (__has_builtin(__builtin_add_overflow) || \
54      (defined(__GNUC__) && (__GNUC__ >= 5)))
55 
56 # if (SIZE_MAX == UINT_MAX)
57 #  define git__add_sizet_overflow(out, one, two) \
58      __builtin_uadd_overflow(one, two, out)
59 #  define git__multiply_sizet_overflow(out, one, two) \
60      __builtin_umul_overflow(one, two, out)
61 # elif (SIZE_MAX == ULONG_MAX)
62 #  define git__add_sizet_overflow(out, one, two) \
63      __builtin_uaddl_overflow(one, two, out)
64 #  define git__multiply_sizet_overflow(out, one, two) \
65      __builtin_umull_overflow(one, two, out)
66 # elif (SIZE_MAX == ULLONG_MAX)
67 #  define git__add_sizet_overflow(out, one, two) \
68      __builtin_uaddll_overflow(one, two, out)
69 #  define git__multiply_sizet_overflow(out, one, two) \
70      __builtin_umulll_overflow(one, two, out)
71 # else
72 #  error compiler has add with overflow intrinsics but SIZE_MAX is unknown
73 # endif
74 
75 # define git__add_int_overflow(out, one, two) \
76     __builtin_sadd_overflow(one, two, out)
77 # define git__sub_int_overflow(out, one, two) \
78     __builtin_ssub_overflow(one, two, out)
79 
80 /* Use Microsoft's safe integer handling functions where available */
81 #elif defined(_MSC_VER)
82 
83 # define ENABLE_INTSAFE_SIGNED_FUNCTIONS
84 # include <intsafe.h>
85 
86 # define git__add_sizet_overflow(out, one, two) \
87     (SizeTAdd(one, two, out) != S_OK)
88 # define git__multiply_sizet_overflow(out, one, two) \
89     (SizeTMult(one, two, out) != S_OK)
90 #define git__add_int_overflow(out, one, two) \
91     (IntAdd(one, two, out) != S_OK)
92 #define git__sub_int_overflow(out, one, two) \
93     (IntSub(one, two, out) != S_OK)
94 
95 #else
96 
97 /**
98  * Sets `one + two` into `out`, unless the arithmetic would overflow.
99  * @return false if the result fits in a `size_t`, true on overflow.
100  */
git__add_sizet_overflow(size_t * out,size_t one,size_t two)101 GIT_INLINE(bool) git__add_sizet_overflow(size_t *out, size_t one, size_t two)
102 {
103 	if (SIZE_MAX - one < two)
104 		return true;
105 	*out = one + two;
106 	return false;
107 }
108 
109 /**
110  * Sets `one * two` into `out`, unless the arithmetic would overflow.
111  * @return false if the result fits in a `size_t`, true on overflow.
112  */
git__multiply_sizet_overflow(size_t * out,size_t one,size_t two)113 GIT_INLINE(bool) git__multiply_sizet_overflow(size_t *out, size_t one, size_t two)
114 {
115 	if (one && SIZE_MAX / one < two)
116 		return true;
117 	*out = one * two;
118 	return false;
119 }
120 
git__add_int_overflow(int * out,int one,int two)121 GIT_INLINE(bool) git__add_int_overflow(int *out, int one, int two)
122 {
123 	if ((two > 0 && one > (INT_MAX - two)) ||
124 	    (two < 0 && one < (INT_MIN - two)))
125 		return true;
126 	*out = one + two;
127 	return false;
128 }
129 
git__sub_int_overflow(int * out,int one,int two)130 GIT_INLINE(bool) git__sub_int_overflow(int *out, int one, int two)
131 {
132 	if ((two > 0 && one < (INT_MIN + two)) ||
133 	    (two < 0 && one > (INT_MAX + two)))
134 		return true;
135 	*out = one - two;
136 	return false;
137 }
138 
139 #endif
140 
141 #endif
142