1 | #ifndef AWS_COMMON_MATH_INL |
2 | #define AWS_COMMON_MATH_INL |
3 | |
4 | /* |
5 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
6 | * |
7 | * Licensed under the Apache License, Version 2.0 (the "License"). |
8 | * You may not use this file except in compliance with the License. |
9 | * A copy of the License is located at |
10 | * |
11 | * http://aws.amazon.com/apache2.0 |
12 | * |
13 | * or in the "license" file accompanying this file. This file is distributed |
14 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
15 | * express or implied. See the License for the specific language governing |
16 | * permissions and limitations under the License. |
17 | */ |
18 | |
19 | #include <aws/common/common.h> |
20 | #include <aws/common/config.h> |
21 | #include <aws/common/math.h> |
22 | |
23 | #include <limits.h> |
24 | #include <stdlib.h> |
25 | |
26 | AWS_EXTERN_C_BEGIN |
27 | |
28 | #if defined(AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS) && (defined(__clang__) || !defined(__cplusplus)) |
29 | /* |
30 | * GCC and clang have these super convenient overflow checking builtins... |
31 | * but (in the case of GCC) they're only available when building C source. |
32 | * We'll fall back to one of the other inlinable variants (or a non-inlined version) |
33 | * if we are building this header on G++. |
34 | */ |
35 | # include <aws/common/math.gcc_overflow.inl> |
36 | #elif defined(__x86_64__) && defined(AWS_HAVE_GCC_INLINE_ASM) |
37 | # include <aws/common/math.gcc_x64_asm.inl> |
38 | #elif defined(AWS_HAVE_MSVC_MULX) |
39 | # include <aws/common/math.msvc.inl> |
40 | #elif defined(CBMC) |
41 | # include <aws/common/math.cbmc.inl> |
42 | #else |
43 | # ifndef AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS |
44 | /* Fall back to the pure-C implementations */ |
45 | # include <aws/common/math.fallback.inl> |
46 | # else |
47 | /* |
48 | * We got here because we are building in C++ mode but we only support overflow extensions |
49 | * in C mode. Because the fallback is _slow_ (involving a division), we'd prefer to make a |
50 | * non-inline call to the fast C intrinsics. |
51 | */ |
52 | # endif /* AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS */ |
53 | #endif /* defined(AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS) && (defined(__clang__) || !defined(__cplusplus)) */ |
54 | |
55 | #if _MSC_VER |
56 | # pragma warning(push) |
57 | # pragma warning(disable : 4127) /*Disable "conditional expression is constant" */ |
58 | #endif /* _MSC_VER */ |
59 | |
60 | /** |
61 | * Multiplies a * b. If the result overflows, returns SIZE_MAX. |
62 | */ |
63 | AWS_STATIC_IMPL size_t aws_mul_size_saturating(size_t a, size_t b) { |
64 | #if SIZE_BITS == 32 |
65 | return (size_t)aws_mul_u32_saturating(a, b); |
66 | #elif SIZE_BITS == 64 |
67 | return (size_t)aws_mul_u64_saturating(a, b); |
68 | #else |
69 | # error "Target not supported" |
70 | #endif |
71 | } |
72 | |
73 | /** |
74 | * Multiplies a * b and returns the result in *r. If the result |
75 | * overflows, returns AWS_OP_ERR; otherwise returns AWS_OP_SUCCESS. |
76 | */ |
77 | AWS_STATIC_IMPL int aws_mul_size_checked(size_t a, size_t b, size_t *r) { |
78 | #if SIZE_BITS == 32 |
79 | return aws_mul_u32_checked(a, b, (uint32_t *)r); |
80 | #elif SIZE_BITS == 64 |
81 | return aws_mul_u64_checked(a, b, (uint64_t *)r); |
82 | #else |
83 | # error "Target not supported" |
84 | #endif |
85 | } |
86 | |
87 | /** |
88 | * Adds a + b. If the result overflows returns SIZE_MAX. |
89 | */ |
90 | AWS_STATIC_IMPL size_t aws_add_size_saturating(size_t a, size_t b) { |
91 | #if SIZE_BITS == 32 |
92 | return (size_t)aws_add_u32_saturating(a, b); |
93 | #elif SIZE_BITS == 64 |
94 | return (size_t)aws_add_u64_saturating(a, b); |
95 | #else |
96 | # error "Target not supported" |
97 | #endif |
98 | } |
99 | |
100 | /** |
101 | * Adds a + b and returns the result in *r. If the result |
102 | * overflows, returns AWS_OP_ERR; otherwise returns AWS_OP_SUCCESS. |
103 | */ |
104 | AWS_STATIC_IMPL int aws_add_size_checked(size_t a, size_t b, size_t *r) { |
105 | #if SIZE_BITS == 32 |
106 | return aws_add_u32_checked(a, b, (uint32_t *)r); |
107 | #elif SIZE_BITS == 64 |
108 | return aws_add_u64_checked(a, b, (uint64_t *)r); |
109 | #else |
110 | # error "Target not supported" |
111 | #endif |
112 | } |
113 | |
114 | /** |
115 | * Function to check if x is power of 2 |
116 | */ |
117 | AWS_STATIC_IMPL bool aws_is_power_of_two(const size_t x) { |
118 | /* First x in the below expression is for the case when x is 0 */ |
119 | return x && (!(x & (x - 1))); |
120 | } |
121 | |
122 | /** |
123 | * Function to find the smallest result that is power of 2 >= n. Returns AWS_OP_ERR if this cannot |
124 | * be done without overflow |
125 | */ |
126 | AWS_STATIC_IMPL int aws_round_up_to_power_of_two(size_t n, size_t *result) { |
127 | if (n == 0) { |
128 | *result = 1; |
129 | return AWS_OP_SUCCESS; |
130 | } |
131 | if (n > SIZE_MAX_POWER_OF_TWO) { |
132 | return aws_raise_error(AWS_ERROR_OVERFLOW_DETECTED); |
133 | } |
134 | |
135 | n--; |
136 | n |= n >> 1; |
137 | n |= n >> 2; |
138 | n |= n >> 4; |
139 | n |= n >> 8; |
140 | n |= n >> 16; |
141 | #if SIZE_BITS == 64 |
142 | n |= n >> 32; |
143 | #endif |
144 | n++; |
145 | *result = n; |
146 | return AWS_OP_SUCCESS; |
147 | } |
148 | |
149 | #if _MSC_VER |
150 | # pragma warning(pop) |
151 | #endif /* _MSC_VER */ |
152 | |
153 | AWS_EXTERN_C_END |
154 | |
155 | #endif /* AWS_COMMON_MATH_INL */ |
156 | |