1 //== GenericTaintChecker.cpp ----------------------------------- -*- C++ -*--=//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This checker defines the attack surface for generic taint propagation.
12 // The taint information produced by it might be useful to other checkers. For
13 // example, checkers should report errors which involve tainted data more
14 // aggressively, even if the involved symbols are under constrained.
16 //===----------------------------------------------------------------------===//
17 #include "ClangSACheckers.h"
18 #include "clang/StaticAnalyzer/Core/Checker.h"
19 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
22 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
23 #include "clang/Basic/Builtins.h"
26 using namespace clang;
30 class GenericTaintChecker : public Checker< check::PostStmt<CallExpr>,
31 check::PreStmt<CallExpr> > {
33 static void *getTag() { static int Tag; return &Tag; }
35 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
36 void checkPostStmt(const DeclRefExpr *DRE, CheckerContext &C) const;
38 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
41 static const unsigned InvalidArgIndex = UINT_MAX;
42 /// Denotes the return vale.
43 static const unsigned ReturnValueIndex = UINT_MAX - 1;
45 mutable OwningPtr<BugType> BT;
46 inline void initBugType() const {
48 BT.reset(new BugType("Use of Untrusted Data", "Untrusted Data"));
51 /// \brief Catch taint related bugs. Check if tainted data is passed to a
53 bool checkPre(const CallExpr *CE, CheckerContext &C) const;
55 /// \brief Add taint sources on a pre-visit.
56 void addSourcesPre(const CallExpr *CE, CheckerContext &C) const;
58 /// \brief Propagate taint generated at pre-visit.
59 bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const;
61 /// \brief Add taint sources on a post visit.
62 void addSourcesPost(const CallExpr *CE, CheckerContext &C) const;
64 /// Check if the region the expression evaluates to is the standard input,
65 /// and thus, is tainted.
66 static bool isStdin(const Expr *E, CheckerContext &C);
68 /// \brief Given a pointer argument, get the symbol of the value it contains
70 static SymbolRef getPointedToSymbol(CheckerContext &C, const Expr *Arg);
72 /// Functions defining the attack surface.
73 typedef ProgramStateRef (GenericTaintChecker::*FnCheck)(const CallExpr *,
74 CheckerContext &C) const;
75 ProgramStateRef postScanf(const CallExpr *CE, CheckerContext &C) const;
76 ProgramStateRef postSocket(const CallExpr *CE, CheckerContext &C) const;
77 ProgramStateRef postRetTaint(const CallExpr *CE, CheckerContext &C) const;
79 /// Taint the scanned input if the file is tainted.
80 ProgramStateRef preFscanf(const CallExpr *CE, CheckerContext &C) const;
82 /// Check for CWE-134: Uncontrolled Format String.
83 static const char MsgUncontrolledFormatString[];
84 bool checkUncontrolledFormatString(const CallExpr *CE,
85 CheckerContext &C) const;
88 /// CERT/STR02-C. "Sanitize data passed to complex subsystems"
89 /// CWE-78, "Failure to Sanitize Data into an OS Command"
90 static const char MsgSanitizeSystemArgs[];
91 bool checkSystemCall(const CallExpr *CE, StringRef Name,
92 CheckerContext &C) const;
94 /// Check if tainted data is used as a buffer size ins strn.. functions,
96 static const char MsgTaintedBufferSize[];
97 bool checkTaintedBufferSize(const CallExpr *CE, const FunctionDecl *FDecl,
98 CheckerContext &C) const;
100 /// Generate a report if the expression is tainted or points to tainted data.
101 bool generateReportIfTainted(const Expr *E, const char Msg[],
102 CheckerContext &C) const;
105 typedef llvm::SmallVector<unsigned, 2> ArgVector;
107 /// \brief A struct used to specify taint propagation rules for a function.
109 /// If any of the possible taint source arguments is tainted, all of the
110 /// destination arguments should also be tainted. Use InvalidArgIndex in the
111 /// src list to specify that all of the arguments can introduce taint. Use
112 /// InvalidArgIndex in the dst arguments to signify that all the non-const
113 /// pointer and reference arguments might be tainted on return. If
114 /// ReturnValueIndex is added to the dst list, the return value will be
116 struct TaintPropagationRule {
117 /// List of arguments which can be taint sources and should be checked.
119 /// List of arguments which should be tainted on function return.
121 // TODO: Check if using other data structures would be more optimal.
123 TaintPropagationRule() {}
125 TaintPropagationRule(unsigned SArg,
126 unsigned DArg, bool TaintRet = false) {
127 SrcArgs.push_back(SArg);
128 DstArgs.push_back(DArg);
130 DstArgs.push_back(ReturnValueIndex);
133 TaintPropagationRule(unsigned SArg1, unsigned SArg2,
134 unsigned DArg, bool TaintRet = false) {
135 SrcArgs.push_back(SArg1);
136 SrcArgs.push_back(SArg2);
137 DstArgs.push_back(DArg);
139 DstArgs.push_back(ReturnValueIndex);
142 /// Get the propagation rule for a given function.
143 static TaintPropagationRule
144 getTaintPropagationRule(const FunctionDecl *FDecl,
148 inline void addSrcArg(unsigned A) { SrcArgs.push_back(A); }
149 inline void addDstArg(unsigned A) { DstArgs.push_back(A); }
151 inline bool isNull() const { return SrcArgs.empty(); }
153 inline bool isDestinationArgument(unsigned ArgNum) const {
154 return (std::find(DstArgs.begin(),
155 DstArgs.end(), ArgNum) != DstArgs.end());
158 static inline bool isTaintedOrPointsToTainted(const Expr *E,
159 ProgramStateRef State,
161 return (State->isTainted(E, C.getLocationContext()) || isStdin(E, C) ||
162 (E->getType().getTypePtr()->isPointerType() &&
163 State->isTainted(getPointedToSymbol(C, E))));
166 /// \brief Pre-process a function which propagates taint according to the
168 ProgramStateRef process(const CallExpr *CE, CheckerContext &C) const;
173 const unsigned GenericTaintChecker::ReturnValueIndex;
174 const unsigned GenericTaintChecker::InvalidArgIndex;
176 const char GenericTaintChecker::MsgUncontrolledFormatString[] =
177 "Untrusted data is used as a format string "
178 "(CWE-134: Uncontrolled Format String)";
180 const char GenericTaintChecker::MsgSanitizeSystemArgs[] =
181 "Untrusted data is passed to a system call "
182 "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
184 const char GenericTaintChecker::MsgTaintedBufferSize[] =
185 "Untrusted data is used to specify the buffer size "
186 "(CERT/STR31-C. Guarantee that storage for strings has sufficient space for "
187 "character data and the null terminator)";
189 } // end of anonymous namespace
191 /// A set which is used to pass information from call pre-visit instruction
192 /// to the call post-visit. The values are unsigned integers, which are either
193 /// ReturnValueIndex, or indexes of the pointer/reference argument, which
194 /// points to data, which should be tainted on return.
195 REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned)
197 GenericTaintChecker::TaintPropagationRule
198 GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
199 const FunctionDecl *FDecl,
202 // TODO: Currently, we might loose precision here: we always mark a return
203 // value as tainted even if it's just a pointer, pointing to tainted data.
205 // Check for exact name match for functions without builtin substitutes.
206 TaintPropagationRule Rule = llvm::StringSwitch<TaintPropagationRule>(Name)
207 .Case("atoi", TaintPropagationRule(0, ReturnValueIndex))
208 .Case("atol", TaintPropagationRule(0, ReturnValueIndex))
209 .Case("atoll", TaintPropagationRule(0, ReturnValueIndex))
210 .Case("getc", TaintPropagationRule(0, ReturnValueIndex))
211 .Case("fgetc", TaintPropagationRule(0, ReturnValueIndex))
212 .Case("getc_unlocked", TaintPropagationRule(0, ReturnValueIndex))
213 .Case("getw", TaintPropagationRule(0, ReturnValueIndex))
214 .Case("toupper", TaintPropagationRule(0, ReturnValueIndex))
215 .Case("tolower", TaintPropagationRule(0, ReturnValueIndex))
216 .Case("strchr", TaintPropagationRule(0, ReturnValueIndex))
217 .Case("strrchr", TaintPropagationRule(0, ReturnValueIndex))
218 .Case("read", TaintPropagationRule(0, 2, 1, true))
219 .Case("pread", TaintPropagationRule(InvalidArgIndex, 1, true))
220 .Case("gets", TaintPropagationRule(InvalidArgIndex, 0, true))
221 .Case("fgets", TaintPropagationRule(2, 0, true))
222 .Case("getline", TaintPropagationRule(2, 0))
223 .Case("getdelim", TaintPropagationRule(3, 0))
224 .Case("fgetln", TaintPropagationRule(0, ReturnValueIndex))
225 .Default(TaintPropagationRule());
230 // Check if it's one of the memory setting/copying functions.
231 // This check is specialized but faster then calling isCLibraryFunction.
233 if ( (BId = FDecl->getMemoryFunctionKind()) )
235 case Builtin::BImemcpy:
236 case Builtin::BImemmove:
237 case Builtin::BIstrncpy:
238 case Builtin::BIstrncat:
239 return TaintPropagationRule(1, 2, 0, true);
240 case Builtin::BIstrlcpy:
241 case Builtin::BIstrlcat:
242 return TaintPropagationRule(1, 2, 0, false);
243 case Builtin::BIstrndup:
244 return TaintPropagationRule(0, 1, ReturnValueIndex);
250 // Process all other functions which could be defined as builtins.
252 if (C.isCLibraryFunction(FDecl, "snprintf") ||
253 C.isCLibraryFunction(FDecl, "sprintf"))
254 return TaintPropagationRule(InvalidArgIndex, 0, true);
255 else if (C.isCLibraryFunction(FDecl, "strcpy") ||
256 C.isCLibraryFunction(FDecl, "stpcpy") ||
257 C.isCLibraryFunction(FDecl, "strcat"))
258 return TaintPropagationRule(1, 0, true);
259 else if (C.isCLibraryFunction(FDecl, "bcopy"))
260 return TaintPropagationRule(0, 2, 1, false);
261 else if (C.isCLibraryFunction(FDecl, "strdup") ||
262 C.isCLibraryFunction(FDecl, "strdupa"))
263 return TaintPropagationRule(0, ReturnValueIndex);
264 else if (C.isCLibraryFunction(FDecl, "wcsdup"))
265 return TaintPropagationRule(0, ReturnValueIndex);
268 // Skipping the following functions, since they might be used for cleansing
269 // or smart memory copy:
270 // - memccpy - copying until hitting a special character.
272 return TaintPropagationRule();
275 void GenericTaintChecker::checkPreStmt(const CallExpr *CE,
276 CheckerContext &C) const {
277 // Check for errors first.
282 addSourcesPre(CE, C);
285 void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
286 CheckerContext &C) const {
287 if (propagateFromPre(CE, C))
289 addSourcesPost(CE, C);
292 void GenericTaintChecker::addSourcesPre(const CallExpr *CE,
293 CheckerContext &C) const {
294 ProgramStateRef State = 0;
295 const FunctionDecl *FDecl = C.getCalleeDecl(CE);
296 if (!FDecl || FDecl->getKind() != Decl::Function)
299 StringRef Name = C.getCalleeName(FDecl);
303 // First, try generating a propagation rule for this function.
304 TaintPropagationRule Rule =
305 TaintPropagationRule::getTaintPropagationRule(FDecl, Name, C);
306 if (!Rule.isNull()) {
307 State = Rule.process(CE, C);
310 C.addTransition(State);
314 // Otherwise, check if we have custom pre-processing implemented.
315 FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
316 .Case("fscanf", &GenericTaintChecker::preFscanf)
318 // Check and evaluate the call.
320 State = (this->*evalFunction)(CE, C);
323 C.addTransition(State);
327 bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
328 CheckerContext &C) const {
329 ProgramStateRef State = C.getState();
331 // Depending on what was tainted at pre-visit, we determined a set of
332 // arguments which should be tainted after the function returns. These are
333 // stored in the state as TaintArgsOnPostVisit set.
334 TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>();
335 if (TaintArgs.isEmpty())
338 for (llvm::ImmutableSet<unsigned>::iterator
339 I = TaintArgs.begin(), E = TaintArgs.end(); I != E; ++I) {
340 unsigned ArgNum = *I;
342 // Special handling for the tainted return value.
343 if (ArgNum == ReturnValueIndex) {
344 State = State->addTaint(CE, C.getLocationContext());
348 // The arguments are pointer arguments. The data they are pointing at is
349 // tainted after the call.
350 if (CE->getNumArgs() < (ArgNum + 1))
352 const Expr* Arg = CE->getArg(ArgNum);
353 SymbolRef Sym = getPointedToSymbol(C, Arg);
355 State = State->addTaint(Sym);
358 // Clear up the taint info from the state.
359 State = State->remove<TaintArgsOnPostVisit>();
361 if (State != C.getState()) {
362 C.addTransition(State);
368 void GenericTaintChecker::addSourcesPost(const CallExpr *CE,
369 CheckerContext &C) const {
370 // Define the attack surface.
371 // Set the evaluation function by switching on the callee name.
372 const FunctionDecl *FDecl = C.getCalleeDecl(CE);
373 if (!FDecl || FDecl->getKind() != Decl::Function)
376 StringRef Name = C.getCalleeName(FDecl);
379 FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
380 .Case("scanf", &GenericTaintChecker::postScanf)
381 // TODO: Add support for vfscanf & family.
382 .Case("getchar", &GenericTaintChecker::postRetTaint)
383 .Case("getchar_unlocked", &GenericTaintChecker::postRetTaint)
384 .Case("getenv", &GenericTaintChecker::postRetTaint)
385 .Case("fopen", &GenericTaintChecker::postRetTaint)
386 .Case("fdopen", &GenericTaintChecker::postRetTaint)
387 .Case("freopen", &GenericTaintChecker::postRetTaint)
388 .Case("getch", &GenericTaintChecker::postRetTaint)
389 .Case("wgetch", &GenericTaintChecker::postRetTaint)
390 .Case("socket", &GenericTaintChecker::postSocket)
393 // If the callee isn't defined, it is not of security concern.
394 // Check and evaluate the call.
395 ProgramStateRef State = 0;
397 State = (this->*evalFunction)(CE, C);
401 C.addTransition(State);
404 bool GenericTaintChecker::checkPre(const CallExpr *CE, CheckerContext &C) const{
406 if (checkUncontrolledFormatString(CE, C))
409 const FunctionDecl *FDecl = C.getCalleeDecl(CE);
410 if (!FDecl || FDecl->getKind() != Decl::Function)
413 StringRef Name = C.getCalleeName(FDecl);
417 if (checkSystemCall(CE, Name, C))
420 if (checkTaintedBufferSize(CE, FDecl, C))
426 SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
428 ProgramStateRef State = C.getState();
429 SVal AddrVal = State->getSVal(Arg->IgnoreParens(), C.getLocationContext());
430 if (AddrVal.isUnknownOrUndef())
433 Loc *AddrLoc = dyn_cast<Loc>(&AddrVal);
437 const PointerType *ArgTy =
438 dyn_cast<PointerType>(Arg->getType().getCanonicalType().getTypePtr());
439 SVal Val = State->getSVal(*AddrLoc,
440 ArgTy ? ArgTy->getPointeeType(): QualType());
441 return Val.getAsSymbol();
445 GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
446 CheckerContext &C) const {
447 ProgramStateRef State = C.getState();
449 // Check for taint in arguments.
450 bool IsTainted = false;
451 for (ArgVector::const_iterator I = SrcArgs.begin(),
452 E = SrcArgs.end(); I != E; ++I) {
453 unsigned ArgNum = *I;
455 if (ArgNum == InvalidArgIndex) {
456 // Check if any of the arguments is tainted, but skip the
457 // destination arguments.
458 for (unsigned int i = 0; i < CE->getNumArgs(); ++i) {
459 if (isDestinationArgument(i))
461 if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(i), State, C)))
467 if (CE->getNumArgs() < (ArgNum + 1))
469 if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(ArgNum), State, C)))
475 // Mark the arguments which should be tainted after the function returns.
476 for (ArgVector::const_iterator I = DstArgs.begin(),
477 E = DstArgs.end(); I != E; ++I) {
478 unsigned ArgNum = *I;
480 // Should we mark all arguments as tainted?
481 if (ArgNum == InvalidArgIndex) {
482 // For all pointer and references that were passed in:
483 // If they are not pointing to const data, mark data as tainted.
484 // TODO: So far we are just going one level down; ideally we'd need to
486 for (unsigned int i = 0; i < CE->getNumArgs(); ++i) {
487 const Expr *Arg = CE->getArg(i);
488 // Process pointer argument.
489 const Type *ArgTy = Arg->getType().getTypePtr();
490 QualType PType = ArgTy->getPointeeType();
491 if ((!PType.isNull() && !PType.isConstQualified())
492 || (ArgTy->isReferenceType() && !Arg->getType().isConstQualified()))
493 State = State->add<TaintArgsOnPostVisit>(i);
498 // Should mark the return value?
499 if (ArgNum == ReturnValueIndex) {
500 State = State->add<TaintArgsOnPostVisit>(ReturnValueIndex);
504 // Mark the given argument.
505 assert(ArgNum < CE->getNumArgs());
506 State = State->add<TaintArgsOnPostVisit>(ArgNum);
513 // If argument 0 (file descriptor) is tainted, all arguments except for arg 0
514 // and arg 1 should get taint.
515 ProgramStateRef GenericTaintChecker::preFscanf(const CallExpr *CE,
516 CheckerContext &C) const {
517 assert(CE->getNumArgs() >= 2);
518 ProgramStateRef State = C.getState();
520 // Check is the file descriptor is tainted.
521 if (State->isTainted(CE->getArg(0), C.getLocationContext()) ||
522 isStdin(CE->getArg(0), C)) {
523 // All arguments except for the first two should get taint.
524 for (unsigned int i = 2; i < CE->getNumArgs(); ++i)
525 State = State->add<TaintArgsOnPostVisit>(i);
533 // If argument 0(protocol domain) is network, the return value should get taint.
534 ProgramStateRef GenericTaintChecker::postSocket(const CallExpr *CE,
535 CheckerContext &C) const {
536 ProgramStateRef State = C.getState();
537 if (CE->getNumArgs() < 3)
540 SourceLocation DomLoc = CE->getArg(0)->getExprLoc();
541 StringRef DomName = C.getMacroNameOrSpelling(DomLoc);
542 // White list the internal communication protocols.
543 if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") ||
544 DomName.equals("AF_UNIX") || DomName.equals("AF_RESERVED_36"))
546 State = State->addTaint(CE, C.getLocationContext());
550 ProgramStateRef GenericTaintChecker::postScanf(const CallExpr *CE,
551 CheckerContext &C) const {
552 ProgramStateRef State = C.getState();
553 if (CE->getNumArgs() < 2)
556 // All arguments except for the very first one should get taint.
557 for (unsigned int i = 1; i < CE->getNumArgs(); ++i) {
558 // The arguments are pointer arguments. The data they are pointing at is
559 // tainted after the call.
560 const Expr* Arg = CE->getArg(i);
561 SymbolRef Sym = getPointedToSymbol(C, Arg);
563 State = State->addTaint(Sym);
568 ProgramStateRef GenericTaintChecker::postRetTaint(const CallExpr *CE,
569 CheckerContext &C) const {
570 return C.getState()->addTaint(CE, C.getLocationContext());
573 bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) {
574 ProgramStateRef State = C.getState();
575 SVal Val = State->getSVal(E, C.getLocationContext());
577 // stdin is a pointer, so it would be a region.
578 const MemRegion *MemReg = Val.getAsRegion();
580 // The region should be symbolic, we do not know it's value.
581 const SymbolicRegion *SymReg = dyn_cast_or_null<SymbolicRegion>(MemReg);
585 // Get it's symbol and find the declaration region it's pointing to.
586 const SymbolRegionValue *Sm =dyn_cast<SymbolRegionValue>(SymReg->getSymbol());
589 const DeclRegion *DeclReg = dyn_cast_or_null<DeclRegion>(Sm->getRegion());
593 // This region corresponds to a declaration, find out if it's a global/extern
594 // variable named stdin with the proper type.
595 if (const VarDecl *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) {
596 D = D->getCanonicalDecl();
597 if ((D->getName().find("stdin") != StringRef::npos) && D->isExternC())
598 if (const PointerType * PtrTy =
599 dyn_cast<PointerType>(D->getType().getTypePtr()))
600 if (PtrTy->getPointeeType() == C.getASTContext().getFILEType())
606 static bool getPrintfFormatArgumentNum(const CallExpr *CE,
607 const CheckerContext &C,
608 unsigned int &ArgNum) {
609 // Find if the function contains a format string argument.
610 // Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf,
611 // vsnprintf, syslog, custom annotated functions.
612 const FunctionDecl *FDecl = C.getCalleeDecl(CE);
615 for (specific_attr_iterator<FormatAttr>
616 i = FDecl->specific_attr_begin<FormatAttr>(),
617 e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
619 const FormatAttr *Format = *i;
620 ArgNum = Format->getFormatIdx() - 1;
621 if ((Format->getType() == "printf") && CE->getNumArgs() > ArgNum)
625 // Or if a function is named setproctitle (this is a heuristic).
626 if (C.getCalleeName(CE).find("setproctitle") != StringRef::npos) {
634 bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
636 CheckerContext &C) const {
640 ProgramStateRef State = C.getState();
641 if (!State->isTainted(getPointedToSymbol(C, E)) &&
642 !State->isTainted(E, C.getLocationContext()))
645 // Generate diagnostic.
646 if (ExplodedNode *N = C.addTransition()) {
648 BugReport *report = new BugReport(*BT, Msg, N);
649 report->addRange(E->getSourceRange());
650 C.emitReport(report);
656 bool GenericTaintChecker::checkUncontrolledFormatString(const CallExpr *CE,
657 CheckerContext &C) const{
658 // Check if the function contains a format string argument.
659 unsigned int ArgNum = 0;
660 if (!getPrintfFormatArgumentNum(CE, C, ArgNum))
663 // If either the format string content or the pointer itself are tainted, warn.
664 if (generateReportIfTainted(CE->getArg(ArgNum),
665 MsgUncontrolledFormatString, C))
670 bool GenericTaintChecker::checkSystemCall(const CallExpr *CE,
672 CheckerContext &C) const {
673 // TODO: It might make sense to run this check on demand. In some cases,
674 // we should check if the environment has been cleansed here. We also might
675 // need to know if the user was reset before these calls(seteuid).
676 unsigned ArgNum = llvm::StringSwitch<unsigned>(Name)
689 if (ArgNum == UINT_MAX || CE->getNumArgs() < (ArgNum + 1))
692 if (generateReportIfTainted(CE->getArg(ArgNum),
693 MsgSanitizeSystemArgs, C))
699 // TODO: Should this check be a part of the CString checker?
700 // If yes, should taint be a global setting?
701 bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE,
702 const FunctionDecl *FDecl,
703 CheckerContext &C) const {
704 // If the function has a buffer size argument, set ArgNum.
705 unsigned ArgNum = InvalidArgIndex;
707 if ( (BId = FDecl->getMemoryFunctionKind()) )
709 case Builtin::BImemcpy:
710 case Builtin::BImemmove:
711 case Builtin::BIstrncpy:
714 case Builtin::BIstrndup:
721 if (ArgNum == InvalidArgIndex) {
722 if (C.isCLibraryFunction(FDecl, "malloc") ||
723 C.isCLibraryFunction(FDecl, "calloc") ||
724 C.isCLibraryFunction(FDecl, "alloca"))
726 else if (C.isCLibraryFunction(FDecl, "memccpy"))
728 else if (C.isCLibraryFunction(FDecl, "realloc"))
730 else if (C.isCLibraryFunction(FDecl, "bcopy"))
734 if (ArgNum != InvalidArgIndex && CE->getNumArgs() > ArgNum &&
735 generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C))
741 void ento::registerGenericTaintChecker(CheckerManager &mgr) {
742 mgr.registerChecker<GenericTaintChecker>();