Home | History | Annotate | Download | only in Checkers
      1 //==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 //  This file defines a set of flow-insensitive security checks.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "ClangSACheckers.h"
     15 #include "clang/Analysis/AnalysisContext.h"
     16 #include "clang/AST/StmtVisitor.h"
     17 #include "clang/Basic/TargetInfo.h"
     18 #include "clang/StaticAnalyzer/Core/Checker.h"
     19 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
     20 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
     21 #include "llvm/ADT/StringSwitch.h"
     22 #include "llvm/Support/raw_ostream.h"
     23 
     24 using namespace clang;
     25 using namespace ento;
     26 
     27 static bool isArc4RandomAvailable(const ASTContext &Ctx) {
     28   const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
     29   return T.getVendor() == llvm::Triple::Apple ||
     30          T.getOS() == llvm::Triple::FreeBSD ||
     31          T.getOS() == llvm::Triple::NetBSD ||
     32          T.getOS() == llvm::Triple::OpenBSD ||
     33          T.getOS() == llvm::Triple::DragonFly;
     34 }
     35 
     36 namespace {
     37 class WalkAST : public StmtVisitor<WalkAST> {
     38   BugReporter &BR;
     39   AnalysisContext* AC;
     40   enum { num_setids = 6 };
     41   IdentifierInfo *II_setid[num_setids];
     42 
     43   const bool CheckRand;
     44 
     45 public:
     46   WalkAST(BugReporter &br, AnalysisContext* ac)
     47   : BR(br), AC(ac), II_setid(),
     48     CheckRand(isArc4RandomAvailable(BR.getContext())) {}
     49 
     50   // Statement visitor methods.
     51   void VisitCallExpr(CallExpr *CE);
     52   void VisitForStmt(ForStmt *S);
     53   void VisitCompoundStmt (CompoundStmt *S);
     54   void VisitStmt(Stmt *S) { VisitChildren(S); }
     55 
     56   void VisitChildren(Stmt *S);
     57 
     58   // Helpers.
     59   bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
     60 
     61   typedef void (WalkAST::*FnCheck)(const CallExpr *,
     62 				   const FunctionDecl *);
     63 
     64   // Checker-specific methods.
     65   void checkLoopConditionForFloat(const ForStmt *FS);
     66   void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
     67   void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
     68   void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
     69   void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
     70   void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
     71   void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
     72   void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
     73   void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
     74   void checkUncheckedReturnValue(CallExpr *CE);
     75 };
     76 } // end anonymous namespace
     77 
     78 //===----------------------------------------------------------------------===//
     79 // AST walking.
     80 //===----------------------------------------------------------------------===//
     81 
     82 void WalkAST::VisitChildren(Stmt *S) {
     83   for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
     84     if (Stmt *child = *I)
     85       Visit(child);
     86 }
     87 
     88 void WalkAST::VisitCallExpr(CallExpr *CE) {
     89   // Get the callee.
     90   const FunctionDecl *FD = CE->getDirectCallee();
     91 
     92   if (!FD)
     93     return;
     94 
     95   // Get the name of the callee. If it's a builtin, strip off the prefix.
     96   IdentifierInfo *II = FD->getIdentifier();
     97   if (!II)   // if no identifier, not a simple C function
     98     return;
     99   StringRef Name = II->getName();
    100   if (Name.startswith("__builtin_"))
    101     Name = Name.substr(10);
    102 
    103   // Set the evaluation function by switching on the callee name.
    104   FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
    105     .Case("gets", &WalkAST::checkCall_gets)
    106     .Case("getpw", &WalkAST::checkCall_getpw)
    107     .Case("mktemp", &WalkAST::checkCall_mktemp)
    108     .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
    109     .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
    110     .Case("drand48", &WalkAST::checkCall_rand)
    111     .Case("erand48", &WalkAST::checkCall_rand)
    112     .Case("jrand48", &WalkAST::checkCall_rand)
    113     .Case("lrand48", &WalkAST::checkCall_rand)
    114     .Case("mrand48", &WalkAST::checkCall_rand)
    115     .Case("nrand48", &WalkAST::checkCall_rand)
    116     .Case("lcong48", &WalkAST::checkCall_rand)
    117     .Case("rand", &WalkAST::checkCall_rand)
    118     .Case("rand_r", &WalkAST::checkCall_rand)
    119     .Case("random", &WalkAST::checkCall_random)
    120     .Case("vfork", &WalkAST::checkCall_vfork)
    121     .Default(NULL);
    122 
    123   // If the callee isn't defined, it is not of security concern.
    124   // Check and evaluate the call.
    125   if (evalFunction)
    126     (this->*evalFunction)(CE, FD);
    127 
    128   // Recurse and check children.
    129   VisitChildren(CE);
    130 }
    131 
    132 void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
    133   for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
    134     if (Stmt *child = *I) {
    135       if (CallExpr *CE = dyn_cast<CallExpr>(child))
    136         checkUncheckedReturnValue(CE);
    137       Visit(child);
    138     }
    139 }
    140 
    141 void WalkAST::VisitForStmt(ForStmt *FS) {
    142   checkLoopConditionForFloat(FS);
    143 
    144   // Recurse and check children.
    145   VisitChildren(FS);
    146 }
    147 
    148 //===----------------------------------------------------------------------===//
    149 // Check: floating poing variable used as loop counter.
    150 // Originally: <rdar://problem/6336718>
    151 // Implements: CERT security coding advisory FLP-30.
    152 //===----------------------------------------------------------------------===//
    153 
    154 static const DeclRefExpr*
    155 getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
    156   expr = expr->IgnoreParenCasts();
    157 
    158   if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
    159     if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
    160           B->getOpcode() == BO_Comma))
    161       return NULL;
    162 
    163     if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
    164       return lhs;
    165 
    166     if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
    167       return rhs;
    168 
    169     return NULL;
    170   }
    171 
    172   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
    173     const NamedDecl *ND = DR->getDecl();
    174     return ND == x || ND == y ? DR : NULL;
    175   }
    176 
    177   if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
    178     return U->isIncrementDecrementOp()
    179       ? getIncrementedVar(U->getSubExpr(), x, y) : NULL;
    180 
    181   return NULL;
    182 }
    183 
    184 /// CheckLoopConditionForFloat - This check looks for 'for' statements that
    185 ///  use a floating point variable as a loop counter.
    186 ///  CERT: FLP30-C, FLP30-CPP.
    187 ///
    188 void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
    189   // Does the loop have a condition?
    190   const Expr *condition = FS->getCond();
    191 
    192   if (!condition)
    193     return;
    194 
    195   // Does the loop have an increment?
    196   const Expr *increment = FS->getInc();
    197 
    198   if (!increment)
    199     return;
    200 
    201   // Strip away '()' and casts.
    202   condition = condition->IgnoreParenCasts();
    203   increment = increment->IgnoreParenCasts();
    204 
    205   // Is the loop condition a comparison?
    206   const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
    207 
    208   if (!B)
    209     return;
    210 
    211   // Is this a comparison?
    212   if (!(B->isRelationalOp() || B->isEqualityOp()))
    213     return;
    214 
    215   // Are we comparing variables?
    216   const DeclRefExpr *drLHS =
    217     dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
    218   const DeclRefExpr *drRHS =
    219     dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
    220 
    221   // Does at least one of the variables have a floating point type?
    222   drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : NULL;
    223   drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : NULL;
    224 
    225   if (!drLHS && !drRHS)
    226     return;
    227 
    228   const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : NULL;
    229   const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : NULL;
    230 
    231   if (!vdLHS && !vdRHS)
    232     return;
    233 
    234   // Does either variable appear in increment?
    235   const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
    236 
    237   if (!drInc)
    238     return;
    239 
    240   // Emit the error.  First figure out which DeclRefExpr in the condition
    241   // referenced the compared variable.
    242   const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
    243 
    244   SmallVector<SourceRange, 2> ranges;
    245   llvm::SmallString<256> sbuf;
    246   llvm::raw_svector_ostream os(sbuf);
    247 
    248   os << "Variable '" << drCond->getDecl()->getName()
    249      << "' with floating point type '" << drCond->getType().getAsString()
    250      << "' should not be used as a loop counter";
    251 
    252   ranges.push_back(drCond->getSourceRange());
    253   ranges.push_back(drInc->getSourceRange());
    254 
    255   const char *bugType = "Floating point variable used as loop counter";
    256 
    257   PathDiagnosticLocation FSLoc =
    258     PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
    259   BR.EmitBasicReport(bugType, "Security", os.str(),
    260                      FSLoc, ranges.data(), ranges.size());
    261 }
    262 
    263 //===----------------------------------------------------------------------===//
    264 // Check: Any use of 'gets' is insecure.
    265 // Originally: <rdar://problem/6335715>
    266 // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
    267 // CWE-242: Use of Inherently Dangerous Function
    268 //===----------------------------------------------------------------------===//
    269 
    270 void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
    271   const FunctionProtoType *FPT
    272     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    273   if (!FPT)
    274     return;
    275 
    276   // Verify that the function takes a single argument.
    277   if (FPT->getNumArgs() != 1)
    278     return;
    279 
    280   // Is the argument a 'char*'?
    281   const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
    282   if (!PT)
    283     return;
    284 
    285   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
    286     return;
    287 
    288   // Issue a warning.
    289   SourceRange R = CE->getCallee()->getSourceRange();
    290   PathDiagnosticLocation CELoc =
    291     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    292   BR.EmitBasicReport("Potential buffer overflow in call to 'gets'",
    293                      "Security",
    294                      "Call to function 'gets' is extremely insecure as it can "
    295                      "always result in a buffer overflow",
    296                      CELoc, &R, 1);
    297 }
    298 
    299 //===----------------------------------------------------------------------===//
    300 // Check: Any use of 'getpwd' is insecure.
    301 // CWE-477: Use of Obsolete Functions
    302 //===----------------------------------------------------------------------===//
    303 
    304 void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
    305   const FunctionProtoType *FPT
    306     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    307   if (!FPT)
    308     return;
    309 
    310   // Verify that the function takes two arguments.
    311   if (FPT->getNumArgs() != 2)
    312     return;
    313 
    314   // Verify the first argument type is integer.
    315   if (!FPT->getArgType(0)->isIntegerType())
    316     return;
    317 
    318   // Verify the second argument type is char*.
    319   const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(1));
    320   if (!PT)
    321     return;
    322 
    323   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
    324     return;
    325 
    326   // Issue a warning.
    327   SourceRange R = CE->getCallee()->getSourceRange();
    328   PathDiagnosticLocation CELoc =
    329     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    330   BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'",
    331                      "Security",
    332                      "The getpw() function is dangerous as it may overflow the "
    333                      "provided buffer. It is obsoleted by getpwuid().",
    334                      CELoc, &R, 1);
    335 }
    336 
    337 //===----------------------------------------------------------------------===//
    338 // Check: Any use of 'mktemp' is insecure.It is obsoleted by mkstemp().
    339 // CWE-377: Insecure Temporary File
    340 //===----------------------------------------------------------------------===//
    341 
    342 void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
    343   const FunctionProtoType *FPT
    344     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    345   if(!FPT)
    346     return;
    347 
    348   // Verify that the function takes a single argument.
    349   if (FPT->getNumArgs() != 1)
    350     return;
    351 
    352   // Verify that the argument is Pointer Type.
    353   const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
    354   if (!PT)
    355     return;
    356 
    357   // Verify that the argument is a 'char*'.
    358   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
    359     return;
    360 
    361   // Issue a waring.
    362   SourceRange R = CE->getCallee()->getSourceRange();
    363   PathDiagnosticLocation CELoc =
    364     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    365   BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'",
    366                      "Security",
    367                      "Call to function 'mktemp' is insecure as it always "
    368                      "creates or uses insecure temporary file.  Use 'mkstemp' instead",
    369                      CELoc, &R, 1);
    370 }
    371 
    372 //===----------------------------------------------------------------------===//
    373 // Check: Any use of 'strcpy' is insecure.
    374 //
    375 // CWE-119: Improper Restriction of Operations within
    376 // the Bounds of a Memory Buffer
    377 //===----------------------------------------------------------------------===//
    378 void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
    379   if (!checkCall_strCommon(CE, FD))
    380     return;
    381 
    382   // Issue a warning.
    383   SourceRange R = CE->getCallee()->getSourceRange();
    384   PathDiagnosticLocation CELoc =
    385     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    386   BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in "
    387                      "call 'strcpy'",
    388                      "Security",
    389                      "Call to function 'strcpy' is insecure as it does not "
    390 		     "provide bounding of the memory buffer. Replace "
    391 		     "unbounded copy functions with analogous functions that "
    392 		     "support length arguments such as 'strncpy'. CWE-119.",
    393                      CELoc, &R, 1);
    394 }
    395 
    396 //===----------------------------------------------------------------------===//
    397 // Check: Any use of 'strcat' is insecure.
    398 //
    399 // CWE-119: Improper Restriction of Operations within
    400 // the Bounds of a Memory Buffer
    401 //===----------------------------------------------------------------------===//
    402 void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
    403   if (!checkCall_strCommon(CE, FD))
    404     return;
    405 
    406   // Issue a warning.
    407   SourceRange R = CE->getCallee()->getSourceRange();
    408   PathDiagnosticLocation CELoc =
    409     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    410   BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in "
    411 		     "call 'strcat'",
    412 		     "Security",
    413 		     "Call to function 'strcat' is insecure as it does not "
    414 		     "provide bounding of the memory buffer. Replace "
    415 		     "unbounded copy functions with analogous functions that "
    416 		     "support length arguments such as 'strncat'. CWE-119.",
    417                      CELoc, &R, 1);
    418 }
    419 
    420 //===----------------------------------------------------------------------===//
    421 // Common check for str* functions with no bounds parameters.
    422 //===----------------------------------------------------------------------===//
    423 bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
    424   const FunctionProtoType *FPT
    425     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    426   if (!FPT)
    427     return false;
    428 
    429   // Verify the function takes two arguments, three in the _chk version.
    430   int numArgs = FPT->getNumArgs();
    431   if (numArgs != 2 && numArgs != 3)
    432     return false;
    433 
    434   // Verify the type for both arguments.
    435   for (int i = 0; i < 2; i++) {
    436     // Verify that the arguments are pointers.
    437     const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(i));
    438     if (!PT)
    439       return false;
    440 
    441     // Verify that the argument is a 'char*'.
    442     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
    443       return false;
    444   }
    445 
    446   return true;
    447 }
    448 
    449 //===----------------------------------------------------------------------===//
    450 // Check: Linear congruent random number generators should not be used
    451 // Originally: <rdar://problem/63371000>
    452 // CWE-338: Use of cryptographically weak prng
    453 //===----------------------------------------------------------------------===//
    454 
    455 void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
    456   if (!CheckRand)
    457     return;
    458 
    459   const FunctionProtoType *FTP
    460     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    461   if (!FTP)
    462     return;
    463 
    464   if (FTP->getNumArgs() == 1) {
    465     // Is the argument an 'unsigned short *'?
    466     // (Actually any integer type is allowed.)
    467     const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
    468     if (!PT)
    469       return;
    470 
    471     if (! PT->getPointeeType()->isIntegerType())
    472       return;
    473   }
    474   else if (FTP->getNumArgs() != 0)
    475     return;
    476 
    477   // Issue a warning.
    478   llvm::SmallString<256> buf1;
    479   llvm::raw_svector_ostream os1(buf1);
    480   os1 << '\'' << *FD << "' is a poor random number generator";
    481 
    482   llvm::SmallString<256> buf2;
    483   llvm::raw_svector_ostream os2(buf2);
    484   os2 << "Function '" << *FD
    485       << "' is obsolete because it implements a poor random number generator."
    486       << "  Use 'arc4random' instead";
    487 
    488   SourceRange R = CE->getCallee()->getSourceRange();
    489   PathDiagnosticLocation CELoc =
    490     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    491   BR.EmitBasicReport(os1.str(), "Security", os2.str(), CELoc, &R, 1);
    492 }
    493 
    494 //===----------------------------------------------------------------------===//
    495 // Check: 'random' should not be used
    496 // Originally: <rdar://problem/63371000>
    497 //===----------------------------------------------------------------------===//
    498 
    499 void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
    500   if (!CheckRand)
    501     return;
    502 
    503   const FunctionProtoType *FTP
    504     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    505   if (!FTP)
    506     return;
    507 
    508   // Verify that the function takes no argument.
    509   if (FTP->getNumArgs() != 0)
    510     return;
    511 
    512   // Issue a warning.
    513   SourceRange R = CE->getCallee()->getSourceRange();
    514   PathDiagnosticLocation CELoc =
    515     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    516   BR.EmitBasicReport("'random' is not a secure random number generator",
    517                      "Security",
    518                      "The 'random' function produces a sequence of values that "
    519                      "an adversary may be able to predict.  Use 'arc4random' "
    520                      "instead", CELoc, &R, 1);
    521 }
    522 
    523 //===----------------------------------------------------------------------===//
    524 // Check: 'vfork' should not be used.
    525 // POS33-C: Do not use vfork().
    526 //===----------------------------------------------------------------------===//
    527 
    528 void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
    529   // All calls to vfork() are insecure, issue a warning.
    530   SourceRange R = CE->getCallee()->getSourceRange();
    531   PathDiagnosticLocation CELoc =
    532     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    533   BR.EmitBasicReport("Potential insecure implementation-specific behavior in "
    534                      "call 'vfork'",
    535                      "Security",
    536                      "Call to function 'vfork' is insecure as it can lead to "
    537                      "denial of service situations in the parent process. "
    538                      "Replace calls to vfork with calls to the safer "
    539                      "'posix_spawn' function",
    540                      CELoc, &R, 1);
    541 }
    542 
    543 //===----------------------------------------------------------------------===//
    544 // Check: Should check whether privileges are dropped successfully.
    545 // Originally: <rdar://problem/6337132>
    546 //===----------------------------------------------------------------------===//
    547 
    548 void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
    549   const FunctionDecl *FD = CE->getDirectCallee();
    550   if (!FD)
    551     return;
    552 
    553   if (II_setid[0] == NULL) {
    554     static const char * const identifiers[num_setids] = {
    555       "setuid", "setgid", "seteuid", "setegid",
    556       "setreuid", "setregid"
    557     };
    558 
    559     for (size_t i = 0; i < num_setids; i++)
    560       II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
    561   }
    562 
    563   const IdentifierInfo *id = FD->getIdentifier();
    564   size_t identifierid;
    565 
    566   for (identifierid = 0; identifierid < num_setids; identifierid++)
    567     if (id == II_setid[identifierid])
    568       break;
    569 
    570   if (identifierid >= num_setids)
    571     return;
    572 
    573   const FunctionProtoType *FTP
    574     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    575   if (!FTP)
    576     return;
    577 
    578   // Verify that the function takes one or two arguments (depending on
    579   //   the function).
    580   if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2))
    581     return;
    582 
    583   // The arguments must be integers.
    584   for (unsigned i = 0; i < FTP->getNumArgs(); i++)
    585     if (! FTP->getArgType(i)->isIntegerType())
    586       return;
    587 
    588   // Issue a warning.
    589   llvm::SmallString<256> buf1;
    590   llvm::raw_svector_ostream os1(buf1);
    591   os1 << "Return value is not checked in call to '" << *FD << '\'';
    592 
    593   llvm::SmallString<256> buf2;
    594   llvm::raw_svector_ostream os2(buf2);
    595   os2 << "The return value from the call to '" << *FD
    596       << "' is not checked.  If an error occurs in '" << *FD
    597       << "', the following code may execute with unexpected privileges";
    598 
    599   SourceRange R = CE->getCallee()->getSourceRange();
    600   PathDiagnosticLocation CELoc =
    601     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    602   BR.EmitBasicReport(os1.str(), "Security", os2.str(), CELoc, &R, 1);
    603 }
    604 
    605 //===----------------------------------------------------------------------===//
    606 // SecuritySyntaxChecker
    607 //===----------------------------------------------------------------------===//
    608 
    609 namespace {
    610 class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
    611 public:
    612   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
    613                         BugReporter &BR) const {
    614     WalkAST walker(BR, mgr.getAnalysisContext(D));
    615     walker.Visit(D->getBody());
    616   }
    617 };
    618 }
    619 
    620 void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
    621   mgr.registerChecker<SecuritySyntaxChecker>();
    622 }
    623