26 #include "llvm/ADT/APSInt.h" 27 #include "llvm/ADT/SmallVector.h" 30 using namespace clang;
35 struct MallocOverflowCheck {
41 : mulop(m), variable(v), maxVal(
std::move(val)) {}
44 class MallocOverflowSecurityChecker :
public Checker<check::ASTCodeBody> {
49 void CheckMallocArgument(
53 void OutputPossibleOverflows(
62 return (op == BO_Mul) && (Val == 0);
65 void MallocOverflowSecurityChecker::CheckMallocArgument(
67 const Expr *TheArgument,
75 const Expr *e = TheArgument;
85 if (mulop ==
nullptr && opc == BO_Mul)
87 if (opc != BO_Mul && opc != BO_Add && opc != BO_Sub && opc != BO_Shl)
90 const Expr *lhs = binop->getLHS();
91 const Expr *rhs = binop->getRHS();
97 }
else if ((opc == BO_Add || opc == BO_Mul) &&
106 else if (isa<DeclRefExpr>(e) || isa<MemberExpr>(e))
112 if (mulop ==
nullptr)
121 PossibleMallocOverflows.push_back(MallocOverflowCheck(mulop, e, maxVal));
126 class CheckOverflowOps :
132 theVecType &toScanFor;
135 bool isIntZeroExpr(
const Expr *E)
const {
149 template <
typename T1>
150 void Erase(
const T1 *DR,
151 llvm::function_ref<
bool(
const MallocOverflowCheck &)> Pred) {
152 auto P = [DR, Pred](
const MallocOverflowCheck &Check) {
153 if (
const auto *CheckDR = dyn_cast<T1>(Check.variable))
154 return getDecl(CheckDR) == getDecl(DR) && Pred(Check);
157 toScanFor.erase(std::remove_if(toScanFor.begin(), toScanFor.end(),
P),
161 void CheckExpr(
const Expr *E_p) {
162 auto PredTrue = [](
const MallocOverflowCheck &) {
return true; };
164 if (
const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
165 Erase<DeclRefExpr>(DR, PredTrue);
166 else if (
const auto *ME = dyn_cast<MemberExpr>(E)) {
167 Erase<MemberExpr>(ME, PredTrue);
177 bool assignKnown =
false;
178 bool numeratorKnown =
false, denomKnown =
false;
192 if (BOp->getOpcode() == BO_Div) {
198 numeratorKnown =
true;
201 if (!assignKnown && !denomKnown)
203 auto denomExtVal = denomVal.getExtValue();
212 auto pred = [assignKnown, numeratorKnown,
213 denomExtVal](
const MallocOverflowCheck &Check) {
214 return assignKnown ||
215 (numeratorKnown && (denomExtVal >= Check.maxVal.getExtValue()));
218 if (
const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
219 Erase<DeclRefExpr>(DR, pred);
220 else if (
const auto *ME = dyn_cast<MemberExpr>(E))
221 Erase<MemberExpr>(ME, pred);
231 if (!isIntZeroExpr(lhs) && !isIntZeroExpr(rhs)) {
237 CheckAssignmentExpr(E);
244 return this->Visit(S->
getBody());
246 void VisitForStmt(
ForStmt *S) {
247 return this->Visit(S->
getBody());
249 void VisitDoStmt(
DoStmt *S) {
250 return this->Visit(S->
getBody());
255 toScanFor(v), Context(ctx)
267 void MallocOverflowSecurityChecker::OutputPossibleOverflows(
271 if (PossibleMallocOverflows.empty())
275 CheckOverflowOps c(PossibleMallocOverflows, BR.
getContext());
279 for (CheckOverflowOps::theVecType::iterator
280 i = PossibleMallocOverflows.begin(),
281 e = PossibleMallocOverflows.end();
286 "the computation of the size of the memory allocation may overflow",
289 i->mulop->getSourceRange());
293 void MallocOverflowSecurityChecker::checkASTCodeBody(
const Decl *D,
309 if (
const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) {
321 if (FnInfo->
isStr (
"malloc") || FnInfo->
isStr (
"_MALLOC")) {
322 if (TheCall->getNumArgs() == 1)
323 CheckMallocArgument(PossibleMallocOverflows, TheCall->getArg(0),
331 OutputPossibleOverflows(PossibleMallocOverflows, D, BR, mgr);
335 ento::registerMallocOverflowSecurityChecker(
CheckerManager &mgr) {
Represents a function declaration or definition.
EvaluatedExprVisitor - This class visits 'Expr *'s.
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Stmt * getBody() const
Get the body of the Declaration.
ElementList::iterator iterator
Decl - This represents one declaration (or definition), e.g.
bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer...
const char *const UnixAPI
static bool isAssignmentOp(Opcode Opc)
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
One of these records is kept for each identifier that is lexed.
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
ForStmt - This represents a 'for (init;cond;inc)' stmt.
ASTContext & getContext()
A builtin binary operation expression such as "x + y" or "x <= y".
CFGBlockListTy::iterator iterator
ASTContext & getASTContext() override
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
Represents a single basic block in a source-level CFG.
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx, SmallVectorImpl< PartialDiagnosticAt > *Diag=nullptr) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
Expr - This represents one expression.
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
CFG * getCFG(Decl const *D)
CHECKER * registerChecker(AT... Args)
Used to register checkers.
DoStmt - This represents a 'do/while' stmt.
BugReporter is a utility class for generating PathDiagnostics for analysis.
Dataflow Directional Tag Classes.
Expr * IgnoreParenImpCasts() LLVM_READONLY
IgnoreParenImpCasts - Ignore parentheses and implicit casts.
static bool EvaluatesToZero(APSInt &Val, BinaryOperatorKind op)
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Create the location for the operator of the binary expression.
SourceManager & getSourceManager()
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
WhileStmt - This represents a 'while' stmt.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
bool isEvaluatable(const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects) const
isEvaluatable - Call EvaluateAsRValue to see if this expression can be constant folded without side-e...
A reference to a declared variable, function, enum, etc.
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=None)
static bool isComparisonOp(Opcode Opc)