21
21
#include " clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
22
22
#include " clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
23
23
#include " clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
24
+ #include " clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
24
25
#include " clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
26
+ #include " clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
25
27
26
28
using namespace clang ;
27
29
using namespace ento ;
28
30
29
31
namespace {
30
32
33
+ QualType getOverflowBuiltinResultType (const CallEvent &Call) {
34
+ assert (Call.getNumArgs () == 3 );
35
+
36
+ return Call.getArgExpr (2 )->getType ()->getPointeeType ();
37
+ }
38
+
39
+ QualType getOverflowBuiltinResultType (const CallEvent &Call, CheckerContext &C,
40
+ unsigned BI) {
41
+ assert (Call.getNumArgs () == 3 );
42
+
43
+ ASTContext &Ast = C.getASTContext ();
44
+
45
+ switch (BI) {
46
+ case Builtin::BI__builtin_smul_overflow:
47
+ case Builtin::BI__builtin_ssub_overflow:
48
+ case Builtin::BI__builtin_sadd_overflow:
49
+ return Ast.IntTy ;
50
+ case Builtin::BI__builtin_smull_overflow:
51
+ case Builtin::BI__builtin_ssubl_overflow:
52
+ case Builtin::BI__builtin_saddl_overflow:
53
+ return Ast.LongTy ;
54
+ case Builtin::BI__builtin_smulll_overflow:
55
+ case Builtin::BI__builtin_ssubll_overflow:
56
+ case Builtin::BI__builtin_saddll_overflow:
57
+ return Ast.LongLongTy ;
58
+ case Builtin::BI__builtin_umul_overflow:
59
+ case Builtin::BI__builtin_usub_overflow:
60
+ case Builtin::BI__builtin_uadd_overflow:
61
+ return Ast.UnsignedIntTy ;
62
+ case Builtin::BI__builtin_umull_overflow:
63
+ case Builtin::BI__builtin_usubl_overflow:
64
+ case Builtin::BI__builtin_uaddl_overflow:
65
+ return Ast.UnsignedLongTy ;
66
+ case Builtin::BI__builtin_umulll_overflow:
67
+ case Builtin::BI__builtin_usubll_overflow:
68
+ case Builtin::BI__builtin_uaddll_overflow:
69
+ return Ast.UnsignedLongLongTy ;
70
+ case Builtin::BI__builtin_mul_overflow:
71
+ case Builtin::BI__builtin_sub_overflow:
72
+ case Builtin::BI__builtin_add_overflow:
73
+ return getOverflowBuiltinResultType (Call);
74
+ default :
75
+ assert (false && " Unknown overflow builtin" );
76
+ }
77
+ }
78
+
31
79
class BuiltinFunctionChecker : public Checker <eval::Call> {
32
80
public:
33
81
bool evalCall (const CallEvent &Call, CheckerContext &C) const ;
82
+ void HandleOverflowBuiltin (const CallEvent &Call, CheckerContext &C,
83
+ BinaryOperator::Opcode Op,
84
+ QualType ResultType) const ;
34
85
35
86
private:
36
87
// From: clang/include/clang/Basic/Builtins.def
@@ -50,6 +101,44 @@ class BuiltinFunctionChecker : public Checker<eval::Call> {
50
101
51
102
} // namespace
52
103
104
+ void BuiltinFunctionChecker::HandleOverflowBuiltin (const CallEvent &Call,
105
+ CheckerContext &C,
106
+ BinaryOperator::Opcode Op,
107
+ QualType ResultType) const {
108
+ // All __builtin_*_overflow functions take 3 argumets.
109
+ assert (Call.getNumArgs () == 3 );
110
+
111
+ ProgramStateRef State = C.getState ();
112
+ SValBuilder &SVB = C.getSValBuilder ();
113
+ const Expr *CE = Call.getOriginExpr ();
114
+
115
+ SVal Arg1 = Call.getArgSVal (0 );
116
+ SVal Arg2 = Call.getArgSVal (1 );
117
+
118
+ SVal RetVal = SVB.evalBinOp (State, Op, Arg1, Arg2, ResultType);
119
+
120
+ // TODO: Handle overflows with values that known to overflow. Like INT_MAX + 1
121
+ // should not produce state for non-overflow case and threat it as
122
+ // unreachable.
123
+
124
+ // Handle non-overflow case.
125
+ {
126
+ ProgramStateRef StateSuccess =
127
+ State->BindExpr (CE, C.getLocationContext (), SVB.makeTruthVal (false ));
128
+
129
+ if (auto L = Call.getArgSVal (2 ).getAs <Loc>())
130
+ StateSuccess = StateSuccess->bindLoc (*L, RetVal, C.getLocationContext ());
131
+
132
+ C.addTransition (StateSuccess);
133
+ }
134
+
135
+ // Handle overflow case.
136
+ {
137
+ C.addTransition (
138
+ State->BindExpr (CE, C.getLocationContext (), SVB.makeTruthVal (true )));
139
+ }
140
+ }
141
+
53
142
bool BuiltinFunctionChecker::isBuiltinLikeFunction (
54
143
const CallEvent &Call) const {
55
144
const auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(Call.getDecl ());
@@ -82,10 +171,41 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
82
171
return true ;
83
172
}
84
173
85
- switch (FD->getBuiltinID ()) {
174
+ unsigned BI = FD->getBuiltinID ();
175
+
176
+ switch (BI) {
86
177
default :
87
178
return false ;
88
-
179
+ case Builtin::BI__builtin_mul_overflow:
180
+ case Builtin::BI__builtin_smul_overflow:
181
+ case Builtin::BI__builtin_smull_overflow:
182
+ case Builtin::BI__builtin_smulll_overflow:
183
+ case Builtin::BI__builtin_umul_overflow:
184
+ case Builtin::BI__builtin_umull_overflow:
185
+ case Builtin::BI__builtin_umulll_overflow:
186
+ HandleOverflowBuiltin (Call, C, BO_Mul,
187
+ getOverflowBuiltinResultType (Call, C, BI));
188
+ return true ;
189
+ case Builtin::BI__builtin_sub_overflow:
190
+ case Builtin::BI__builtin_ssub_overflow:
191
+ case Builtin::BI__builtin_ssubl_overflow:
192
+ case Builtin::BI__builtin_ssubll_overflow:
193
+ case Builtin::BI__builtin_usub_overflow:
194
+ case Builtin::BI__builtin_usubl_overflow:
195
+ case Builtin::BI__builtin_usubll_overflow:
196
+ HandleOverflowBuiltin (Call, C, BO_Sub,
197
+ getOverflowBuiltinResultType (Call, C, BI));
198
+ return true ;
199
+ case Builtin::BI__builtin_add_overflow:
200
+ case Builtin::BI__builtin_sadd_overflow:
201
+ case Builtin::BI__builtin_saddl_overflow:
202
+ case Builtin::BI__builtin_saddll_overflow:
203
+ case Builtin::BI__builtin_uadd_overflow:
204
+ case Builtin::BI__builtin_uaddl_overflow:
205
+ case Builtin::BI__builtin_uaddll_overflow:
206
+ HandleOverflowBuiltin (Call, C, BO_Add,
207
+ getOverflowBuiltinResultType (Call, C, BI));
208
+ return true ;
89
209
case Builtin::BI__builtin_assume:
90
210
case Builtin::BI__assume: {
91
211
assert (Call.getNumArgs () > 0 );
0 commit comments