36 assert(
T->isIntegerType());
40 return ACtx.
getBitIntType(
T->isUnsignedIntegerType(), BitWidth * 2);
45 assert(
Call.getNumArgs() == 3);
47 return Call.getArgExpr(2)->getType()->getPointeeType();
53 assert(
Call.getNumArgs() == 3);
58 case Builtin::BI__builtin_smul_overflow:
59 case Builtin::BI__builtin_ssub_overflow:
60 case Builtin::BI__builtin_sadd_overflow:
62 case Builtin::BI__builtin_smull_overflow:
63 case Builtin::BI__builtin_ssubl_overflow:
64 case Builtin::BI__builtin_saddl_overflow:
66 case Builtin::BI__builtin_smulll_overflow:
67 case Builtin::BI__builtin_ssubll_overflow:
68 case Builtin::BI__builtin_saddll_overflow:
70 case Builtin::BI__builtin_umul_overflow:
71 case Builtin::BI__builtin_usub_overflow:
72 case Builtin::BI__builtin_uadd_overflow:
74 case Builtin::BI__builtin_umull_overflow:
75 case Builtin::BI__builtin_usubl_overflow:
76 case Builtin::BI__builtin_uaddl_overflow:
78 case Builtin::BI__builtin_umulll_overflow:
79 case Builtin::BI__builtin_usubll_overflow:
80 case Builtin::BI__builtin_uaddll_overflow:
82 case Builtin::BI__builtin_mul_overflow:
83 case Builtin::BI__builtin_sub_overflow:
84 case Builtin::BI__builtin_add_overflow:
85 return getOverflowBuiltinResultType(
Call);
87 assert(
false &&
"Unknown overflow builtin");
92class BuiltinFunctionChecker :
public Checker<eval::Call> {
94 bool evalCall(
const CallEvent &
Call, CheckerContext &
C)
const;
95 void handleOverflowBuiltin(
const CallEvent &
Call, CheckerContext &
C,
97 QualType ResultType)
const;
98 const NoteTag *createBuiltinOverflowNoteTag(CheckerContext &
C,
99 bool BothFeasible, SVal Arg1,
100 SVal Arg2, SVal
Result)
const;
103 const CallEvent &
Call,
105 bool IsOverflow)
const;
106 std::pair<bool, bool> checkOverflow(CheckerContext &
C, SVal RetVal,
112 const CallDescriptionSet BuiltinLikeStdFunctions{
113 {CDM::SimpleFunc, {
"std",
"addressof"}},
114 {CDM::SimpleFunc, {
"std",
"__addressof"}},
115 {CDM::SimpleFunc, {
"std",
"as_const"}},
116 {CDM::SimpleFunc, {
"std",
"forward"}},
117 {CDM::SimpleFunc, {
"std",
"forward_like"}},
118 {CDM::SimpleFunc, {
"std",
"move"}},
119 {CDM::SimpleFunc, {
"std",
"move_if_noexcept"}},
122 bool isBuiltinLikeFunction(
const CallEvent &
Call)
const;
127const NoteTag *BuiltinFunctionChecker::createBuiltinOverflowNoteTag(
129 return C.getNoteTag([
Result, Arg1, Arg2, overflow](PathSensitiveBugReport &BR,
130 llvm::raw_ostream &
OS) {
139 OS <<
"Assuming overflow";
141 OS <<
"Assuming no overflow";
146BuiltinFunctionChecker::checkOverflow(CheckerContext &
C, SVal RetVal,
147 QualType Res)
const {
151 unsigned BitWidth =
C.getASTContext().getIntWidth(Res);
154 SValBuilder &SVB =
C.getSValBuilder();
157 auto MinValType = llvm::APSInt::getMinValue(BitWidth, IsUnsigned);
158 auto MaxValType = llvm::APSInt::getMaxValue(BitWidth, IsUnsigned);
159 nonloc::ConcreteInt MinVal{VF.getValue(MinValType)};
160 nonloc::ConcreteInt MaxVal{VF.getValue(MaxValType)};
163 SVal IsLeMax = SVB.
evalBinOp(State, BO_LE, RetVal, MaxVal, Res);
164 SVal IsGeMin = SVB.
evalBinOp(State, BO_GE, RetVal, MinVal, Res);
166 auto [MayNotOverflow, MayOverflow] =
167 State->assume(IsLeMax.
castAs<DefinedOrUnknownSVal>());
168 auto [MayNotUnderflow, MayUnderflow] =
169 State->assume(IsGeMin.
castAs<DefinedOrUnknownSVal>());
171 return {MayOverflow || MayUnderflow, MayNotOverflow && MayNotUnderflow};
176 SVal RetVal,
bool IsOverflow)
const {
177 SValBuilder &SVB =
C.getSValBuilder();
178 SVal Arg1 =
Call.getArgSVal(0);
179 SVal Arg2 =
Call.getArgSVal(1);
180 auto BoolTy =
C.getASTContext().BoolTy;
183 State->BindExpr(
Call.getOriginExpr(),
C.getLocationContext(),
186 if (
auto L =
Call.getArgSVal(2).getAs<Loc>()) {
187 NewState = NewState->bindLoc(*L, RetVal,
C.getLocationContext());
197void BuiltinFunctionChecker::handleOverflowBuiltin(
const CallEvent &
Call,
200 QualType ResultType)
const {
202 assert(
Call.getNumArgs() == 3);
205 SValBuilder &SVB =
C.getSValBuilder();
207 SVal Arg1 =
Call.getArgSVal(0);
208 SVal Arg2 =
Call.getArgSVal(1);
210 QualType SufficientlyWideTy = getSufficientTypeForOverflowOp(
C, ResultType);
211 assert(!SufficientlyWideTy.
isNull());
213 SVal RetValMax = SVB.
evalBinOp(State, Op, Arg1, Arg2, SufficientlyWideTy);
214 SVal RetVal = SVB.
evalBinOp(State, Op, Arg1, Arg2, ResultType);
216 auto [Overflow, NotOverflow] = checkOverflow(
C, RetValMax, ResultType);
220 initStateAftetBuiltinOverflow(
C, State,
Call, RetVal,
false);
222 C.addTransition(NewState, createBuiltinOverflowNoteTag(
223 C,
false, Arg1, Arg2, RetVal));
227 auto NewState = initStateAftetBuiltinOverflow(
C, State,
Call, RetVal,
true);
229 C.addTransition(NewState, createBuiltinOverflowNoteTag(
C,
true,
230 Arg1, Arg2, RetVal));
234bool BuiltinFunctionChecker::isBuiltinLikeFunction(
235 const CallEvent &
Call)
const {
236 const auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
237 if (!FD || FD->getNumParams() != 1)
240 if (QualType RetTy = FD->getReturnType();
241 !RetTy->isPointerType() && !RetTy->isReferenceType())
244 if (QualType ParmTy = FD->getParamDecl(0)->getType();
245 !ParmTy->isPointerType() && !ParmTy->isReferenceType())
251bool BuiltinFunctionChecker::evalCall(
const CallEvent &
Call,
252 CheckerContext &
C)
const {
254 const auto *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
258 const LocationContext *LCtx =
C.getLocationContext();
259 const Expr *CE =
Call.getOriginExpr();
261 if (isBuiltinLikeFunction(
Call)) {
262 C.addTransition(state->BindExpr(CE, LCtx,
Call.getArgSVal(0)));
266 unsigned BI = FD->getBuiltinID();
271 case Builtin::BI__builtin_mul_overflow:
272 case Builtin::BI__builtin_smul_overflow:
273 case Builtin::BI__builtin_smull_overflow:
274 case Builtin::BI__builtin_smulll_overflow:
275 case Builtin::BI__builtin_umul_overflow:
276 case Builtin::BI__builtin_umull_overflow:
277 case Builtin::BI__builtin_umulll_overflow:
278 handleOverflowBuiltin(
Call,
C, BO_Mul,
279 getOverflowBuiltinResultType(
Call,
C, BI));
281 case Builtin::BI__builtin_sub_overflow:
282 case Builtin::BI__builtin_ssub_overflow:
283 case Builtin::BI__builtin_ssubl_overflow:
284 case Builtin::BI__builtin_ssubll_overflow:
285 case Builtin::BI__builtin_usub_overflow:
286 case Builtin::BI__builtin_usubl_overflow:
287 case Builtin::BI__builtin_usubll_overflow:
288 handleOverflowBuiltin(
Call,
C, BO_Sub,
289 getOverflowBuiltinResultType(
Call,
C, BI));
291 case Builtin::BI__builtin_add_overflow:
292 case Builtin::BI__builtin_sadd_overflow:
293 case Builtin::BI__builtin_saddl_overflow:
294 case Builtin::BI__builtin_saddll_overflow:
295 case Builtin::BI__builtin_uadd_overflow:
296 case Builtin::BI__builtin_uaddl_overflow:
297 case Builtin::BI__builtin_uaddll_overflow:
298 handleOverflowBuiltin(
Call,
C, BO_Add,
299 getOverflowBuiltinResultType(
Call,
C, BI));
301 case Builtin::BI__builtin_unpredictable:
302 case Builtin::BI__builtin_expect:
303 case Builtin::BI__builtin_expect_with_probability:
304 case Builtin::BI__builtin_assume_aligned:
305 case Builtin::BI__builtin_addressof:
306 case Builtin::BI__builtin_function_start: {
312 assert (
Call.getNumArgs() > 0);
313 SVal Arg =
Call.getArgSVal(0);
314 C.addTransition(state->BindExpr(CE, LCtx, Arg));
318 case Builtin::BI__builtin_dynamic_object_size:
319 case Builtin::BI__builtin_object_size:
320 case Builtin::BI__builtin_constant_p: {
323 SValBuilder &SVB =
C.getSValBuilder();
324 SVal
V = UnknownVal();
325 Expr::EvalResult EVResult;
334 if (FD->getBuiltinID() == Builtin::BI__builtin_constant_p) {
342 C.addTransition(state->BindExpr(CE, LCtx,
V));
348void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) {
352bool ento::shouldRegisterBuiltinFunctionChecker(
const CheckerManager &mgr) {
Defines enum values for all the target-independent builtin functions.
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 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.
ProgramStateRef addTaint(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Create a new state in which the value of the statement is marked as tainted.
bool isTainted(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Check if the statement has a tainted value in the given state.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
const FunctionProtoType * T
APValue Val
Val - This is the value the expression can be folded to.