[nullability] Rework the way we ensure raw pointers are initialized.
We’re making this more consistent with smart pointers in that we give our
transfer functions a chance to initialize the pointer first and only create a
“backup” value if the transfer functions didn’t initialize the pointer.
I was prompted to make this change when I observed that, for raw pointer
glvalues, `ensurePointerHasValue()` would create a storage location if necessary
but not associate it with the expression. This seemed like a simple fix, but
merely adding an `Env.setStorageLocation()` caused failures because
`modelGetReferenceableValue()` was now trying to set a storage location for an
expression that already had one.
This can be fixed by moving `ensurePointerHasValue()` until after the transfer
function has run, which makes things more consistent with the treatment of smart
pointers too. To emphasize the distinction between raw and smart pointers, I am
renaming `ensurePointerHasValue()` to `ensureRawPointerHasValue()`.
Some transfer functions previously assumed that the expression they operate on
was already guaranteed to be associated with a pointer. Now, transfer functions
need to take care of this themselves if necessary. To do this, I am providing an
overload of `ensureRawPointerHasValue()` that takes an expression and returns
the pointer associated with that expression (either an already existing pointer
or a newly created one).
PiperOrigin-RevId: 646927739
Change-Id: Id05e9fff268127814606b97dadd7cd9c995eed97
diff --git a/bazel/llvm.bzl b/bazel/llvm.bzl
index a3e90c5..3c1e17c 100644
--- a/bazel/llvm.bzl
+++ b/bazel/llvm.bzl
@@ -53,7 +53,7 @@
executable = False,
)
-LLVM_COMMIT_SHA = "4e0a0eae58f7a6998866719f7eb970096a2a52e9"
+LLVM_COMMIT_SHA = "54b61adc0cbefb7f923ef43c407704ba9f9d8b69"
def llvm_loader_repository_dependencies():
# This *declares* the dependency, but it won't actually be *downloaded* unless it's used.
diff --git a/nullability/pointer_nullability_analysis.cc b/nullability/pointer_nullability_analysis.cc
index fca04ea..59a4dd6 100644
--- a/nullability/pointer_nullability_analysis.cc
+++ b/nullability/pointer_nullability_analysis.cc
@@ -79,6 +79,43 @@
return Result;
}
+// If `E` is already associated with a `PointerValue`, returns it.
+// Otherwise, associates a newly created `PointerValue` with `E` and returns it.
+// Returns null iff `E` is not a raw pointer expression.
+absl::Nullable<PointerValue *> ensureRawPointerHasValue(
+ absl::Nonnull<const Expr *> E, Environment &Env) {
+ if (!isSupportedRawPointerType(E->getType())) return nullptr;
+
+ if (E->isPRValue()) {
+ if (auto *Val = Env.get<PointerValue>(*E)) return Val;
+ auto *Val = cast<PointerValue>(Env.createValue(E->getType()));
+ Env.setValue(*E, *Val);
+ return Val;
+ }
+
+ StorageLocation *Loc = Env.getStorageLocation(*E);
+ if (Loc == nullptr) {
+ Loc = &Env.createStorageLocation(*E);
+ Env.setStorageLocation(*E, *Loc);
+ }
+ if (auto *Val = Env.get<PointerValue>(*Loc)) return Val;
+ auto *Val = cast<PointerValue>(Env.createValue(E->getType()));
+ Env.setValue(*Loc, *Val);
+ return Val;
+}
+
+// If `Elt` is an expression of raw pointer type, ensures that it has a
+// `PointerValue` associated with it.
+void ensureRawPointerHasValue(const CFGElement &Elt, Environment &Env) {
+ auto S = Elt.getAs<CFGStmt>();
+ if (!S) return;
+
+ const Expr *E = dyn_cast<Expr>(S->getStmt());
+ if (!E) return;
+
+ ensureRawPointerHasValue(E, Env);
+}
+
void computeNullability(absl::Nonnull<const Expr *> E,
TransferState<PointerNullabilityLattice> &State,
std::function<TypeNullability()> Compute) {
@@ -326,7 +363,7 @@
void transferValue_NullPointer(
absl::Nonnull<const Expr *> NullPointer, const MatchFinder::MatchResult &,
TransferState<PointerNullabilityLattice> &State) {
- if (auto *PointerVal = getRawPointerValue(NullPointer, State.Env)) {
+ if (auto *PointerVal = ensureRawPointerHasValue(NullPointer, State.Env)) {
initNullPointer(*PointerVal, State.Env.getDataflowAnalysisContext());
}
}
@@ -335,7 +372,7 @@
absl::Nonnull<const Expr *> NotNullPointer,
const MatchFinder::MatchResult &,
TransferState<PointerNullabilityLattice> &State) {
- if (auto *PointerVal = getRawPointerValue(NotNullPointer, State.Env)) {
+ if (auto *PointerVal = ensureRawPointerHasValue(NotNullPointer, State.Env)) {
initPointerNullState(*PointerVal, State.Env.getDataflowAnalysisContext(),
NullabilityKind::NonNull);
}
@@ -709,7 +746,7 @@
void transferValue_Pointer(absl::Nonnull<const Expr *> PointerExpr,
const MatchFinder::MatchResult &Result,
TransferState<PointerNullabilityLattice> &State) {
- auto *PointerVal = getRawPointerValue(PointerExpr, State.Env);
+ auto *PointerVal = ensureRawPointerHasValue(PointerExpr, State.Env);
if (!PointerVal) return;
initPointerFromTypeNullability(*PointerVal, PointerExpr, State);
@@ -1040,9 +1077,7 @@
PointerVal = dyn_cast_or_null<PointerValue>(State.Env.getValue(*Loc));
}
if (!PointerVal) {
- // Use value that may have been set by the builtin transfer function or by
- // `ensurePointerHasValue()`.
- PointerVal = getRawPointerValue(MCE, State.Env);
+ PointerVal = ensureRawPointerHasValue(MCE, State.Env);
}
if (PointerVal) {
State.Env.setValue(*MCE, *PointerVal);
@@ -1585,27 +1620,6 @@
.Build();
}
-// Ensure that all expressions of raw pointer type have a `PointerValue`
-// associated with them so we can track nullability through them.
-void ensurePointerHasValue(const CFGElement &Elt, Environment &Env) {
- auto S = Elt.getAs<CFGStmt>();
- if (!S) return;
-
- auto *E = dyn_cast<Expr>(S->getStmt());
- if (E == nullptr || !isSupportedRawPointerType(E->getType())) return;
-
- if (E->isPRValue()) {
- if (Env.getValue(*E) == nullptr)
- // `createValue()` always produces a value for pointer types.
- Env.setValue(*E, *Env.createValue(E->getType()));
- } else {
- StorageLocation *Loc = Env.getStorageLocation(*E);
- if (Loc == nullptr) Loc = &Env.createStorageLocation(*E);
- if (Env.getValue(*Loc) == nullptr)
- Env.setValue(*Loc, *Env.createValue(E->getType()));
- }
-}
-
// Ensure that all expressions of smart pointer type have an underlying
// raw pointer initialized from the type nullability.
void ensureSmartPointerInitialized(
@@ -1655,9 +1669,9 @@
Environment &Env) {
TransferState<PointerNullabilityLattice> State(Lattice, Env);
- ensurePointerHasValue(Elt, Env);
TypeTransferer(Elt, getASTContext(), State);
ValueTransferer(Elt, getASTContext(), State);
+ ensureRawPointerHasValue(Elt, Env);
ensureSmartPointerInitialized(Elt, State);
}