UnixAPIChecker.cpp revision 239462
167754Smsmith//= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-// 267754Smsmith// 377424Smsmith// The LLVM Compiler Infrastructure 4114237Snjl// 567754Smsmith// This file is distributed under the University of Illinois Open Source 667754Smsmith// License. See LICENSE.TXT for details. 767754Smsmith// 867754Smsmith//===----------------------------------------------------------------------===// 967754Smsmith// 1067754Smsmith// This defines UnixAPIChecker, which is an assortment of checks on calls 1167754Smsmith// to various, widely used UNIX/Posix functions. 12114237Snjl// 1370243Smsmith//===----------------------------------------------------------------------===// 1467754Smsmith 1567754Smsmith#include "ClangSACheckers.h" 1667754Smsmith#include "clang/StaticAnalyzer/Core/Checker.h" 1767754Smsmith#include "clang/StaticAnalyzer/Core/CheckerManager.h" 1867754Smsmith#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 1967754Smsmith#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 2067754Smsmith#include "clang/Basic/TargetInfo.h" 2167754Smsmith#include "llvm/ADT/Optional.h" 2267754Smsmith#include "llvm/ADT/SmallString.h" 2367754Smsmith#include "llvm/ADT/STLExtras.h" 2467754Smsmith#include "llvm/ADT/StringSwitch.h" 2567754Smsmith#include <fcntl.h> 2667754Smsmith 2767754Smsmithusing namespace clang; 2867754Smsmithusing namespace ento; 2967754Smsmithusing llvm::Optional; 3067754Smsmith 3167754Smsmithnamespace { 3267754Smsmithclass UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > { 3367754Smsmith mutable OwningPtr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero; 3467754Smsmith mutable Optional<uint64_t> Val_O_CREAT; 3567754Smsmith 3667754Smsmithpublic: 3767754Smsmith void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 3867754Smsmith 3967754Smsmith void CheckOpen(CheckerContext &C, const CallExpr *CE) const; 4067754Smsmith void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const; 4167754Smsmith void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const; 4267754Smsmith void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const; 4367754Smsmith void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const; 4467754Smsmith void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const; 4567754Smsmith void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const; 4667754Smsmith 4767754Smsmith typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &, 4867754Smsmith const CallExpr *) const; 4967754Smsmithprivate: 5067754Smsmith bool ReportZeroByteAllocation(CheckerContext &C, 5167754Smsmith ProgramStateRef falseState, 5267754Smsmith const Expr *arg, 5367754Smsmith const char *fn_name) const; 5467754Smsmith void BasicAllocationCheck(CheckerContext &C, 5567754Smsmith const CallExpr *CE, 5667754Smsmith const unsigned numArgs, 5767754Smsmith const unsigned sizeArg, 5867754Smsmith const char *fn) const; 5967754Smsmith}; 6067754Smsmith} //end anonymous namespace 6167754Smsmith 6267754Smsmith//===----------------------------------------------------------------------===// 6367754Smsmith// Utility functions. 6467754Smsmith//===----------------------------------------------------------------------===// 6567754Smsmith 6667754Smsmithstatic inline void LazyInitialize(OwningPtr<BugType> &BT, 6767754Smsmith const char *name) { 6867754Smsmith if (BT) 6967754Smsmith return; 7067754Smsmith BT.reset(new BugType(name, categories::UnixAPI)); 7167754Smsmith} 7267754Smsmith 7367754Smsmith//===----------------------------------------------------------------------===// 7467754Smsmith// "open" (man 2 open) 7567754Smsmith//===----------------------------------------------------------------------===// 7667754Smsmith 7767754Smsmithvoid UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { 7867754Smsmith // The definition of O_CREAT is platform specific. We need a better way 7967754Smsmith // of querying this information from the checking environment. 8067754Smsmith if (!Val_O_CREAT.hasValue()) { 8167754Smsmith if (C.getASTContext().getTargetInfo().getTriple().getVendor() 8267754Smsmith == llvm::Triple::Apple) 8367754Smsmith Val_O_CREAT = 0x0200; 8467754Smsmith else { 8567754Smsmith // FIXME: We need a more general way of getting the O_CREAT value. 8667754Smsmith // We could possibly grovel through the preprocessor state, but 8767754Smsmith // that would require passing the Preprocessor object to the ExprEngine. 8867754Smsmith return; 8967754Smsmith } 9067754Smsmith } 9167754Smsmith 9267754Smsmith // Look at the 'oflags' argument for the O_CREAT flag. 9367754Smsmith ProgramStateRef state = C.getState(); 9467754Smsmith 9567754Smsmith if (CE->getNumArgs() < 2) { 9667754Smsmith // The frontend should issue a warning for this case, so this is a sanity 9767754Smsmith // check. 9867754Smsmith return; 9967754Smsmith } 10067754Smsmith 10167754Smsmith // Now check if oflags has O_CREAT set. 10267754Smsmith const Expr *oflagsEx = CE->getArg(1); 10367754Smsmith const SVal V = state->getSVal(oflagsEx, C.getLocationContext()); 10467754Smsmith if (!isa<NonLoc>(V)) { 10567754Smsmith // The case where 'V' can be a location can only be due to a bad header, 10667754Smsmith // so in this case bail out. 10767754Smsmith return; 10867754Smsmith } 10967754Smsmith NonLoc oflags = cast<NonLoc>(V); 11067754Smsmith NonLoc ocreateFlag = 11167754Smsmith cast<NonLoc>(C.getSValBuilder().makeIntVal(Val_O_CREAT.getValue(), 11267754Smsmith oflagsEx->getType())); 11367754Smsmith SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And, 11467754Smsmith oflags, ocreateFlag, 11567754Smsmith oflagsEx->getType()); 11667754Smsmith if (maskedFlagsUC.isUnknownOrUndef()) 11767754Smsmith return; 11867754Smsmith DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC); 11967754Smsmith 12067754Smsmith // Check if maskedFlags is non-zero. 12167754Smsmith ProgramStateRef trueState, falseState; 12273561Smsmith llvm::tie(trueState, falseState) = state->assume(maskedFlags); 12373561Smsmith 12467754Smsmith // Only emit an error if the value of 'maskedFlags' is properly 12577424Smsmith // constrained; 12691116Smsmith if (!(trueState && !falseState)) 12767754Smsmith return; 12867754Smsmith 12967754Smsmith if (CE->getNumArgs() < 3) { 13067754Smsmith ExplodedNode *N = C.generateSink(trueState); 13167754Smsmith if (!N) 13267754Smsmith return; 13377424Smsmith 13467754Smsmith LazyInitialize(BT_open, "Improper use of 'open'"); 13567754Smsmith 13667754Smsmith BugReport *report = 13767754Smsmith new BugReport(*BT_open, 13867754Smsmith "Call to 'open' requires a third argument when " 13967754Smsmith "the 'O_CREAT' flag is set", N); 14067754Smsmith report->addRange(oflagsEx->getSourceRange()); 14167754Smsmith C.EmitReport(report); 14267754Smsmith } 14367754Smsmith} 14467754Smsmith 14567754Smsmith//===----------------------------------------------------------------------===// 14667754Smsmith// pthread_once 14767754Smsmith//===----------------------------------------------------------------------===// 14867754Smsmith 14967754Smsmithvoid UnixAPIChecker::CheckPthreadOnce(CheckerContext &C, 15091116Smsmith const CallExpr *CE) const { 15167754Smsmith 15267754Smsmith // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker. 15367754Smsmith // They can possibly be refactored. 15477424Smsmith 15591116Smsmith if (CE->getNumArgs() < 1) 15677424Smsmith return; 15767754Smsmith 15867754Smsmith // Check if the first argument is stack allocated. If so, issue a warning 15991116Smsmith // because that's likely to be bad news. 16067754Smsmith ProgramStateRef state = C.getState(); 16167754Smsmith const MemRegion *R = 162114237Snjl state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion(); 163107325Siwasaki if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) 16467754Smsmith return; 16567754Smsmith 16667754Smsmith ExplodedNode *N = C.generateSink(state); 16767754Smsmith if (!N) 16867754Smsmith return; 16967754Smsmith 17067754Smsmith SmallString<256> S; 17167754Smsmith llvm::raw_svector_ostream os(S); 17267754Smsmith os << "Call to 'pthread_once' uses"; 17367754Smsmith if (const VarRegion *VR = dyn_cast<VarRegion>(R)) 17467754Smsmith os << " the local variable '" << VR->getDecl()->getName() << '\''; 17599679Siwasaki else 17677424Smsmith os << " stack allocated memory"; 17767754Smsmith os << " for the \"control\" value. Using such transient memory for " 17882367Smsmith "the control value is potentially dangerous."; 17999679Siwasaki if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) 18067754Smsmith os << " Perhaps you intended to declare the variable as 'static'?"; 18167754Smsmith 18267754Smsmith LazyInitialize(BT_pthreadOnce, "Improper use of 'pthread_once'"); 18367754Smsmith 18467754Smsmith BugReport *report = new BugReport(*BT_pthreadOnce, os.str(), N); 18591116Smsmith report->addRange(CE->getArg(0)->getSourceRange()); 18691116Smsmith C.EmitReport(report); 18791116Smsmith} 18891116Smsmith 18967754Smsmith//===----------------------------------------------------------------------===// 19091116Smsmith// "calloc", "malloc", "realloc", "alloca" and "valloc" with allocation size 0 19187031Smsmith//===----------------------------------------------------------------------===// 19267754Smsmith// FIXME: Eventually these should be rolled into the MallocChecker, but right now 19391116Smsmith// they're more basic and valuable for widespread use. 19467754Smsmith 19587031Smsmith// Returns true if we try to do a zero byte allocation, false otherwise. 19691116Smsmith// Fills in trueState and falseState. 19787031Smsmithstatic bool IsZeroByteAllocation(ProgramStateRef state, 19867754Smsmith const SVal argVal, 19987031Smsmith ProgramStateRef *trueState, 20067754Smsmith ProgramStateRef *falseState) { 20167754Smsmith llvm::tie(*trueState, *falseState) = 20291116Smsmith state->assume(cast<DefinedSVal>(argVal)); 20399679Siwasaki 20467754Smsmith return (*falseState && !*trueState); 20567754Smsmith} 20667754Smsmith 20767754Smsmith// Generates an error report, indicating that the function whose name is given 20867754Smsmith// will perform a zero byte allocation. 20967754Smsmith// Returns false if an error occured, true otherwise. 21067754Smsmithbool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C, 21167754Smsmith ProgramStateRef falseState, 21277424Smsmith const Expr *arg, 21377424Smsmith const char *fn_name) const { 21467754Smsmith ExplodedNode *N = C.generateSink(falseState); 21567754Smsmith if (!N) 21667754Smsmith return false; 21767754Smsmith 21891116Smsmith LazyInitialize(BT_mallocZero, 21967754Smsmith "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)"); 22067754Smsmith 22167754Smsmith SmallString<256> S; 22267754Smsmith llvm::raw_svector_ostream os(S); 22367754Smsmith os << "Call to '" << fn_name << "' has an allocation size of 0 bytes"; 22491116Smsmith BugReport *report = new BugReport(*BT_mallocZero, os.str(), N); 22591116Smsmith 22691116Smsmith report->addRange(arg->getSourceRange()); 22767754Smsmith bugreporter::addTrackNullOrUndefValueVisitor(N, arg, report); 22867754Smsmith C.EmitReport(report); 22967754Smsmith 23067754Smsmith return true; 23167754Smsmith} 23291116Smsmith 23367754Smsmith// Does a basic check for 0-sized allocations suitable for most of the below 23491116Smsmith// functions (modulo "calloc") 235107325Siwasakivoid UnixAPIChecker::BasicAllocationCheck(CheckerContext &C, 236107325Siwasaki const CallExpr *CE, 237107325Siwasaki const unsigned numArgs, 23891116Smsmith const unsigned sizeArg, 239107325Siwasaki const char *fn) const { 240107325Siwasaki // Sanity check for the correct number of arguments 241107325Siwasaki if (CE->getNumArgs() != numArgs) 24273561Smsmith return; 24367754Smsmith 24491116Smsmith // Check if the allocation size is 0. 24567754Smsmith ProgramStateRef state = C.getState(); 24667754Smsmith ProgramStateRef trueState = NULL, falseState = NULL; 24791116Smsmith const Expr *arg = CE->getArg(sizeArg); 24867754Smsmith SVal argVal = state->getSVal(arg, C.getLocationContext()); 24967754Smsmith 25091116Smsmith if (argVal.isUnknownOrUndef()) 25191116Smsmith return; 25267754Smsmith 25391116Smsmith // Is the value perfectly constrained to zero? 25467754Smsmith if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) { 25599679Siwasaki (void) ReportZeroByteAllocation(C, falseState, arg, fn); 25677424Smsmith return; 25791116Smsmith } 25877424Smsmith // Assume the value is non-zero going forward. 25977424Smsmith assert(trueState); 26077424Smsmith if (trueState != state) 26167754Smsmith C.addTransition(trueState); 262114237Snjl} 263107325Siwasaki 26477424Smsmithvoid UnixAPIChecker::CheckCallocZero(CheckerContext &C, 26591116Smsmith const CallExpr *CE) const { 26687031Smsmith unsigned int nArgs = CE->getNumArgs(); 26791116Smsmith if (nArgs != 2) 26891116Smsmith return; 26987031Smsmith 27091116Smsmith ProgramStateRef state = C.getState(); 27187031Smsmith ProgramStateRef trueState = NULL, falseState = NULL; 27287031Smsmith 27367754Smsmith unsigned int i; 274114237Snjl for (i = 0; i < nArgs; i++) { 275107325Siwasaki const Expr *arg = CE->getArg(i); 27691116Smsmith SVal argVal = state->getSVal(arg, C.getLocationContext()); 27767754Smsmith if (argVal.isUnknownOrUndef()) { 27887031Smsmith if (i == 0) 27987031Smsmith continue; 28091116Smsmith else 28199679Siwasaki return; 28287031Smsmith } 28387031Smsmith 28467754Smsmith if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) { 28567754Smsmith if (ReportZeroByteAllocation(C, falseState, arg, "calloc")) 28687031Smsmith return; 28787031Smsmith else if (i == 0) 28887031Smsmith continue; 28987031Smsmith else 29067754Smsmith return; 29187031Smsmith } 29299679Siwasaki } 29367754Smsmith 29467754Smsmith // Assume the value is non-zero going forward. 29591116Smsmith assert(trueState); 29691116Smsmith if (trueState != state) 29791116Smsmith C.addTransition(trueState); 29867754Smsmith} 299107325Siwasaki 30067754Smsmithvoid UnixAPIChecker::CheckMallocZero(CheckerContext &C, 30187031Smsmith const CallExpr *CE) const { 302107325Siwasaki BasicAllocationCheck(C, CE, 1, 0, "malloc"); 30387031Smsmith} 304107325Siwasaki 305107325Siwasakivoid UnixAPIChecker::CheckReallocZero(CheckerContext &C, 306114237Snjl const CallExpr *CE) const { 307107325Siwasaki BasicAllocationCheck(C, CE, 2, 1, "realloc"); 308107325Siwasaki} 309107325Siwasaki 310107325Siwasakivoid UnixAPIChecker::CheckAllocaZero(CheckerContext &C, 31169450Smsmith const CallExpr *CE) const { 312107325Siwasaki BasicAllocationCheck(C, CE, 1, 0, "alloca"); 313107325Siwasaki} 314107325Siwasaki 315107325Siwasakivoid UnixAPIChecker::CheckVallocZero(CheckerContext &C, 316114237Snjl const CallExpr *CE) const { 317107325Siwasaki BasicAllocationCheck(C, CE, 1, 0, "valloc"); 318107325Siwasaki} 319107325Siwasaki 320107325Siwasaki 321107325Siwasaki//===----------------------------------------------------------------------===// 32287031Smsmith// Central dispatch function. 323107325Siwasaki//===----------------------------------------------------------------------===// 32491116Smsmith 325107325Siwasakivoid UnixAPIChecker::checkPreStmt(const CallExpr *CE, 32687031Smsmith CheckerContext &C) const { 327107325Siwasaki const FunctionDecl *FD = C.getCalleeDecl(CE); 32869450Smsmith if (!FD || FD->getKind() != Decl::Function) 32987031Smsmith return; 330107325Siwasaki 33187031Smsmith StringRef FName = C.getCalleeName(FD); 332107325Siwasaki if (FName.empty()) 333107325Siwasaki return; 33467754Smsmith 335107325Siwasaki SubChecker SC = 33687031Smsmith llvm::StringSwitch<SubChecker>(FName) 33787031Smsmith .Case("open", &UnixAPIChecker::CheckOpen) 33887031Smsmith .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce) 339114237Snjl .Case("calloc", &UnixAPIChecker::CheckCallocZero) 340107325Siwasaki .Case("malloc", &UnixAPIChecker::CheckMallocZero) 341107325Siwasaki .Case("realloc", &UnixAPIChecker::CheckReallocZero) 34287031Smsmith .Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero) 34387031Smsmith .Case("valloc", &UnixAPIChecker::CheckVallocZero) 34467754Smsmith .Default(NULL); 34587031Smsmith 346107325Siwasaki if (SC) 34787031Smsmith (this->*SC)(C, CE); 348107325Siwasaki} 349107325Siwasaki 35087031Smsmith//===----------------------------------------------------------------------===// 351107325Siwasaki// Registration. 35287031Smsmith//===----------------------------------------------------------------------===// 35387031Smsmith 35487031Smsmithvoid ento::registerUnixAPIChecker(CheckerManager &mgr) { 355114237Snjl mgr.registerChecker<UnixAPIChecker>(); 356107325Siwasaki} 357107325Siwasaki