Index: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -1667,7 +1667,7 @@ def UnixAPIPortabilityChecker : Checker<"UnixAPI">, HelpText<"Finds implementation-defined behavior in UNIX/Posix functions">, Documentation; - + } // end optin.portability //===----------------------------------------------------------------------===// Index: clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -11,11 +11,12 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/Basic/TargetInfo.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" @@ -59,9 +60,11 @@ }; -class UnixAPIPortabilityChecker : public Checker< check::PreStmt > { +class UnixAPIPortabilityChecker + : public Checker, check::PostCall> { public: void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; + void checkPostCall(const CallEvent &Call, CheckerContext &C) const; private: mutable std::unique_ptr BT_mallocZero; @@ -493,6 +496,41 @@ CheckVallocZero(C, CE); } +void UnixAPIPortabilityChecker::checkPostCall(const CallEvent &Call, + CheckerContext &C) const { + + auto State = C.getState(); + + const IdentifierInfo *II = Call.getCalleeIdentifier(); + if (!II) + return; + if (!II->isStr("printf")) + return; + + if (!BT_mallocZero) + BT_mallocZero.reset(new BugType(this, "Call to printf", "Example checker")); + + for (unsigned int i = 0; i < Call.getNumArgs(); i++) { + const auto *Arg = Call.getArgExpr(i); + if (!Arg) + return; + const auto *LC = C.getLocationContext(); + auto Val = State->getSVal(Arg, LC); + if (Val.isZeroConstant()) { + ExplodedNode *N = C.generateErrorNode(); + + // Further better the diagnostic message by adding a bug report visitor + auto Report = std::make_unique( + *BT_mallocZero, + "Passing a null pointer to printf() is implementation dependant. " + "Portability warning.", + N); + Report->addRange(Arg->getSourceRange()); + C.emitReport(std::move(Report)); + } + } +} + //===----------------------------------------------------------------------===// // Registration. //===----------------------------------------------------------------------===//