llvm.org GIT mirror llvm / ba86f98
Change checked arithmetic functions API to return Optional Returning optional is much safer. The previous API had potential to cause use of undefined variables, if the value passed by pointer was accidentally read afterwards. Differential Revision: https://reviews.llvm.org/D48137 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@334634 91177308-0d34-0410-b5e6-96231b3b80d8 George Karpenkov 1 year, 4 months ago
2 changed file(s) with 50 addition(s) and 67 deletion(s). Raw diff Collapse all Expand all
1515 #define LLVM_SUPPORT_CHECKEDARITHMETIC_H
1616
1717 #include "llvm/ADT/APInt.h"
18 #include "llvm/ADT/Optional.h"
1819
1920 #include
2021
2122 namespace {
2223
2324 /// Utility function to apply a given method of \c APInt \p F to \p LHS and
24 /// \p RHS, and write the output into \p Res.
25 /// \return Whether the operation overflows.
25 /// \p RHS.
26 /// \return Empty optional if the operation overflows, or result otherwise.
2627 template
2728 typename std::enable_if::value && sizeof(T) * 8 <= 64,
28 bool>::type
29 checkedOp(T LHS, T RHS, F Op, T *Res = nullptr, bool Signed = true) {
29 llvm::Optional>::type
30 checkedOp(T LHS, T RHS, F Op, bool Signed = true) {
3031 llvm::APInt ALHS(/*BitSize=*/sizeof(T) * 8, LHS, Signed);
3132 llvm::APInt ARHS(/*BitSize=*/sizeof(T) * 8, RHS, Signed);
3233 bool Overflow;
3334 llvm::APInt Out = (ALHS.*Op)(ARHS, Overflow);
34 if (Res)
35 *Res = Signed ? Out.getSExtValue() : Out.getZExtValue();
36 return Overflow;
35 if (Overflow)
36 return llvm::None;
37 return Signed ? Out.getSExtValue() : Out.getZExtValue();
3738 }
3839 }
3940
4041 namespace llvm {
4142
42 /// Add two signed integers \p LHS and \p RHS, write into \p Res if non-null.
43 /// Does not guarantee saturating arithmetic.
44 /// \return Whether the result overflows.
43 /// Add two signed integers \p LHS and \p RHS, return wrapped result if
44 /// available.
4545 template
46 typename std::enable_if::value, bool>::type
47 checkedAdd(T LHS, T RHS, T *Res = nullptr) {
48 return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov, Res);
46 typename std::enable_if::value, llvm::Optional>::type
47 checkedAdd(T LHS, T RHS) {
48 return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov);
4949 }
5050
51 /// Multiply two signed integers \p LHS and \p RHS, write into \p Res if
52 /// non-null.
53 /// Does not guarantee saturating arithmetic.
54 /// \return Whether the result overflows.
51 /// Multiply two signed integers \p LHS and \p RHS, return wrapped result
52 /// if available.
5553 template
56 typename std::enable_if::value, bool>::type
57 checkedMul(T LHS, T RHS, T *Res = nullptr) {
58 return checkedOp(LHS, RHS, &llvm::APInt::smul_ov, Res);
54 typename std::enable_if::value, llvm::Optional>::type
55 checkedMul(T LHS, T RHS) {
56 return checkedOp(LHS, RHS, &llvm::APInt::smul_ov);
5957 }
6058
61 /// Add two unsigned integers \p LHS and \p RHS, write into \p Res if non-null.
62 /// Does not guarantee saturating arithmetic.
63 /// \return Whether the result overflows.
59 /// Add two unsigned integers \p LHS and \p RHS, return wrapped result
60 /// if available.
6461 template
65 typename std::enable_if::value, bool>::type
66 checkedAddUnsigned(T LHS, T RHS, T *Res = nullptr) {
67 return checkedOp(LHS, RHS, &llvm::APInt::uadd_ov, Res, /*Signed=*/false);
62 typename std::enable_if::value, llvm::Optional>::type
63 checkedAddUnsigned(T LHS, T RHS) {
64 return checkedOp(LHS, RHS, &llvm::APInt::uadd_ov, /*Signed=*/false);
6865 }
6966
70 /// Multiply two unsigned integers \p LHS and \p RHS, write into \p Res if
71 /// non-null.
72 /// Does not guarantee saturating arithmetic.
73 /// \return Whether the result overflows.
67 /// Multiply two unsigned integers \p LHS and \p RHS, return wrapped result
68 /// if available.
7469 template
75 typename std::enable_if::value, bool>::type
76 checkedMulUnsigned(T LHS, T RHS, T *Res = nullptr) {
77 return checkedOp(LHS, RHS, &llvm::APInt::umul_ov, Res, /*Signed=*/false);
70 typename std::enable_if::value, llvm::Optional>::type
71 checkedMulUnsigned(T LHS, T RHS) {
72 return checkedOp(LHS, RHS, &llvm::APInt::umul_ov, /*Signed=*/false);
7873 }
7974
8075 } // End llvm namespace
55 namespace {
66
77 TEST(CheckedArithmetic, CheckedAdd) {
8 int64_t Out;
98 const int64_t Max = std::numeric_limits::max();
109 const int64_t Min = std::numeric_limits::min();
11 EXPECT_EQ(checkedAdd(Max, Max, &Out), true);
12 EXPECT_EQ(checkedAdd(Min, -1, &Out), true);
13 EXPECT_EQ(checkedAdd(Max, 1, &Out), true);
14 EXPECT_EQ(checkedAdd(10, 1, &Out), false);
15 EXPECT_EQ(Out, 11);
10 EXPECT_EQ(checkedAdd(Max, Max), None);
11 EXPECT_EQ(checkedAdd(Min, -1), None);
12 EXPECT_EQ(checkedAdd(Max, 1), None);
13 EXPECT_EQ(checkedAdd(10, 1), Optional(11));
1614 }
1715
1816 TEST(CheckedArithmetic, CheckedAddSmall) {
19 int16_t Out;
2017 const int16_t Max = std::numeric_limits::max();
2118 const int16_t Min = std::numeric_limits::min();
22 EXPECT_EQ(checkedAdd(Max, Max, &Out), true);
23 EXPECT_EQ(checkedAdd(Min, -1, &Out), true);
24 EXPECT_EQ(checkedAdd(Max, 1, &Out), true);
25 EXPECT_EQ(checkedAdd(10, 1, &Out), false);
26 EXPECT_EQ(Out, 11);
19 EXPECT_EQ(checkedAdd(Max, Max), None);
20 EXPECT_EQ(checkedAdd(Min, -1), None);
21 EXPECT_EQ(checkedAdd(Max, 1), None);
22 EXPECT_EQ(checkedAdd(10, 1), Optional(11));
2723 }
2824
2925 TEST(CheckedArithmetic, CheckedMul) {
30 int64_t Out;
3126 const int64_t Max = std::numeric_limits::max();
3227 const int64_t Min = std::numeric_limits::min();
33 EXPECT_EQ(checkedMul(Max, 2, &Out), true);
34 EXPECT_EQ(checkedMul(Max, Max, &Out), true);
35 EXPECT_EQ(checkedMul(Min, 2, &Out), true);
36 EXPECT_EQ(checkedMul(10, 2, &Out), false);
37 EXPECT_EQ(Out, 20);
28 EXPECT_EQ(checkedMul(Max, 2), None);
29 EXPECT_EQ(checkedMul(Max, Max), None);
30 EXPECT_EQ(checkedMul(Min, 2), None);
31 EXPECT_EQ(checkedMul(10, 2), Optional(20));
3832 }
3933
4034 TEST(CheckedArithmetic, CheckedMulSmall) {
41 int16_t Out;
4235 const int16_t Max = std::numeric_limits::max();
4336 const int16_t Min = std::numeric_limits::min();
44 EXPECT_EQ(checkedMul(Max, 2, &Out), true);
45 EXPECT_EQ(checkedMul(Max, Max, &Out), true);
46 EXPECT_EQ(checkedMul(Min, 2, &Out), true);
47 EXPECT_EQ(checkedMul(10, 2, &Out), false);
48 EXPECT_EQ(Out, 20);
37 EXPECT_EQ(checkedMul(Max, 2), None);
38 EXPECT_EQ(checkedMul(Max, Max), None);
39 EXPECT_EQ(checkedMul(Min, 2), None);
40 EXPECT_EQ(checkedMul(10, 2), Optional(20));
4941 }
5042
5143 TEST(CheckedArithmetic, CheckedAddUnsigned) {
52 uint64_t Out;
5344 const uint64_t Max = std::numeric_limits::max();
54 EXPECT_EQ(checkedAddUnsigned(Max, Max, &Out), true);
55 EXPECT_EQ(checkedAddUnsigned(Max, 1, &Out), true);
56 EXPECT_EQ(checkedAddUnsigned(10, 1, &Out), false);
57 EXPECT_EQ(Out, uint64_t(11));
45 EXPECT_EQ(checkedAddUnsigned(Max, Max), None);
46 EXPECT_EQ(checkedAddUnsigned(Max, 1), None);
47 EXPECT_EQ(checkedAddUnsigned(10, 1), Optional(11));
5848 }
5949
6050 TEST(CheckedArithmetic, CheckedMulUnsigned) {
61 uint64_t Out;
6251 const uint64_t Max = std::numeric_limits::max();
63 EXPECT_EQ(checkedMulUnsigned(Max, 2, &Out), true);
64 EXPECT_EQ(checkedMulUnsigned(Max, Max, &Out), true);
65 EXPECT_EQ(checkedMulUnsigned(10, 2, &Out), false);
66 EXPECT_EQ(Out, uint64_t(20));
52 EXPECT_EQ(checkedMulUnsigned(Max, 2), llvm::None);
53 EXPECT_EQ(checkedMulUnsigned(Max, Max), llvm::None);
54 EXPECT_EQ(checkedMulUnsigned(10, 2), Optional(20));
6755 }
6856
6957