xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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