sanisizer
Sanitize sizes to avoid integer overflow
Loading...
Searching...
No Matches
arithmetic.hpp
Go to the documentation of this file.
1#ifndef SANISIZER_ARITHMETIC_HPP
2#define SANISIZER_ARITHMETIC_HPP
3
4#include <limits>
5#include <type_traits>
6#include <stdexcept>
7
8#include "attest.hpp"
9#include "utils.hpp"
10
16namespace sanisizer {
17
21template<typename Dest_, typename First_, typename Second_>
22constexpr bool needs_sum_check() {
23 constexpr Dest_ dest_maxed = std::numeric_limits<Dest_>::max();
24 constexpr auto first_maxed = get_max<First_>();
25 if constexpr(as_unsigned(first_maxed) > as_unsigned(dest_maxed)) {
26 return true;
27 } else {
28 constexpr Dest_ delta = dest_maxed - static_cast<Dest_>(first_maxed);
29 constexpr auto second_maxed = get_max<Second_>();
30 return as_unsigned(second_maxed) > as_unsigned(delta);
31 }
32}
33
34template<typename Dest_, typename First_, typename Second_>
35constexpr auto sum_protected(First_ first, Second_ second) {
37 const Dest_ first_val = get_value(first);
38
40 const Dest_ second_val = get_value(second);
41
42 if constexpr(needs_sum_check<Dest_, First_, Second_>()) {
43 static_assert(std::is_integral<Dest_>::value);
44 constexpr Dest_ dest_maxed = std::numeric_limits<Dest_>::max();
45 if (static_cast<Dest_>(dest_maxed - first_val) < second_val) {
46 throw std::overflow_error("overflow detected in sanisizer::sum");
47 }
48 return Attestation<Dest_, dest_maxed>(static_cast<Dest_>(first_val + second_val));
49
50 } else {
51 constexpr Dest_ maxsum = static_cast<Dest_>(get_max<First_>()) + static_cast<Dest_>(get_max<Second_>());
52 return Attestation<Dest_, maxsum>(static_cast<Dest_>(first_val + second_val));
53 }
54}
55
56template<typename Dest_, typename First_, typename Second_, typename ... Args_>
57constexpr auto sum_protected(First_ first, Second_ second, Args_... more) {
58 const auto subsum = sum_protected<Dest_>(first, second);
59 return sum_protected<Dest_>(subsum, more...);
60}
61
62template<typename Dest_, typename First_, typename Second_>
63constexpr Dest_ sum_unprotected(First_ first, Second_ second) {
64 static_assert(std::is_integral<Dest_>::value);
65 static_assert(std::is_integral<First_>::value);
66 static_assert(std::is_integral<Second_>::value);
67 return static_cast<Dest_>(first) + static_cast<Dest_>(second);
68}
69
70template<typename Dest_, typename First_, typename Second_, typename ... Args_>
71constexpr Dest_ sum_unprotected(First_ first, Second_ second, Args_... more) {
72 const auto subsum = sum_unprotected<Dest_>(first, second);
73 return sum_unprotected<Dest_>(subsum, more...);
74}
95template<typename Dest_, typename First_, typename ... Args_>
96constexpr Dest_ sum(First_ first, Args_... more) {
97 return get_value(sum_protected<Dest_>(first, more...));
98}
99
113template<typename Dest_, typename First_, typename ... Args_>
114constexpr Dest_ sum_unsafe(First_ first, Args_... more) {
115 return sum_unprotected<Dest_>(first, more...);
116}
117
121template<typename Dest_, typename First_, typename Second_>
122constexpr bool needs_product_check() {
123 constexpr Dest_ dest_maxed = std::numeric_limits<Dest_>::max();
124 constexpr auto first_maxed = get_max<First_>();
125 if constexpr(as_unsigned(first_maxed) > as_unsigned(dest_maxed)) {
126 return true;
127 } else if constexpr(first_maxed == 0) {
128 return false;
129 } else {
130 constexpr auto ratio = dest_maxed / first_maxed;
131 constexpr auto second_maxed = get_max<Second_>();
132 return as_unsigned(second_maxed) > as_unsigned(ratio);
133 }
134}
135
136template<typename Dest_, typename First_, typename Second_>
137constexpr auto product_protected(First_ first, Second_ second) {
139 const Dest_ first_val = get_value(first);
140
141 check_overflow<Dest_>(second);
142 const Dest_ second_val = get_value(second);
143
144 if constexpr(needs_product_check<Dest_, First_, Second_>()) {
145 static_assert(std::is_integral<Dest_>::value);
146 constexpr Dest_ dest_maxed = std::numeric_limits<Dest_>::max();
147 if (first_val && static_cast<Dest_>(dest_maxed / first_val) < second_val) {
148 throw std::overflow_error("overflow detected in sanisizer::product");
149 }
150 return Attestation<Dest_, dest_maxed>(static_cast<Dest_>(first_val * second_val));
151
152 } else {
153 constexpr Dest_ maxprod = static_cast<Dest_>(get_max<First_>()) * static_cast<Dest_>(get_max<Second_>());
154 return Attestation<Dest_, maxprod>(static_cast<Dest_>(first_val * second_val));
155 }
156}
157
158template<typename Dest_, typename First_, typename Second_, typename ... Args_>
159constexpr auto product_protected(First_ first, Second_ second, Args_... more) {
160 const auto subproduct = product_protected<Dest_>(first, second);
161 return product_protected<Dest_>(subproduct, more...);
162}
163
164template<typename Dest_, typename First_, typename Second_>
165constexpr Dest_ product_unprotected(First_ left, Second_ right) {
166 static_assert(std::is_integral<Dest_>::value);
167 static_assert(std::is_integral<First_>::value);
168 static_assert(std::is_integral<Second_>::value);
169 return static_cast<Dest_>(left) * static_cast<Dest_>(right);
170}
171
172template<typename Dest_, typename First_, typename Second_, typename ... Args_>
173constexpr Dest_ product_unprotected(First_ left, Second_ right, Args_... more) {
174 const auto subproduct = product_unprotected<Dest_>(left, right);
175 return product_unprotected<Dest_>(subproduct, more...);
176}
201template<typename Dest_, typename First_, typename ... Args_>
202constexpr Dest_ product(First_ first, Args_... more) {
203 return get_value(product_protected<Dest_>(first, more...));
204}
205
218template<typename Dest_, typename First_, typename ... Args_>
219constexpr Dest_ product_unsafe(First_ first, Args_... more) {
220 return product_unprotected<Dest_>(first, more...);
221}
222
223}
224
225#endif
Create compile-time attestations.
Sanitize sizes to avoid integer overflow.
Definition arithmetic.hpp:16
constexpr auto get_value(Value_ x)
Definition attest.hpp:105
constexpr bool check_overflow(Value_ x)
Definition attest.hpp:178
constexpr Dest_ sum_unsafe(First_ first, Args_... more)
Definition arithmetic.hpp:114
constexpr auto get_max()
Definition attest.hpp:119
constexpr Dest_ product_unsafe(First_ first, Args_... more)
Definition arithmetic.hpp:219
constexpr Dest_ product(First_ first, Args_... more)
Definition arithmetic.hpp:202
constexpr Dest_ sum(First_ first, Args_... more)
Definition arithmetic.hpp:96
Attest to additional compile-time properties of an integer.
Definition attest.hpp:30