25 #include "llvm/ADT/APSInt.h"
26 #include "llvm/ADT/SmallVector.h"
29 using namespace clang;
34 struct MallocOverflowCheck {
42 : call(call), mulop(m), variable(
v), maxVal(
std::move(val)) {}
45 class MallocOverflowSecurityChecker :
public Checker<check::ASTCodeBody> {
47 void checkASTCodeBody(
const Decl *D, AnalysisManager &mgr,
48 BugReporter &BR)
const;
50 void CheckMallocArgument(
54 void OutputPossibleOverflows(
56 const Decl *D, BugReporter &BR, AnalysisManager &mgr)
const;
63 return (op == BO_Mul) && (Val == 0);
66 void MallocOverflowSecurityChecker::CheckMallocArgument(
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) &&
105 }
else if (isa<DeclRefExpr, MemberExpr>(e))
111 if (mulop ==
nullptr)
118 PossibleMallocOverflows.push_back(
119 MallocOverflowCheck(TheCall, mulop, e, maxVal));
124 class CheckOverflowOps :
130 theVecType &toScanFor;
133 bool isIntZeroExpr(
const Expr *E)
const {
138 return Result.Val.getInt() == 0;
147 template <
typename T1>
148 void Erase(
const T1 *DR,
149 llvm::function_ref<
bool(
const MallocOverflowCheck &)> Pred) {
150 auto P = [DR, Pred](
const MallocOverflowCheck &Check) {
151 if (
const auto *CheckDR = dyn_cast<T1>(Check.variable))
152 return getDecl(CheckDR) == getDecl(DR) && Pred(Check);
155 llvm::erase_if(toScanFor,
P);
158 void CheckExpr(
const Expr *E_p) {
160 const auto PrecedesMalloc = [E,
this](
const MallocOverflowCheck &
c) {
164 if (
const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
165 Erase<DeclRefExpr>(DR, PrecedesMalloc);
166 else if (
const auto *ME = dyn_cast<MemberExpr>(E)) {
167 Erase<MemberExpr>(ME, PrecedesMalloc);
177 bool assignKnown =
false;
178 bool numeratorKnown =
false, denomKnown =
false;
192 if (BOp->getOpcode() == BO_Div) {
196 denomVal = Result.Val.getInt();
201 numeratorKnown =
true;
204 if (!assignKnown && !denomKnown)
206 auto denomExtVal = denomVal.getExtValue();
215 auto pred = [assignKnown, numeratorKnown,
216 denomExtVal](
const MallocOverflowCheck &Check) {
217 return assignKnown ||
218 (numeratorKnown && (denomExtVal >= Check.maxVal.getExtValue()));
221 if (
const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
222 Erase<DeclRefExpr>(DR, pred);
223 else if (
const auto *ME = dyn_cast<MemberExpr>(E))
224 Erase<MemberExpr>(ME, pred);
234 if (!isIntZeroExpr(lhs) && !isIntZeroExpr(rhs)) {
240 CheckAssignmentExpr(E);
247 return this->Visit(S->getBody());
249 void VisitForStmt(
ForStmt *S) {
250 return this->Visit(S->getBody());
252 void VisitDoStmt(
DoStmt *S) {
253 return this->Visit(S->getBody());
258 toScanFor(
v), Context(ctx)
270 void MallocOverflowSecurityChecker::OutputPossibleOverflows(
272 const Decl *D, BugReporter &BR, AnalysisManager &mgr)
const {
274 if (PossibleMallocOverflows.empty())
278 CheckOverflowOps
c(PossibleMallocOverflows, BR.getContext());
279 c.Visit(mgr.getAnalysisDeclContext(D)->getBody());
282 for (CheckOverflowOps::theVecType::iterator
283 i = PossibleMallocOverflows.begin(),
284 e = PossibleMallocOverflows.end();
289 "the computation of the size of the memory allocation may overflow",
291 BR.getSourceManager()),
292 i->mulop->getSourceRange());
296 void MallocOverflowSecurityChecker::checkASTCodeBody(
const Decl *D,
297 AnalysisManager &mgr,
298 BugReporter &BR)
const {
300 CFG *cfg = mgr.getCFG(D);
312 if (
const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) {
324 if (FnInfo->
isStr (
"malloc") || FnInfo->
isStr (
"_MALLOC")) {
326 CheckMallocArgument(PossibleMallocOverflows, TheCall,
327 mgr.getASTContext());
334 OutputPossibleOverflows(PossibleMallocOverflows, D, BR, mgr);
337 void ento::registerMallocOverflowSecurityChecker(CheckerManager &mgr) {
338 mgr.registerChecker<MallocOverflowSecurityChecker>();
341 bool ento::shouldRegisterMallocOverflowSecurityChecker(
const CheckerManager &mgr) {