1*0b57cec5SDimitry Andric // MallocOverflowSecurityChecker.cpp - Check for malloc overflows -*- C++ -*-=// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This checker detects a common memory allocation security flaw. 10*0b57cec5SDimitry Andric // Suppose 'unsigned int n' comes from an untrusted source. If the 11*0b57cec5SDimitry Andric // code looks like 'malloc (n * 4)', and an attacker can make 'n' be 12*0b57cec5SDimitry Andric // say MAX_UINT/4+2, then instead of allocating the correct 'n' 4-byte 13*0b57cec5SDimitry Andric // elements, this will actually allocate only two because of overflow. 14*0b57cec5SDimitry Andric // Then when the rest of the program attempts to store values past the 15*0b57cec5SDimitry Andric // second element, these values will actually overwrite other items in 16*0b57cec5SDimitry Andric // the heap, probably allowing the attacker to execute arbitrary code. 17*0b57cec5SDimitry Andric // 18*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 19*0b57cec5SDimitry Andric 20*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 21*0b57cec5SDimitry Andric #include "clang/AST/EvaluatedExprVisitor.h" 22*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 23*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 24*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 25*0b57cec5SDimitry Andric #include "llvm/ADT/APSInt.h" 26*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 27*0b57cec5SDimitry Andric #include <utility> 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric using namespace clang; 30*0b57cec5SDimitry Andric using namespace ento; 31*0b57cec5SDimitry Andric using llvm::APSInt; 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric namespace { 34*0b57cec5SDimitry Andric struct MallocOverflowCheck { 35*0b57cec5SDimitry Andric const BinaryOperator *mulop; 36*0b57cec5SDimitry Andric const Expr *variable; 37*0b57cec5SDimitry Andric APSInt maxVal; 38*0b57cec5SDimitry Andric 39*0b57cec5SDimitry Andric MallocOverflowCheck(const BinaryOperator *m, const Expr *v, APSInt val) 40*0b57cec5SDimitry Andric : mulop(m), variable(v), maxVal(std::move(val)) {} 41*0b57cec5SDimitry Andric }; 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric class MallocOverflowSecurityChecker : public Checker<check::ASTCodeBody> { 44*0b57cec5SDimitry Andric public: 45*0b57cec5SDimitry Andric void checkASTCodeBody(const Decl *D, AnalysisManager &mgr, 46*0b57cec5SDimitry Andric BugReporter &BR) const; 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric void CheckMallocArgument( 49*0b57cec5SDimitry Andric SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows, 50*0b57cec5SDimitry Andric const Expr *TheArgument, ASTContext &Context) const; 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric void OutputPossibleOverflows( 53*0b57cec5SDimitry Andric SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows, 54*0b57cec5SDimitry Andric const Decl *D, BugReporter &BR, AnalysisManager &mgr) const; 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric }; 57*0b57cec5SDimitry Andric } // end anonymous namespace 58*0b57cec5SDimitry Andric 59*0b57cec5SDimitry Andric // Return true for computations which evaluate to zero: e.g., mult by 0. 60*0b57cec5SDimitry Andric static inline bool EvaluatesToZero(APSInt &Val, BinaryOperatorKind op) { 61*0b57cec5SDimitry Andric return (op == BO_Mul) && (Val == 0); 62*0b57cec5SDimitry Andric } 63*0b57cec5SDimitry Andric 64*0b57cec5SDimitry Andric void MallocOverflowSecurityChecker::CheckMallocArgument( 65*0b57cec5SDimitry Andric SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows, 66*0b57cec5SDimitry Andric const Expr *TheArgument, 67*0b57cec5SDimitry Andric ASTContext &Context) const { 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric /* Look for a linear combination with a single variable, and at least 70*0b57cec5SDimitry Andric one multiplication. 71*0b57cec5SDimitry Andric Reject anything that applies to the variable: an explicit cast, 72*0b57cec5SDimitry Andric conditional expression, an operation that could reduce the range 73*0b57cec5SDimitry Andric of the result, or anything too complicated :-). */ 74*0b57cec5SDimitry Andric const Expr *e = TheArgument; 75*0b57cec5SDimitry Andric const BinaryOperator * mulop = nullptr; 76*0b57cec5SDimitry Andric APSInt maxVal; 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric for (;;) { 79*0b57cec5SDimitry Andric maxVal = 0; 80*0b57cec5SDimitry Andric e = e->IgnoreParenImpCasts(); 81*0b57cec5SDimitry Andric if (const BinaryOperator *binop = dyn_cast<BinaryOperator>(e)) { 82*0b57cec5SDimitry Andric BinaryOperatorKind opc = binop->getOpcode(); 83*0b57cec5SDimitry Andric // TODO: ignore multiplications by 1, reject if multiplied by 0. 84*0b57cec5SDimitry Andric if (mulop == nullptr && opc == BO_Mul) 85*0b57cec5SDimitry Andric mulop = binop; 86*0b57cec5SDimitry Andric if (opc != BO_Mul && opc != BO_Add && opc != BO_Sub && opc != BO_Shl) 87*0b57cec5SDimitry Andric return; 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric const Expr *lhs = binop->getLHS(); 90*0b57cec5SDimitry Andric const Expr *rhs = binop->getRHS(); 91*0b57cec5SDimitry Andric if (rhs->isEvaluatable(Context)) { 92*0b57cec5SDimitry Andric e = lhs; 93*0b57cec5SDimitry Andric maxVal = rhs->EvaluateKnownConstInt(Context); 94*0b57cec5SDimitry Andric if (EvaluatesToZero(maxVal, opc)) 95*0b57cec5SDimitry Andric return; 96*0b57cec5SDimitry Andric } else if ((opc == BO_Add || opc == BO_Mul) && 97*0b57cec5SDimitry Andric lhs->isEvaluatable(Context)) { 98*0b57cec5SDimitry Andric maxVal = lhs->EvaluateKnownConstInt(Context); 99*0b57cec5SDimitry Andric if (EvaluatesToZero(maxVal, opc)) 100*0b57cec5SDimitry Andric return; 101*0b57cec5SDimitry Andric e = rhs; 102*0b57cec5SDimitry Andric } else 103*0b57cec5SDimitry Andric return; 104*0b57cec5SDimitry Andric } 105*0b57cec5SDimitry Andric else if (isa<DeclRefExpr>(e) || isa<MemberExpr>(e)) 106*0b57cec5SDimitry Andric break; 107*0b57cec5SDimitry Andric else 108*0b57cec5SDimitry Andric return; 109*0b57cec5SDimitry Andric } 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric if (mulop == nullptr) 112*0b57cec5SDimitry Andric return; 113*0b57cec5SDimitry Andric 114*0b57cec5SDimitry Andric // We've found the right structure of malloc argument, now save 115*0b57cec5SDimitry Andric // the data so when the body of the function is completely available 116*0b57cec5SDimitry Andric // we can check for comparisons. 117*0b57cec5SDimitry Andric 118*0b57cec5SDimitry Andric // TODO: Could push this into the innermost scope where 'e' is 119*0b57cec5SDimitry Andric // defined, rather than the whole function. 120*0b57cec5SDimitry Andric PossibleMallocOverflows.push_back(MallocOverflowCheck(mulop, e, maxVal)); 121*0b57cec5SDimitry Andric } 122*0b57cec5SDimitry Andric 123*0b57cec5SDimitry Andric namespace { 124*0b57cec5SDimitry Andric // A worker class for OutputPossibleOverflows. 125*0b57cec5SDimitry Andric class CheckOverflowOps : 126*0b57cec5SDimitry Andric public EvaluatedExprVisitor<CheckOverflowOps> { 127*0b57cec5SDimitry Andric public: 128*0b57cec5SDimitry Andric typedef SmallVectorImpl<MallocOverflowCheck> theVecType; 129*0b57cec5SDimitry Andric 130*0b57cec5SDimitry Andric private: 131*0b57cec5SDimitry Andric theVecType &toScanFor; 132*0b57cec5SDimitry Andric ASTContext &Context; 133*0b57cec5SDimitry Andric 134*0b57cec5SDimitry Andric bool isIntZeroExpr(const Expr *E) const { 135*0b57cec5SDimitry Andric if (!E->getType()->isIntegralOrEnumerationType()) 136*0b57cec5SDimitry Andric return false; 137*0b57cec5SDimitry Andric Expr::EvalResult Result; 138*0b57cec5SDimitry Andric if (E->EvaluateAsInt(Result, Context)) 139*0b57cec5SDimitry Andric return Result.Val.getInt() == 0; 140*0b57cec5SDimitry Andric return false; 141*0b57cec5SDimitry Andric } 142*0b57cec5SDimitry Andric 143*0b57cec5SDimitry Andric static const Decl *getDecl(const DeclRefExpr *DR) { return DR->getDecl(); } 144*0b57cec5SDimitry Andric static const Decl *getDecl(const MemberExpr *ME) { 145*0b57cec5SDimitry Andric return ME->getMemberDecl(); 146*0b57cec5SDimitry Andric } 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric template <typename T1> 149*0b57cec5SDimitry Andric void Erase(const T1 *DR, 150*0b57cec5SDimitry Andric llvm::function_ref<bool(const MallocOverflowCheck &)> Pred) { 151*0b57cec5SDimitry Andric auto P = [DR, Pred](const MallocOverflowCheck &Check) { 152*0b57cec5SDimitry Andric if (const auto *CheckDR = dyn_cast<T1>(Check.variable)) 153*0b57cec5SDimitry Andric return getDecl(CheckDR) == getDecl(DR) && Pred(Check); 154*0b57cec5SDimitry Andric return false; 155*0b57cec5SDimitry Andric }; 156*0b57cec5SDimitry Andric toScanFor.erase(std::remove_if(toScanFor.begin(), toScanFor.end(), P), 157*0b57cec5SDimitry Andric toScanFor.end()); 158*0b57cec5SDimitry Andric } 159*0b57cec5SDimitry Andric 160*0b57cec5SDimitry Andric void CheckExpr(const Expr *E_p) { 161*0b57cec5SDimitry Andric auto PredTrue = [](const MallocOverflowCheck &) { return true; }; 162*0b57cec5SDimitry Andric const Expr *E = E_p->IgnoreParenImpCasts(); 163*0b57cec5SDimitry Andric if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) 164*0b57cec5SDimitry Andric Erase<DeclRefExpr>(DR, PredTrue); 165*0b57cec5SDimitry Andric else if (const auto *ME = dyn_cast<MemberExpr>(E)) { 166*0b57cec5SDimitry Andric Erase<MemberExpr>(ME, PredTrue); 167*0b57cec5SDimitry Andric } 168*0b57cec5SDimitry Andric } 169*0b57cec5SDimitry Andric 170*0b57cec5SDimitry Andric // Check if the argument to malloc is assigned a value 171*0b57cec5SDimitry Andric // which cannot cause an overflow. 172*0b57cec5SDimitry Andric // e.g., malloc (mul * x) and, 173*0b57cec5SDimitry Andric // case 1: mul = <constant value> 174*0b57cec5SDimitry Andric // case 2: mul = a/b, where b > x 175*0b57cec5SDimitry Andric void CheckAssignmentExpr(BinaryOperator *AssignEx) { 176*0b57cec5SDimitry Andric bool assignKnown = false; 177*0b57cec5SDimitry Andric bool numeratorKnown = false, denomKnown = false; 178*0b57cec5SDimitry Andric APSInt denomVal; 179*0b57cec5SDimitry Andric denomVal = 0; 180*0b57cec5SDimitry Andric 181*0b57cec5SDimitry Andric // Erase if the multiplicand was assigned a constant value. 182*0b57cec5SDimitry Andric const Expr *rhs = AssignEx->getRHS(); 183*0b57cec5SDimitry Andric if (rhs->isEvaluatable(Context)) 184*0b57cec5SDimitry Andric assignKnown = true; 185*0b57cec5SDimitry Andric 186*0b57cec5SDimitry Andric // Discard the report if the multiplicand was assigned a value, 187*0b57cec5SDimitry Andric // that can never overflow after multiplication. e.g., the assignment 188*0b57cec5SDimitry Andric // is a division operator and the denominator is > other multiplicand. 189*0b57cec5SDimitry Andric const Expr *rhse = rhs->IgnoreParenImpCasts(); 190*0b57cec5SDimitry Andric if (const BinaryOperator *BOp = dyn_cast<BinaryOperator>(rhse)) { 191*0b57cec5SDimitry Andric if (BOp->getOpcode() == BO_Div) { 192*0b57cec5SDimitry Andric const Expr *denom = BOp->getRHS()->IgnoreParenImpCasts(); 193*0b57cec5SDimitry Andric Expr::EvalResult Result; 194*0b57cec5SDimitry Andric if (denom->EvaluateAsInt(Result, Context)) { 195*0b57cec5SDimitry Andric denomVal = Result.Val.getInt(); 196*0b57cec5SDimitry Andric denomKnown = true; 197*0b57cec5SDimitry Andric } 198*0b57cec5SDimitry Andric const Expr *numerator = BOp->getLHS()->IgnoreParenImpCasts(); 199*0b57cec5SDimitry Andric if (numerator->isEvaluatable(Context)) 200*0b57cec5SDimitry Andric numeratorKnown = true; 201*0b57cec5SDimitry Andric } 202*0b57cec5SDimitry Andric } 203*0b57cec5SDimitry Andric if (!assignKnown && !denomKnown) 204*0b57cec5SDimitry Andric return; 205*0b57cec5SDimitry Andric auto denomExtVal = denomVal.getExtValue(); 206*0b57cec5SDimitry Andric 207*0b57cec5SDimitry Andric // Ignore negative denominator. 208*0b57cec5SDimitry Andric if (denomExtVal < 0) 209*0b57cec5SDimitry Andric return; 210*0b57cec5SDimitry Andric 211*0b57cec5SDimitry Andric const Expr *lhs = AssignEx->getLHS(); 212*0b57cec5SDimitry Andric const Expr *E = lhs->IgnoreParenImpCasts(); 213*0b57cec5SDimitry Andric 214*0b57cec5SDimitry Andric auto pred = [assignKnown, numeratorKnown, 215*0b57cec5SDimitry Andric denomExtVal](const MallocOverflowCheck &Check) { 216*0b57cec5SDimitry Andric return assignKnown || 217*0b57cec5SDimitry Andric (numeratorKnown && (denomExtVal >= Check.maxVal.getExtValue())); 218*0b57cec5SDimitry Andric }; 219*0b57cec5SDimitry Andric 220*0b57cec5SDimitry Andric if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) 221*0b57cec5SDimitry Andric Erase<DeclRefExpr>(DR, pred); 222*0b57cec5SDimitry Andric else if (const auto *ME = dyn_cast<MemberExpr>(E)) 223*0b57cec5SDimitry Andric Erase<MemberExpr>(ME, pred); 224*0b57cec5SDimitry Andric } 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric public: 227*0b57cec5SDimitry Andric void VisitBinaryOperator(BinaryOperator *E) { 228*0b57cec5SDimitry Andric if (E->isComparisonOp()) { 229*0b57cec5SDimitry Andric const Expr * lhs = E->getLHS(); 230*0b57cec5SDimitry Andric const Expr * rhs = E->getRHS(); 231*0b57cec5SDimitry Andric // Ignore comparisons against zero, since they generally don't 232*0b57cec5SDimitry Andric // protect against an overflow. 233*0b57cec5SDimitry Andric if (!isIntZeroExpr(lhs) && !isIntZeroExpr(rhs)) { 234*0b57cec5SDimitry Andric CheckExpr(lhs); 235*0b57cec5SDimitry Andric CheckExpr(rhs); 236*0b57cec5SDimitry Andric } 237*0b57cec5SDimitry Andric } 238*0b57cec5SDimitry Andric if (E->isAssignmentOp()) 239*0b57cec5SDimitry Andric CheckAssignmentExpr(E); 240*0b57cec5SDimitry Andric EvaluatedExprVisitor<CheckOverflowOps>::VisitBinaryOperator(E); 241*0b57cec5SDimitry Andric } 242*0b57cec5SDimitry Andric 243*0b57cec5SDimitry Andric /* We specifically ignore loop conditions, because they're typically 244*0b57cec5SDimitry Andric not error checks. */ 245*0b57cec5SDimitry Andric void VisitWhileStmt(WhileStmt *S) { 246*0b57cec5SDimitry Andric return this->Visit(S->getBody()); 247*0b57cec5SDimitry Andric } 248*0b57cec5SDimitry Andric void VisitForStmt(ForStmt *S) { 249*0b57cec5SDimitry Andric return this->Visit(S->getBody()); 250*0b57cec5SDimitry Andric } 251*0b57cec5SDimitry Andric void VisitDoStmt(DoStmt *S) { 252*0b57cec5SDimitry Andric return this->Visit(S->getBody()); 253*0b57cec5SDimitry Andric } 254*0b57cec5SDimitry Andric 255*0b57cec5SDimitry Andric CheckOverflowOps(theVecType &v, ASTContext &ctx) 256*0b57cec5SDimitry Andric : EvaluatedExprVisitor<CheckOverflowOps>(ctx), 257*0b57cec5SDimitry Andric toScanFor(v), Context(ctx) 258*0b57cec5SDimitry Andric { } 259*0b57cec5SDimitry Andric }; 260*0b57cec5SDimitry Andric } 261*0b57cec5SDimitry Andric 262*0b57cec5SDimitry Andric // OutputPossibleOverflows - We've found a possible overflow earlier, 263*0b57cec5SDimitry Andric // now check whether Body might contain a comparison which might be 264*0b57cec5SDimitry Andric // preventing the overflow. 265*0b57cec5SDimitry Andric // This doesn't do flow analysis, range analysis, or points-to analysis; it's 266*0b57cec5SDimitry Andric // just a dumb "is there a comparison" scan. The aim here is to 267*0b57cec5SDimitry Andric // detect the most blatent cases of overflow and educate the 268*0b57cec5SDimitry Andric // programmer. 269*0b57cec5SDimitry Andric void MallocOverflowSecurityChecker::OutputPossibleOverflows( 270*0b57cec5SDimitry Andric SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows, 271*0b57cec5SDimitry Andric const Decl *D, BugReporter &BR, AnalysisManager &mgr) const { 272*0b57cec5SDimitry Andric // By far the most common case: nothing to check. 273*0b57cec5SDimitry Andric if (PossibleMallocOverflows.empty()) 274*0b57cec5SDimitry Andric return; 275*0b57cec5SDimitry Andric 276*0b57cec5SDimitry Andric // Delete any possible overflows which have a comparison. 277*0b57cec5SDimitry Andric CheckOverflowOps c(PossibleMallocOverflows, BR.getContext()); 278*0b57cec5SDimitry Andric c.Visit(mgr.getAnalysisDeclContext(D)->getBody()); 279*0b57cec5SDimitry Andric 280*0b57cec5SDimitry Andric // Output warnings for all overflows that are left. 281*0b57cec5SDimitry Andric for (CheckOverflowOps::theVecType::iterator 282*0b57cec5SDimitry Andric i = PossibleMallocOverflows.begin(), 283*0b57cec5SDimitry Andric e = PossibleMallocOverflows.end(); 284*0b57cec5SDimitry Andric i != e; 285*0b57cec5SDimitry Andric ++i) { 286*0b57cec5SDimitry Andric BR.EmitBasicReport( 287*0b57cec5SDimitry Andric D, this, "malloc() size overflow", categories::UnixAPI, 288*0b57cec5SDimitry Andric "the computation of the size of the memory allocation may overflow", 289*0b57cec5SDimitry Andric PathDiagnosticLocation::createOperatorLoc(i->mulop, 290*0b57cec5SDimitry Andric BR.getSourceManager()), 291*0b57cec5SDimitry Andric i->mulop->getSourceRange()); 292*0b57cec5SDimitry Andric } 293*0b57cec5SDimitry Andric } 294*0b57cec5SDimitry Andric 295*0b57cec5SDimitry Andric void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D, 296*0b57cec5SDimitry Andric AnalysisManager &mgr, 297*0b57cec5SDimitry Andric BugReporter &BR) const { 298*0b57cec5SDimitry Andric 299*0b57cec5SDimitry Andric CFG *cfg = mgr.getCFG(D); 300*0b57cec5SDimitry Andric if (!cfg) 301*0b57cec5SDimitry Andric return; 302*0b57cec5SDimitry Andric 303*0b57cec5SDimitry Andric // A list of variables referenced in possibly overflowing malloc operands. 304*0b57cec5SDimitry Andric SmallVector<MallocOverflowCheck, 2> PossibleMallocOverflows; 305*0b57cec5SDimitry Andric 306*0b57cec5SDimitry Andric for (CFG::iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) { 307*0b57cec5SDimitry Andric CFGBlock *block = *it; 308*0b57cec5SDimitry Andric for (CFGBlock::iterator bi = block->begin(), be = block->end(); 309*0b57cec5SDimitry Andric bi != be; ++bi) { 310*0b57cec5SDimitry Andric if (Optional<CFGStmt> CS = bi->getAs<CFGStmt>()) { 311*0b57cec5SDimitry Andric if (const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) { 312*0b57cec5SDimitry Andric // Get the callee. 313*0b57cec5SDimitry Andric const FunctionDecl *FD = TheCall->getDirectCallee(); 314*0b57cec5SDimitry Andric 315*0b57cec5SDimitry Andric if (!FD) 316*0b57cec5SDimitry Andric continue; 317*0b57cec5SDimitry Andric 318*0b57cec5SDimitry Andric // Get the name of the callee. If it's a builtin, strip off the prefix. 319*0b57cec5SDimitry Andric IdentifierInfo *FnInfo = FD->getIdentifier(); 320*0b57cec5SDimitry Andric if (!FnInfo) 321*0b57cec5SDimitry Andric continue; 322*0b57cec5SDimitry Andric 323*0b57cec5SDimitry Andric if (FnInfo->isStr ("malloc") || FnInfo->isStr ("_MALLOC")) { 324*0b57cec5SDimitry Andric if (TheCall->getNumArgs() == 1) 325*0b57cec5SDimitry Andric CheckMallocArgument(PossibleMallocOverflows, TheCall->getArg(0), 326*0b57cec5SDimitry Andric mgr.getASTContext()); 327*0b57cec5SDimitry Andric } 328*0b57cec5SDimitry Andric } 329*0b57cec5SDimitry Andric } 330*0b57cec5SDimitry Andric } 331*0b57cec5SDimitry Andric } 332*0b57cec5SDimitry Andric 333*0b57cec5SDimitry Andric OutputPossibleOverflows(PossibleMallocOverflows, D, BR, mgr); 334*0b57cec5SDimitry Andric } 335*0b57cec5SDimitry Andric 336*0b57cec5SDimitry Andric void ento::registerMallocOverflowSecurityChecker(CheckerManager &mgr) { 337*0b57cec5SDimitry Andric mgr.registerChecker<MallocOverflowSecurityChecker>(); 338*0b57cec5SDimitry Andric } 339*0b57cec5SDimitry Andric 340*0b57cec5SDimitry Andric bool ento::shouldRegisterMallocOverflowSecurityChecker(const LangOptions &LO) { 341*0b57cec5SDimitry Andric return true; 342*0b57cec5SDimitry Andric } 343