62 assert(
Call.getNumArgs() == 3);
64 return Call.getArgExpr(2)->getType()->getPointeeType();
70 assert(
Call.getNumArgs() == 3);
75 case Builtin::BI__builtin_smul_overflow:
76 case Builtin::BI__builtin_ssub_overflow:
77 case Builtin::BI__builtin_sadd_overflow:
79 case Builtin::BI__builtin_smull_overflow:
80 case Builtin::BI__builtin_ssubl_overflow:
81 case Builtin::BI__builtin_saddl_overflow:
83 case Builtin::BI__builtin_smulll_overflow:
84 case Builtin::BI__builtin_ssubll_overflow:
85 case Builtin::BI__builtin_saddll_overflow:
87 case Builtin::BI__builtin_umul_overflow:
88 case Builtin::BI__builtin_usub_overflow:
89 case Builtin::BI__builtin_uadd_overflow:
91 case Builtin::BI__builtin_umull_overflow:
92 case Builtin::BI__builtin_usubl_overflow:
93 case Builtin::BI__builtin_uaddl_overflow:
95 case Builtin::BI__builtin_umulll_overflow:
96 case Builtin::BI__builtin_usubll_overflow:
97 case Builtin::BI__builtin_uaddll_overflow:
99 case Builtin::BI__builtin_mul_overflow:
100 case Builtin::BI__builtin_sub_overflow:
101 case Builtin::BI__builtin_add_overflow:
102 return getOverflowBuiltinResultType(
Call);
104 assert(
false &&
"Unknown overflow builtin");
109class BuiltinFunctionChecker :
public Checker<eval::Call> {
111 bool evalCall(
const CallEvent &
Call, CheckerContext &
C)
const;
112 void handleOverflowBuiltin(
const CallEvent &
Call, CheckerContext &
C,
114 QualType ResultType)
const;
115 const NoteTag *createBuiltinOverflowNoteTag(CheckerContext &
C,
116 bool BothFeasible, SVal Arg1,
117 SVal Arg2, SVal
Result)
const;
120 const CallEvent &
Call,
122 bool IsOverflow)
const;
123 std::pair<bool, bool> checkOverflow(CheckerContext &
C, SVal RetVal,
129 const CallDescriptionSet BuiltinLikeStdFunctions{
130 {CDM::SimpleFunc, {
"std",
"addressof"}},
131 {CDM::SimpleFunc, {
"std",
"__addressof"}},
132 {CDM::SimpleFunc, {
"std",
"as_const"}},
133 {CDM::SimpleFunc, {
"std",
"forward"}},
134 {CDM::SimpleFunc, {
"std",
"forward_like"}},
135 {CDM::SimpleFunc, {
"std",
"move"}},
136 {CDM::SimpleFunc, {
"std",
"move_if_noexcept"}},
139 bool isBuiltinLikeFunction(
const CallEvent &
Call)
const;
144const NoteTag *BuiltinFunctionChecker::createBuiltinOverflowNoteTag(
146 return C.getNoteTag([
Result, Arg1, Arg2, overflow](PathSensitiveBugReport &BR,
147 llvm::raw_ostream &
OS) {
156 OS <<
"Assuming overflow";
158 OS <<
"Assuming no overflow";
163BuiltinFunctionChecker::checkOverflow(CheckerContext &
C, SVal RetVal,
164 QualType Res)
const {
168 unsigned BitWidth =
C.getASTContext().getIntWidth(Res);
171 SValBuilder &SVB =
C.getSValBuilder();
174 auto MinValType = llvm::APSInt::getMinValue(BitWidth, IsUnsigned);
175 auto MaxValType = llvm::APSInt::getMaxValue(BitWidth, IsUnsigned);
176 nonloc::ConcreteInt MinVal{VF.getValue(MinValType)};
177 nonloc::ConcreteInt MaxVal{VF.getValue(MaxValType)};
180 SVal IsLeMax = SVB.
evalBinOp(State, BO_LE, RetVal, MaxVal, Res);
181 SVal IsGeMin = SVB.
evalBinOp(State, BO_GE, RetVal, MinVal, Res);
183 auto [MayNotOverflow, MayOverflow] =
184 State->assume(IsLeMax.
castAs<DefinedOrUnknownSVal>());
185 auto [MayNotUnderflow, MayUnderflow] =
186 State->assume(IsGeMin.
castAs<DefinedOrUnknownSVal>());
188 return {MayOverflow || MayUnderflow, MayNotOverflow && MayNotUnderflow};
193 SVal RetVal,
bool IsOverflow)
const {
194 SValBuilder &SVB =
C.getSValBuilder();
195 SVal Arg1 =
Call.getArgSVal(0);
196 SVal Arg2 =
Call.getArgSVal(1);
197 auto BoolTy =
C.getASTContext().BoolTy;
200 State->BindExpr(
Call.getOriginExpr(),
C.getStackFrame(),
203 if (
auto L =
Call.getArgSVal(2).getAs<Loc>()) {
204 NewState = NewState->bindLoc(*L, RetVal,
C.getStackFrame());
214void BuiltinFunctionChecker::handleOverflowBuiltin(
const CallEvent &
Call,
217 QualType ResultType)
const {
219 assert(
Call.getNumArgs() == 3);
222 SValBuilder &SVB =
C.getSValBuilder();
224 SVal Arg1 =
Call.getArgSVal(0);
225 SVal Arg2 =
Call.getArgSVal(1);
226 QualType Arg1Ty =
Call.getArgExpr(0)->getType();
227 QualType Arg2Ty =
Call.getArgExpr(1)->getType();
229 QualType SufficientlyWideTy =
230 getSufficientTypeForOverflowOp(
C, Op, Arg1Ty, Arg2Ty);
231 assert(!SufficientlyWideTy.
isNull());
233 SVal RetValMax = SVB.
evalBinOp(State, Op, Arg1, Arg2, SufficientlyWideTy);
234 SVal RetVal = SVB.
evalBinOp(State, Op, Arg1, Arg2, ResultType);
236 auto [Overflow, NotOverflow] = checkOverflow(
C, RetValMax, ResultType);
240 initStateAftetBuiltinOverflow(
C, State,
Call, RetVal,
false);
242 C.addTransition(NewState, createBuiltinOverflowNoteTag(
243 C,
false, Arg1, Arg2, RetVal));
247 auto NewState = initStateAftetBuiltinOverflow(
C, State,
Call, RetVal,
true);
249 C.addTransition(NewState, createBuiltinOverflowNoteTag(
C,
true,
250 Arg1, Arg2, RetVal));
254bool BuiltinFunctionChecker::isBuiltinLikeFunction(
255 const CallEvent &
Call)
const {
256 const auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
257 if (!FD || FD->getNumParams() != 1)
260 if (QualType RetTy = FD->getReturnType();
261 !RetTy->isPointerType() && !RetTy->isReferenceType())
264 if (QualType ParmTy = FD->getParamDecl(0)->getType();
265 !ParmTy->isPointerType() && !ParmTy->isReferenceType())
271bool BuiltinFunctionChecker::evalCall(
const CallEvent &
Call,
272 CheckerContext &
C)
const {
274 const auto *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
278 const StackFrame *SF =
C.getStackFrame();
279 const Expr *CE =
Call.getOriginExpr();
281 if (isBuiltinLikeFunction(
Call)) {
282 C.addTransition(state->BindExpr(CE, SF,
Call.getArgSVal(0)));
286 unsigned BI = FD->getBuiltinID();
291 case Builtin::BI__builtin_mul_overflow:
292 case Builtin::BI__builtin_smul_overflow:
293 case Builtin::BI__builtin_smull_overflow:
294 case Builtin::BI__builtin_smulll_overflow:
295 case Builtin::BI__builtin_umul_overflow:
296 case Builtin::BI__builtin_umull_overflow:
297 case Builtin::BI__builtin_umulll_overflow:
298 handleOverflowBuiltin(
Call,
C, BO_Mul,
299 getOverflowBuiltinResultType(
Call,
C, BI));
301 case Builtin::BI__builtin_sub_overflow:
302 case Builtin::BI__builtin_ssub_overflow:
303 case Builtin::BI__builtin_ssubl_overflow:
304 case Builtin::BI__builtin_ssubll_overflow:
305 case Builtin::BI__builtin_usub_overflow:
306 case Builtin::BI__builtin_usubl_overflow:
307 case Builtin::BI__builtin_usubll_overflow:
308 handleOverflowBuiltin(
Call,
C, BO_Sub,
309 getOverflowBuiltinResultType(
Call,
C, BI));
311 case Builtin::BI__builtin_add_overflow:
312 case Builtin::BI__builtin_sadd_overflow:
313 case Builtin::BI__builtin_saddl_overflow:
314 case Builtin::BI__builtin_saddll_overflow:
315 case Builtin::BI__builtin_uadd_overflow:
316 case Builtin::BI__builtin_uaddl_overflow:
317 case Builtin::BI__builtin_uaddll_overflow:
318 handleOverflowBuiltin(
Call,
C, BO_Add,
319 getOverflowBuiltinResultType(
Call,
C, BI));
321 case Builtin::BI__builtin_unpredictable:
322 case Builtin::BI__builtin_expect:
323 case Builtin::BI__builtin_expect_with_probability:
324 case Builtin::BI__builtin_assume_aligned:
325 case Builtin::BI__builtin_addressof:
326 case Builtin::BI__builtin_function_start: {
332 assert (
Call.getNumArgs() > 0);
333 SVal Arg =
Call.getArgSVal(0);
334 C.addTransition(state->BindExpr(CE, SF, Arg));
338 case Builtin::BI__builtin_dynamic_object_size:
339 case Builtin::BI__builtin_object_size:
340 case Builtin::BI__builtin_constant_p: {
343 SValBuilder &SVB =
C.getSValBuilder();
344 SVal
V = UnknownVal();
345 Expr::EvalResult EVResult;
354 if (FD->getBuiltinID() == Builtin::BI__builtin_constant_p) {
362 C.addTransition(state->BindExpr(CE, SF,
V));
368void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) {
372bool ento::shouldRegisterBuiltinFunctionChecker(
const CheckerManager &mgr) {
Defines enum values for all the target-independent builtin functions.
Result
Implement __builtin_bit_cast and related operations.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
unsigned getIntWidth(QualType T) const
CanQualType UnsignedLongTy
CanQualType UnsignedIntTy
CanQualType UnsignedLongLongTy
QualType getBitIntType(bool Unsigned, unsigned NumBits) const
Return a bit-precise integer type with the specified signedness and bit count.
BinaryOperatorKind Opcode
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
@ SE_NoSideEffects
Strictly evaluate the expression.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
void apply(llvm::APSInt &Value) const
Convert a given APSInt, in place, to match this type.
APSIntType getAPSIntType(QualType T) const
Returns the type of the APSInt used to store values of the given QualType.
bool contains(const CallEvent &Call) const
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
The tag upon which the TagVisitor reacts.
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
bool isInteresting(SymbolRef sym) const
BasicValueFactory & getBasicValueFactory()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
nonloc::ConcreteInt makeTruthVal(bool b, QualType type)
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
bool isTainted(ProgramStateRef State, const Expr *E, const StackFrame *SF, TaintTagType Kind=TaintTagGeneric)
Check if the expression has a tainted value in the given state.
ProgramStateRef addTaint(ProgramStateRef State, const Expr *E, const StackFrame *SF, TaintTagType Kind=TaintTagGeneric)
Create a new state in which the value of the expression is marked as tainted.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
Top level wrappers for InstallAPI frontend operations.
@ Result
The result type of a method or function.
APValue Val
Val - This is the value the expression can be folded to.