17330f729Sjoerg //= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This defines UnixAPIChecker, which is an assortment of checks on calls
107330f729Sjoerg // to various, widely used UNIX/Posix functions.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg
147330f729Sjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
157330f729Sjoerg #include "clang/Basic/TargetInfo.h"
167330f729Sjoerg #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
177330f729Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
187330f729Sjoerg #include "clang/StaticAnalyzer/Core/CheckerManager.h"
197330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
207330f729Sjoerg #include "llvm/ADT/Optional.h"
217330f729Sjoerg #include "llvm/ADT/STLExtras.h"
227330f729Sjoerg #include "llvm/ADT/SmallString.h"
23*e038c9c4Sjoerg #include "llvm/ADT/StringExtras.h"
247330f729Sjoerg #include "llvm/Support/raw_ostream.h"
257330f729Sjoerg
267330f729Sjoerg using namespace clang;
277330f729Sjoerg using namespace ento;
287330f729Sjoerg
297330f729Sjoerg enum class OpenVariant {
307330f729Sjoerg /// The standard open() call:
317330f729Sjoerg /// int open(const char *path, int oflag, ...);
327330f729Sjoerg Open,
337330f729Sjoerg
347330f729Sjoerg /// The variant taking a directory file descriptor and a relative path:
357330f729Sjoerg /// int openat(int fd, const char *path, int oflag, ...);
367330f729Sjoerg OpenAt
377330f729Sjoerg };
387330f729Sjoerg
397330f729Sjoerg namespace {
407330f729Sjoerg
417330f729Sjoerg class UnixAPIMisuseChecker : public Checker< check::PreStmt<CallExpr> > {
427330f729Sjoerg mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce;
437330f729Sjoerg mutable Optional<uint64_t> Val_O_CREAT;
447330f729Sjoerg
457330f729Sjoerg public:
467330f729Sjoerg DefaultBool CheckMisuse, CheckPortability;
477330f729Sjoerg
487330f729Sjoerg void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
497330f729Sjoerg
507330f729Sjoerg void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
517330f729Sjoerg void CheckOpenAt(CheckerContext &C, const CallExpr *CE) const;
527330f729Sjoerg void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
537330f729Sjoerg
547330f729Sjoerg void CheckOpenVariant(CheckerContext &C,
557330f729Sjoerg const CallExpr *CE, OpenVariant Variant) const;
567330f729Sjoerg
577330f729Sjoerg void ReportOpenBug(CheckerContext &C,
587330f729Sjoerg ProgramStateRef State,
597330f729Sjoerg const char *Msg,
607330f729Sjoerg SourceRange SR) const;
617330f729Sjoerg
627330f729Sjoerg };
637330f729Sjoerg
647330f729Sjoerg class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > {
657330f729Sjoerg public:
667330f729Sjoerg void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
677330f729Sjoerg
687330f729Sjoerg private:
697330f729Sjoerg mutable std::unique_ptr<BugType> BT_mallocZero;
707330f729Sjoerg
717330f729Sjoerg void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
727330f729Sjoerg void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
737330f729Sjoerg void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
747330f729Sjoerg void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const;
757330f729Sjoerg void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
767330f729Sjoerg void CheckAllocaWithAlignZero(CheckerContext &C, const CallExpr *CE) const;
777330f729Sjoerg void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
787330f729Sjoerg
797330f729Sjoerg bool ReportZeroByteAllocation(CheckerContext &C,
807330f729Sjoerg ProgramStateRef falseState,
817330f729Sjoerg const Expr *arg,
827330f729Sjoerg const char *fn_name) const;
837330f729Sjoerg void BasicAllocationCheck(CheckerContext &C,
847330f729Sjoerg const CallExpr *CE,
857330f729Sjoerg const unsigned numArgs,
867330f729Sjoerg const unsigned sizeArg,
877330f729Sjoerg const char *fn) const;
887330f729Sjoerg };
897330f729Sjoerg
907330f729Sjoerg } //end anonymous namespace
917330f729Sjoerg
LazyInitialize(const CheckerBase * Checker,std::unique_ptr<BugType> & BT,const char * name)927330f729Sjoerg static void LazyInitialize(const CheckerBase *Checker,
937330f729Sjoerg std::unique_ptr<BugType> &BT,
947330f729Sjoerg const char *name) {
957330f729Sjoerg if (BT)
967330f729Sjoerg return;
977330f729Sjoerg BT.reset(new BugType(Checker, name, categories::UnixAPI));
987330f729Sjoerg }
997330f729Sjoerg
1007330f729Sjoerg //===----------------------------------------------------------------------===//
1017330f729Sjoerg // "open" (man 2 open)
1027330f729Sjoerg //===----------------------------------------------------------------------===/
1037330f729Sjoerg
checkPreStmt(const CallExpr * CE,CheckerContext & C) const1047330f729Sjoerg void UnixAPIMisuseChecker::checkPreStmt(const CallExpr *CE,
1057330f729Sjoerg CheckerContext &C) const {
1067330f729Sjoerg const FunctionDecl *FD = C.getCalleeDecl(CE);
1077330f729Sjoerg if (!FD || FD->getKind() != Decl::Function)
1087330f729Sjoerg return;
1097330f729Sjoerg
1107330f729Sjoerg // Don't treat functions in namespaces with the same name a Unix function
1117330f729Sjoerg // as a call to the Unix function.
1127330f729Sjoerg const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
1137330f729Sjoerg if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
1147330f729Sjoerg return;
1157330f729Sjoerg
1167330f729Sjoerg StringRef FName = C.getCalleeName(FD);
1177330f729Sjoerg if (FName.empty())
1187330f729Sjoerg return;
1197330f729Sjoerg
1207330f729Sjoerg if (FName == "open")
1217330f729Sjoerg CheckOpen(C, CE);
1227330f729Sjoerg
1237330f729Sjoerg else if (FName == "openat")
1247330f729Sjoerg CheckOpenAt(C, CE);
1257330f729Sjoerg
1267330f729Sjoerg else if (FName == "pthread_once")
1277330f729Sjoerg CheckPthreadOnce(C, CE);
1287330f729Sjoerg }
ReportOpenBug(CheckerContext & C,ProgramStateRef State,const char * Msg,SourceRange SR) const1297330f729Sjoerg void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
1307330f729Sjoerg ProgramStateRef State,
1317330f729Sjoerg const char *Msg,
1327330f729Sjoerg SourceRange SR) const {
1337330f729Sjoerg ExplodedNode *N = C.generateErrorNode(State);
1347330f729Sjoerg if (!N)
1357330f729Sjoerg return;
1367330f729Sjoerg
1377330f729Sjoerg LazyInitialize(this, BT_open, "Improper use of 'open'");
1387330f729Sjoerg
1397330f729Sjoerg auto Report = std::make_unique<PathSensitiveBugReport>(*BT_open, Msg, N);
1407330f729Sjoerg Report->addRange(SR);
1417330f729Sjoerg C.emitReport(std::move(Report));
1427330f729Sjoerg }
1437330f729Sjoerg
CheckOpen(CheckerContext & C,const CallExpr * CE) const1447330f729Sjoerg void UnixAPIMisuseChecker::CheckOpen(CheckerContext &C,
1457330f729Sjoerg const CallExpr *CE) const {
1467330f729Sjoerg CheckOpenVariant(C, CE, OpenVariant::Open);
1477330f729Sjoerg }
1487330f729Sjoerg
CheckOpenAt(CheckerContext & C,const CallExpr * CE) const1497330f729Sjoerg void UnixAPIMisuseChecker::CheckOpenAt(CheckerContext &C,
1507330f729Sjoerg const CallExpr *CE) const {
1517330f729Sjoerg CheckOpenVariant(C, CE, OpenVariant::OpenAt);
1527330f729Sjoerg }
1537330f729Sjoerg
CheckOpenVariant(CheckerContext & C,const CallExpr * CE,OpenVariant Variant) const1547330f729Sjoerg void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
1557330f729Sjoerg const CallExpr *CE,
1567330f729Sjoerg OpenVariant Variant) const {
1577330f729Sjoerg // The index of the argument taking the flags open flags (O_RDONLY,
1587330f729Sjoerg // O_WRONLY, O_CREAT, etc.),
1597330f729Sjoerg unsigned int FlagsArgIndex;
1607330f729Sjoerg const char *VariantName;
1617330f729Sjoerg switch (Variant) {
1627330f729Sjoerg case OpenVariant::Open:
1637330f729Sjoerg FlagsArgIndex = 1;
1647330f729Sjoerg VariantName = "open";
1657330f729Sjoerg break;
1667330f729Sjoerg case OpenVariant::OpenAt:
1677330f729Sjoerg FlagsArgIndex = 2;
1687330f729Sjoerg VariantName = "openat";
1697330f729Sjoerg break;
1707330f729Sjoerg };
1717330f729Sjoerg
1727330f729Sjoerg // All calls should at least provide arguments up to the 'flags' parameter.
1737330f729Sjoerg unsigned int MinArgCount = FlagsArgIndex + 1;
1747330f729Sjoerg
1757330f729Sjoerg // If the flags has O_CREAT set then open/openat() require an additional
1767330f729Sjoerg // argument specifying the file mode (permission bits) for the created file.
1777330f729Sjoerg unsigned int CreateModeArgIndex = FlagsArgIndex + 1;
1787330f729Sjoerg
1797330f729Sjoerg // The create mode argument should be the last argument.
1807330f729Sjoerg unsigned int MaxArgCount = CreateModeArgIndex + 1;
1817330f729Sjoerg
1827330f729Sjoerg ProgramStateRef state = C.getState();
1837330f729Sjoerg
1847330f729Sjoerg if (CE->getNumArgs() < MinArgCount) {
1857330f729Sjoerg // The frontend should issue a warning for this case, so this is a sanity
1867330f729Sjoerg // check.
1877330f729Sjoerg return;
1887330f729Sjoerg } else if (CE->getNumArgs() == MaxArgCount) {
1897330f729Sjoerg const Expr *Arg = CE->getArg(CreateModeArgIndex);
1907330f729Sjoerg QualType QT = Arg->getType();
1917330f729Sjoerg if (!QT->isIntegerType()) {
1927330f729Sjoerg SmallString<256> SBuf;
1937330f729Sjoerg llvm::raw_svector_ostream OS(SBuf);
1947330f729Sjoerg OS << "The " << CreateModeArgIndex + 1
1957330f729Sjoerg << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
1967330f729Sjoerg << " argument to '" << VariantName << "' is not an integer";
1977330f729Sjoerg
1987330f729Sjoerg ReportOpenBug(C, state,
1997330f729Sjoerg SBuf.c_str(),
2007330f729Sjoerg Arg->getSourceRange());
2017330f729Sjoerg return;
2027330f729Sjoerg }
2037330f729Sjoerg } else if (CE->getNumArgs() > MaxArgCount) {
2047330f729Sjoerg SmallString<256> SBuf;
2057330f729Sjoerg llvm::raw_svector_ostream OS(SBuf);
2067330f729Sjoerg OS << "Call to '" << VariantName << "' with more than " << MaxArgCount
2077330f729Sjoerg << " arguments";
2087330f729Sjoerg
2097330f729Sjoerg ReportOpenBug(C, state,
2107330f729Sjoerg SBuf.c_str(),
2117330f729Sjoerg CE->getArg(MaxArgCount)->getSourceRange());
2127330f729Sjoerg return;
2137330f729Sjoerg }
2147330f729Sjoerg
2157330f729Sjoerg // The definition of O_CREAT is platform specific. We need a better way
2167330f729Sjoerg // of querying this information from the checking environment.
2177330f729Sjoerg if (!Val_O_CREAT.hasValue()) {
2187330f729Sjoerg if (C.getASTContext().getTargetInfo().getTriple().getVendor()
2197330f729Sjoerg == llvm::Triple::Apple)
2207330f729Sjoerg Val_O_CREAT = 0x0200;
2217330f729Sjoerg else {
2227330f729Sjoerg // FIXME: We need a more general way of getting the O_CREAT value.
2237330f729Sjoerg // We could possibly grovel through the preprocessor state, but
2247330f729Sjoerg // that would require passing the Preprocessor object to the ExprEngine.
2257330f729Sjoerg // See also: MallocChecker.cpp / M_ZERO.
2267330f729Sjoerg return;
2277330f729Sjoerg }
2287330f729Sjoerg }
2297330f729Sjoerg
2307330f729Sjoerg // Now check if oflags has O_CREAT set.
2317330f729Sjoerg const Expr *oflagsEx = CE->getArg(FlagsArgIndex);
2327330f729Sjoerg const SVal V = C.getSVal(oflagsEx);
2337330f729Sjoerg if (!V.getAs<NonLoc>()) {
2347330f729Sjoerg // The case where 'V' can be a location can only be due to a bad header,
2357330f729Sjoerg // so in this case bail out.
2367330f729Sjoerg return;
2377330f729Sjoerg }
2387330f729Sjoerg NonLoc oflags = V.castAs<NonLoc>();
2397330f729Sjoerg NonLoc ocreateFlag = C.getSValBuilder()
2407330f729Sjoerg .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
2417330f729Sjoerg SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
2427330f729Sjoerg oflags, ocreateFlag,
2437330f729Sjoerg oflagsEx->getType());
2447330f729Sjoerg if (maskedFlagsUC.isUnknownOrUndef())
2457330f729Sjoerg return;
2467330f729Sjoerg DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
2477330f729Sjoerg
2487330f729Sjoerg // Check if maskedFlags is non-zero.
2497330f729Sjoerg ProgramStateRef trueState, falseState;
2507330f729Sjoerg std::tie(trueState, falseState) = state->assume(maskedFlags);
2517330f729Sjoerg
2527330f729Sjoerg // Only emit an error if the value of 'maskedFlags' is properly
2537330f729Sjoerg // constrained;
2547330f729Sjoerg if (!(trueState && !falseState))
2557330f729Sjoerg return;
2567330f729Sjoerg
2577330f729Sjoerg if (CE->getNumArgs() < MaxArgCount) {
2587330f729Sjoerg SmallString<256> SBuf;
2597330f729Sjoerg llvm::raw_svector_ostream OS(SBuf);
2607330f729Sjoerg OS << "Call to '" << VariantName << "' requires a "
2617330f729Sjoerg << CreateModeArgIndex + 1
2627330f729Sjoerg << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
2637330f729Sjoerg << " argument when the 'O_CREAT' flag is set";
2647330f729Sjoerg ReportOpenBug(C, trueState,
2657330f729Sjoerg SBuf.c_str(),
2667330f729Sjoerg oflagsEx->getSourceRange());
2677330f729Sjoerg }
2687330f729Sjoerg }
2697330f729Sjoerg
2707330f729Sjoerg //===----------------------------------------------------------------------===//
2717330f729Sjoerg // pthread_once
2727330f729Sjoerg //===----------------------------------------------------------------------===//
2737330f729Sjoerg
CheckPthreadOnce(CheckerContext & C,const CallExpr * CE) const2747330f729Sjoerg void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
2757330f729Sjoerg const CallExpr *CE) const {
2767330f729Sjoerg
2777330f729Sjoerg // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
2787330f729Sjoerg // They can possibly be refactored.
2797330f729Sjoerg
2807330f729Sjoerg if (CE->getNumArgs() < 1)
2817330f729Sjoerg return;
2827330f729Sjoerg
2837330f729Sjoerg // Check if the first argument is stack allocated. If so, issue a warning
2847330f729Sjoerg // because that's likely to be bad news.
2857330f729Sjoerg ProgramStateRef state = C.getState();
2867330f729Sjoerg const MemRegion *R = C.getSVal(CE->getArg(0)).getAsRegion();
2877330f729Sjoerg if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
2887330f729Sjoerg return;
2897330f729Sjoerg
2907330f729Sjoerg ExplodedNode *N = C.generateErrorNode(state);
2917330f729Sjoerg if (!N)
2927330f729Sjoerg return;
2937330f729Sjoerg
2947330f729Sjoerg SmallString<256> S;
2957330f729Sjoerg llvm::raw_svector_ostream os(S);
2967330f729Sjoerg os << "Call to 'pthread_once' uses";
2977330f729Sjoerg if (const VarRegion *VR = dyn_cast<VarRegion>(R))
2987330f729Sjoerg os << " the local variable '" << VR->getDecl()->getName() << '\'';
2997330f729Sjoerg else
3007330f729Sjoerg os << " stack allocated memory";
3017330f729Sjoerg os << " for the \"control\" value. Using such transient memory for "
3027330f729Sjoerg "the control value is potentially dangerous.";
3037330f729Sjoerg if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
3047330f729Sjoerg os << " Perhaps you intended to declare the variable as 'static'?";
3057330f729Sjoerg
3067330f729Sjoerg LazyInitialize(this, BT_pthreadOnce, "Improper use of 'pthread_once'");
3077330f729Sjoerg
3087330f729Sjoerg auto report =
3097330f729Sjoerg std::make_unique<PathSensitiveBugReport>(*BT_pthreadOnce, os.str(), N);
3107330f729Sjoerg report->addRange(CE->getArg(0)->getSourceRange());
3117330f729Sjoerg C.emitReport(std::move(report));
3127330f729Sjoerg }
3137330f729Sjoerg
3147330f729Sjoerg //===----------------------------------------------------------------------===//
3157330f729Sjoerg // "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc"
3167330f729Sjoerg // with allocation size 0
3177330f729Sjoerg //===----------------------------------------------------------------------===//
3187330f729Sjoerg
3197330f729Sjoerg // FIXME: Eventually these should be rolled into the MallocChecker, but right now
3207330f729Sjoerg // they're more basic and valuable for widespread use.
3217330f729Sjoerg
3227330f729Sjoerg // Returns true if we try to do a zero byte allocation, false otherwise.
3237330f729Sjoerg // Fills in trueState and falseState.
IsZeroByteAllocation(ProgramStateRef state,const SVal argVal,ProgramStateRef * trueState,ProgramStateRef * falseState)3247330f729Sjoerg static bool IsZeroByteAllocation(ProgramStateRef state,
3257330f729Sjoerg const SVal argVal,
3267330f729Sjoerg ProgramStateRef *trueState,
3277330f729Sjoerg ProgramStateRef *falseState) {
3287330f729Sjoerg std::tie(*trueState, *falseState) =
3297330f729Sjoerg state->assume(argVal.castAs<DefinedSVal>());
3307330f729Sjoerg
3317330f729Sjoerg return (*falseState && !*trueState);
3327330f729Sjoerg }
3337330f729Sjoerg
3347330f729Sjoerg // Generates an error report, indicating that the function whose name is given
3357330f729Sjoerg // will perform a zero byte allocation.
3367330f729Sjoerg // Returns false if an error occurred, true otherwise.
ReportZeroByteAllocation(CheckerContext & C,ProgramStateRef falseState,const Expr * arg,const char * fn_name) const3377330f729Sjoerg bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
3387330f729Sjoerg CheckerContext &C,
3397330f729Sjoerg ProgramStateRef falseState,
3407330f729Sjoerg const Expr *arg,
3417330f729Sjoerg const char *fn_name) const {
3427330f729Sjoerg ExplodedNode *N = C.generateErrorNode(falseState);
3437330f729Sjoerg if (!N)
3447330f729Sjoerg return false;
3457330f729Sjoerg
3467330f729Sjoerg LazyInitialize(this, BT_mallocZero,
3477330f729Sjoerg "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
3487330f729Sjoerg
3497330f729Sjoerg SmallString<256> S;
3507330f729Sjoerg llvm::raw_svector_ostream os(S);
3517330f729Sjoerg os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
3527330f729Sjoerg auto report =
3537330f729Sjoerg std::make_unique<PathSensitiveBugReport>(*BT_mallocZero, os.str(), N);
3547330f729Sjoerg
3557330f729Sjoerg report->addRange(arg->getSourceRange());
3567330f729Sjoerg bugreporter::trackExpressionValue(N, arg, *report);
3577330f729Sjoerg C.emitReport(std::move(report));
3587330f729Sjoerg
3597330f729Sjoerg return true;
3607330f729Sjoerg }
3617330f729Sjoerg
3627330f729Sjoerg // Does a basic check for 0-sized allocations suitable for most of the below
3637330f729Sjoerg // functions (modulo "calloc")
BasicAllocationCheck(CheckerContext & C,const CallExpr * CE,const unsigned numArgs,const unsigned sizeArg,const char * fn) const3647330f729Sjoerg void UnixAPIPortabilityChecker::BasicAllocationCheck(CheckerContext &C,
3657330f729Sjoerg const CallExpr *CE,
3667330f729Sjoerg const unsigned numArgs,
3677330f729Sjoerg const unsigned sizeArg,
3687330f729Sjoerg const char *fn) const {
3697330f729Sjoerg // Sanity check for the correct number of arguments
3707330f729Sjoerg if (CE->getNumArgs() != numArgs)
3717330f729Sjoerg return;
3727330f729Sjoerg
3737330f729Sjoerg // Check if the allocation size is 0.
3747330f729Sjoerg ProgramStateRef state = C.getState();
3757330f729Sjoerg ProgramStateRef trueState = nullptr, falseState = nullptr;
3767330f729Sjoerg const Expr *arg = CE->getArg(sizeArg);
3777330f729Sjoerg SVal argVal = C.getSVal(arg);
3787330f729Sjoerg
3797330f729Sjoerg if (argVal.isUnknownOrUndef())
3807330f729Sjoerg return;
3817330f729Sjoerg
3827330f729Sjoerg // Is the value perfectly constrained to zero?
3837330f729Sjoerg if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
3847330f729Sjoerg (void) ReportZeroByteAllocation(C, falseState, arg, fn);
3857330f729Sjoerg return;
3867330f729Sjoerg }
3877330f729Sjoerg // Assume the value is non-zero going forward.
3887330f729Sjoerg assert(trueState);
3897330f729Sjoerg if (trueState != state)
3907330f729Sjoerg C.addTransition(trueState);
3917330f729Sjoerg }
3927330f729Sjoerg
CheckCallocZero(CheckerContext & C,const CallExpr * CE) const3937330f729Sjoerg void UnixAPIPortabilityChecker::CheckCallocZero(CheckerContext &C,
3947330f729Sjoerg const CallExpr *CE) const {
3957330f729Sjoerg unsigned int nArgs = CE->getNumArgs();
3967330f729Sjoerg if (nArgs != 2)
3977330f729Sjoerg return;
3987330f729Sjoerg
3997330f729Sjoerg ProgramStateRef state = C.getState();
4007330f729Sjoerg ProgramStateRef trueState = nullptr, falseState = nullptr;
4017330f729Sjoerg
4027330f729Sjoerg unsigned int i;
4037330f729Sjoerg for (i = 0; i < nArgs; i++) {
4047330f729Sjoerg const Expr *arg = CE->getArg(i);
4057330f729Sjoerg SVal argVal = C.getSVal(arg);
4067330f729Sjoerg if (argVal.isUnknownOrUndef()) {
4077330f729Sjoerg if (i == 0)
4087330f729Sjoerg continue;
4097330f729Sjoerg else
4107330f729Sjoerg return;
4117330f729Sjoerg }
4127330f729Sjoerg
4137330f729Sjoerg if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
4147330f729Sjoerg if (ReportZeroByteAllocation(C, falseState, arg, "calloc"))
4157330f729Sjoerg return;
4167330f729Sjoerg else if (i == 0)
4177330f729Sjoerg continue;
4187330f729Sjoerg else
4197330f729Sjoerg return;
4207330f729Sjoerg }
4217330f729Sjoerg }
4227330f729Sjoerg
4237330f729Sjoerg // Assume the value is non-zero going forward.
4247330f729Sjoerg assert(trueState);
4257330f729Sjoerg if (trueState != state)
4267330f729Sjoerg C.addTransition(trueState);
4277330f729Sjoerg }
4287330f729Sjoerg
CheckMallocZero(CheckerContext & C,const CallExpr * CE) const4297330f729Sjoerg void UnixAPIPortabilityChecker::CheckMallocZero(CheckerContext &C,
4307330f729Sjoerg const CallExpr *CE) const {
4317330f729Sjoerg BasicAllocationCheck(C, CE, 1, 0, "malloc");
4327330f729Sjoerg }
4337330f729Sjoerg
CheckReallocZero(CheckerContext & C,const CallExpr * CE) const4347330f729Sjoerg void UnixAPIPortabilityChecker::CheckReallocZero(CheckerContext &C,
4357330f729Sjoerg const CallExpr *CE) const {
4367330f729Sjoerg BasicAllocationCheck(C, CE, 2, 1, "realloc");
4377330f729Sjoerg }
4387330f729Sjoerg
CheckReallocfZero(CheckerContext & C,const CallExpr * CE) const4397330f729Sjoerg void UnixAPIPortabilityChecker::CheckReallocfZero(CheckerContext &C,
4407330f729Sjoerg const CallExpr *CE) const {
4417330f729Sjoerg BasicAllocationCheck(C, CE, 2, 1, "reallocf");
4427330f729Sjoerg }
4437330f729Sjoerg
CheckAllocaZero(CheckerContext & C,const CallExpr * CE) const4447330f729Sjoerg void UnixAPIPortabilityChecker::CheckAllocaZero(CheckerContext &C,
4457330f729Sjoerg const CallExpr *CE) const {
4467330f729Sjoerg BasicAllocationCheck(C, CE, 1, 0, "alloca");
4477330f729Sjoerg }
4487330f729Sjoerg
CheckAllocaWithAlignZero(CheckerContext & C,const CallExpr * CE) const4497330f729Sjoerg void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero(
4507330f729Sjoerg CheckerContext &C,
4517330f729Sjoerg const CallExpr *CE) const {
4527330f729Sjoerg BasicAllocationCheck(C, CE, 2, 0, "__builtin_alloca_with_align");
4537330f729Sjoerg }
4547330f729Sjoerg
CheckVallocZero(CheckerContext & C,const CallExpr * CE) const4557330f729Sjoerg void UnixAPIPortabilityChecker::CheckVallocZero(CheckerContext &C,
4567330f729Sjoerg const CallExpr *CE) const {
4577330f729Sjoerg BasicAllocationCheck(C, CE, 1, 0, "valloc");
4587330f729Sjoerg }
4597330f729Sjoerg
checkPreStmt(const CallExpr * CE,CheckerContext & C) const4607330f729Sjoerg void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE,
4617330f729Sjoerg CheckerContext &C) const {
4627330f729Sjoerg const FunctionDecl *FD = C.getCalleeDecl(CE);
4637330f729Sjoerg if (!FD || FD->getKind() != Decl::Function)
4647330f729Sjoerg return;
4657330f729Sjoerg
4667330f729Sjoerg // Don't treat functions in namespaces with the same name a Unix function
4677330f729Sjoerg // as a call to the Unix function.
4687330f729Sjoerg const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
4697330f729Sjoerg if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
4707330f729Sjoerg return;
4717330f729Sjoerg
4727330f729Sjoerg StringRef FName = C.getCalleeName(FD);
4737330f729Sjoerg if (FName.empty())
4747330f729Sjoerg return;
4757330f729Sjoerg
4767330f729Sjoerg if (FName == "calloc")
4777330f729Sjoerg CheckCallocZero(C, CE);
4787330f729Sjoerg
4797330f729Sjoerg else if (FName == "malloc")
4807330f729Sjoerg CheckMallocZero(C, CE);
4817330f729Sjoerg
4827330f729Sjoerg else if (FName == "realloc")
4837330f729Sjoerg CheckReallocZero(C, CE);
4847330f729Sjoerg
4857330f729Sjoerg else if (FName == "reallocf")
4867330f729Sjoerg CheckReallocfZero(C, CE);
4877330f729Sjoerg
4887330f729Sjoerg else if (FName == "alloca" || FName == "__builtin_alloca")
4897330f729Sjoerg CheckAllocaZero(C, CE);
4907330f729Sjoerg
4917330f729Sjoerg else if (FName == "__builtin_alloca_with_align")
4927330f729Sjoerg CheckAllocaWithAlignZero(C, CE);
4937330f729Sjoerg
4947330f729Sjoerg else if (FName == "valloc")
4957330f729Sjoerg CheckVallocZero(C, CE);
4967330f729Sjoerg }
4977330f729Sjoerg
4987330f729Sjoerg //===----------------------------------------------------------------------===//
4997330f729Sjoerg // Registration.
5007330f729Sjoerg //===----------------------------------------------------------------------===//
5017330f729Sjoerg
5027330f729Sjoerg #define REGISTER_CHECKER(CHECKERNAME) \
5037330f729Sjoerg void ento::register##CHECKERNAME(CheckerManager &mgr) { \
5047330f729Sjoerg mgr.registerChecker<CHECKERNAME>(); \
5057330f729Sjoerg } \
5067330f729Sjoerg \
507*e038c9c4Sjoerg bool ento::shouldRegister##CHECKERNAME(const CheckerManager &mgr) { \
5087330f729Sjoerg return true; \
5097330f729Sjoerg }
5107330f729Sjoerg
5117330f729Sjoerg REGISTER_CHECKER(UnixAPIMisuseChecker)
5127330f729Sjoerg REGISTER_CHECKER(UnixAPIPortabilityChecker)
513