chrisbazley created this revision.
Herald added subscribers: steakhal, martong.
Herald added a reviewer: NoQ.
Herald added a project: All.
chrisbazley requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
The existing nullability checker is so limited
when applied to top-level functions that a casual
observer might assume it doesn't work at all:
void test1(int *_Nullable x)
{
*x = 5; // no warning!
}
Added a NullabilityChecker::checkBeginFunction method
to honour any _Nullable annotation of parameters in
a top-level call.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D142743
Files:
clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
Index: clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -26,12 +26,13 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/Analysis/AnyCall.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/CheckerHelpers.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Path.h"
@@ -78,10 +79,11 @@
};
class NullabilityChecker
- : public Checker<check::Bind, check::PreCall, check::PreStmt<ReturnStmt>,
- check::PostCall, check::PostStmt<ExplicitCastExpr>,
- check::PostObjCMessage, check::DeadSymbols, eval::Assume,
- check::Location, check::Event<ImplicitNullDerefEvent>> {
+ : public Checker<check::Bind, check::BeginFunction, check::PreCall,
+ check::PreStmt<ReturnStmt>, check::PostCall,
+ check::PostStmt<ExplicitCastExpr>, check::PostObjCMessage,
+ check::DeadSymbols, eval::Assume, check::Location,
+ check::Event<ImplicitNullDerefEvent>> {
public:
// If true, the checker will not diagnose nullabilility issues for calls
@@ -104,6 +106,7 @@
CheckerContext &C) const;
ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
bool Assumption) const;
+ void checkBeginFunction(CheckerContext &C) const;
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
const char *Sep) const override;
@@ -1344,6 +1347,59 @@
}
}
+/// We want to trust developer annotations and consider all 'nullable'
+/// parameters as potentially null. Each marked parameter will get a
+/// corresponding constraint.
+///
+/// \code
+/// void foo(int *_Nullable x) {
+/// // . . .
+/// *x = 42; // we want to consider this as an error...
+/// // . . .
+/// }
+/// \endcode
+void NullabilityChecker::checkBeginFunction(CheckerContext &Context) const {
+ // Planned assumption makes sense only for top-level functions.
+ if (!Context.inTopFrame())
+ return;
+
+ const LocationContext *LocContext = Context.getLocationContext();
+
+ const Decl *FD = LocContext->getDecl();
+ // AnyCall helps us here to avoid checking for FunctionDecl and ObjCMethodDecl
+ // separately and aggregates interfaces of these classes.
+ auto AbstractCall = AnyCall::forDecl(FD);
+ if (!AbstractCall)
+ return;
+
+ ProgramStateRef State = Context.getState();
+
+ for (const ParmVarDecl *Parameter : AbstractCall->parameters()) {
+ Nullability RequiredNullability =
+ getNullabilityAnnotation(Parameter->getType());
+
+ if (RequiredNullability != Nullability::Nullable)
+ continue;
+
+ Loc ParameterLoc = State->getLValue(Parameter, LocContext);
+ // We never consider top-level function parameters undefined.
+ auto StoredVal =
+ State->getSVal(ParameterLoc).castAs<DefinedOrUnknownSVal>();
+
+ const MemRegion *Region = getTrackRegion(StoredVal);
+ if (!Region)
+ continue;
+
+ const Stmt *NullabilitySource = Parameter->getBody();
+ if (ProgramStateRef NewState = State->set<NullabilityMap>(
+ Region, NullabilityState(RequiredNullability, NullabilitySource))) {
+ State = NewState;
+ }
+ }
+
+ Context.addTransition(State);
+}
+
void ento::registerNullabilityBase(CheckerManager &mgr) {
mgr.registerChecker<NullabilityChecker>();
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits