47 assert(
Call.getNumArgs() == 3);
49 return Call.getArgExpr(2)->getType()->getPointeeType();
55 assert(
Call.getNumArgs() == 3);
60 case Builtin::BI__builtin_smul_overflow:
61 case Builtin::BI__builtin_ssub_overflow:
62 case Builtin::BI__builtin_sadd_overflow:
64 case Builtin::BI__builtin_smull_overflow:
65 case Builtin::BI__builtin_ssubl_overflow:
66 case Builtin::BI__builtin_saddl_overflow:
68 case Builtin::BI__builtin_smulll_overflow:
69 case Builtin::BI__builtin_ssubll_overflow:
70 case Builtin::BI__builtin_saddll_overflow:
72 case Builtin::BI__builtin_umul_overflow:
73 case Builtin::BI__builtin_usub_overflow:
74 case Builtin::BI__builtin_uadd_overflow:
76 case Builtin::BI__builtin_umull_overflow:
77 case Builtin::BI__builtin_usubl_overflow:
78 case Builtin::BI__builtin_uaddl_overflow:
80 case Builtin::BI__builtin_umulll_overflow:
81 case Builtin::BI__builtin_usubll_overflow:
82 case Builtin::BI__builtin_uaddll_overflow:
84 case Builtin::BI__builtin_mul_overflow:
85 case Builtin::BI__builtin_sub_overflow:
86 case Builtin::BI__builtin_add_overflow:
87 return getOverflowBuiltinResultType(
Call);
89 assert(
false &&
"Unknown overflow builtin");
94class BuiltinFunctionChecker :
public Checker<eval::Call> {
101 bool BothFeasible,
SVal Arg1,
111 {CDM::SimpleFunc, {
"std",
"addressof"}},
112 {CDM::SimpleFunc, {
"std",
"__addressof"}},
113 {CDM::SimpleFunc, {
"std",
"as_const"}},
114 {CDM::SimpleFunc, {
"std",
"forward"}},
115 {CDM::SimpleFunc, {
"std",
"forward_like"}},
116 {CDM::SimpleFunc, {
"std",
"move"}},
117 {CDM::SimpleFunc, {
"std",
"move_if_noexcept"}},
125const NoteTag *BuiltinFunctionChecker::createBuiltinNoOverflowNoteTag(
128 return C.getNoteTag([Result, Arg1, Arg2, BothFeasible](
138 OS <<
"Assuming no overflow";
143BuiltinFunctionChecker::createBuiltinOverflowNoteTag(
CheckerContext &
C)
const {
145 llvm::raw_ostream &OS) { OS <<
"Assuming overflow"; },
155 unsigned BitWidth =
C.getASTContext().getIntWidth(Res);
161 auto MinValType = llvm::APSInt::getMinValue(BitWidth, IsUnsigned);
162 auto MaxValType = llvm::APSInt::getMaxValue(BitWidth, IsUnsigned);
167 SVal IsLeMax = SVB.
evalBinOp(State, BO_LE, RetVal, MaxVal, Res);
168 SVal IsGeMin = SVB.
evalBinOp(State, BO_GE, RetVal, MinVal, Res);
170 auto [MayNotOverflow, MayOverflow] =
172 auto [MayNotUnderflow, MayUnderflow] =
175 return {MayOverflow || MayUnderflow, MayNotOverflow && MayNotUnderflow};
178void BuiltinFunctionChecker::handleOverflowBuiltin(
const CallEvent &
Call,
183 assert(
Call.getNumArgs() == 3);
187 const Expr *CE =
Call.getOriginExpr();
188 auto BoolTy =
C.getASTContext().BoolTy;
194 getSufficientTypeForOverflowOp(
C, ResultType));
195 SVal RetVal = SVB.
evalBinOp(State, Op, Arg1, Arg2, ResultType);
197 auto [Overflow, NotOverflow] = checkOverflow(
C, RetValMax, ResultType);
200 CE,
C.getLocationContext(), SVB.
makeTruthVal(
false, BoolTy));
202 if (
auto L =
Call.getArgSVal(2).getAs<
Loc>()) {
204 StateNoOverflow->bindLoc(*L, RetVal,
C.getLocationContext());
208 StateNoOverflow =
addTaint(StateNoOverflow, *L);
213 createBuiltinNoOverflowNoteTag(
214 C, NotOverflow && Overflow, Arg1, Arg2, RetVal));
218 C.addTransition(State->BindExpr(CE,
C.getLocationContext(),
220 createBuiltinOverflowNoteTag(
C));
224bool BuiltinFunctionChecker::isBuiltinLikeFunction(
226 const auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
227 if (!FD || FD->getNumParams() != 1)
230 if (
QualType RetTy = FD->getReturnType();
234 if (
QualType ParmTy = FD->getParamDecl(0)->getType();
238 return BuiltinLikeStdFunctions.contains(
Call);
244 const auto *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
249 const Expr *CE =
Call.getOriginExpr();
251 if (isBuiltinLikeFunction(
Call)) {
252 C.addTransition(state->BindExpr(CE, LCtx,
Call.getArgSVal(0)));
256 unsigned BI = FD->getBuiltinID();
261 case Builtin::BI__builtin_mul_overflow:
262 case Builtin::BI__builtin_smul_overflow:
263 case Builtin::BI__builtin_smull_overflow:
264 case Builtin::BI__builtin_smulll_overflow:
265 case Builtin::BI__builtin_umul_overflow:
266 case Builtin::BI__builtin_umull_overflow:
267 case Builtin::BI__builtin_umulll_overflow:
268 handleOverflowBuiltin(
Call,
C, BO_Mul,
269 getOverflowBuiltinResultType(
Call,
C, BI));
271 case Builtin::BI__builtin_sub_overflow:
272 case Builtin::BI__builtin_ssub_overflow:
273 case Builtin::BI__builtin_ssubl_overflow:
274 case Builtin::BI__builtin_ssubll_overflow:
275 case Builtin::BI__builtin_usub_overflow:
276 case Builtin::BI__builtin_usubl_overflow:
277 case Builtin::BI__builtin_usubll_overflow:
278 handleOverflowBuiltin(
Call,
C, BO_Sub,
279 getOverflowBuiltinResultType(
Call,
C, BI));
281 case Builtin::BI__builtin_add_overflow:
282 case Builtin::BI__builtin_sadd_overflow:
283 case Builtin::BI__builtin_saddl_overflow:
284 case Builtin::BI__builtin_saddll_overflow:
285 case Builtin::BI__builtin_uadd_overflow:
286 case Builtin::BI__builtin_uaddl_overflow:
287 case Builtin::BI__builtin_uaddll_overflow:
288 handleOverflowBuiltin(
Call,
C, BO_Add,
289 getOverflowBuiltinResultType(
Call,
C, BI));
291 case Builtin::BI__builtin_assume:
292 case Builtin::BI__assume: {
293 assert (
Call.getNumArgs() > 0);
302 C.generateSink(
C.getState(),
C.getPredecessor());
306 C.addTransition(state);
310 case Builtin::BI__builtin_unpredictable:
311 case Builtin::BI__builtin_expect:
312 case Builtin::BI__builtin_expect_with_probability:
313 case Builtin::BI__builtin_assume_aligned:
314 case Builtin::BI__builtin_addressof:
315 case Builtin::BI__builtin_function_start: {
321 assert (
Call.getNumArgs() > 0);
323 C.addTransition(state->BindExpr(CE, LCtx, Arg));
327 case Builtin::BI__builtin_dynamic_object_size:
328 case Builtin::BI__builtin_object_size:
329 case Builtin::BI__builtin_constant_p: {
337 llvm::APSInt Result = EVResult.
Val.
getInt();
343 if (FD->getBuiltinID() == Builtin::BI__builtin_constant_p) {
351 C.addTransition(state->BindExpr(CE, LCtx,
V));
361bool 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
QualType getIntTypeForBitwidth(unsigned DestWidth, unsigned Signed) const
getIntTypeForBitwidth - sets integer QualTy according to specified details: bitwidth,...
CanQualType UnsignedLongTy
CanQualType UnsignedIntTy
CanQualType UnsignedLongLongTy
This represents one expression.
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.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
A (possibly-)qualified type.
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
bool isPointerType() const
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.
An immutable set of CallDescriptions.
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
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.
Value representing integer constant.
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.
The JSON file list parser is used to communicate input to InstallAPI.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
const FunctionProtoType * T
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.