[nullability] Fix crash in `transferFlowSensitiveAccessorCall()`.
Need to use `dyn_cast_or_null` instead of `dyn_cast` because `getValue()` may
return null. (This patch adds a test that triggers this case.)
The new test exposed another issue: In the case where the line discussed above
sets `PointerVal` to null, we need to execute the fallback that calls
`getPointerValueFromExpr()` to ensure that we initialize the `PointerValue`'s
nullability properties. (The diagnosis expects every `PointerValue` to have
nullability properties set.)
PiperOrigin-RevId: 576862372
Change-Id: Ib6f4e7811cac534cb41c5f969f73ef802993499b
diff --git a/nullability/pointer_nullability_analysis.cc b/nullability/pointer_nullability_analysis.cc
index 12e9ce7..3791a87 100644
--- a/nullability/pointer_nullability_analysis.cc
+++ b/nullability/pointer_nullability_analysis.cc
@@ -527,9 +527,11 @@
if (dataflow::RecordStorageLocation *RecordLoc =
dataflow::getImplicitObjectLocation(*MCE, State.Env)) {
StorageLocation *Loc = RecordLoc->getChild(*member);
- PointerVal = dyn_cast<PointerValue>(State.Env.getValue(*Loc));
- } else {
- // Use value that may have been set by the builtin transfer function.
+ 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 = getPointerValueFromExpr(MCE, State.Env);
}
if (PointerVal) {
diff --git a/nullability/test/function_calls.cc b/nullability/test/function_calls.cc
index d4f4aa5..51a5c3b 100644
--- a/nullability/test/function_calls.cc
+++ b/nullability/test/function_calls.cc
@@ -692,6 +692,23 @@
)cc"));
}
+TEST(PointerNullabilityTest, Accessor_BaseObjectReturnedByReference) {
+ // Crash repro:
+ // If the base object of the accessor call expression is a reference returned
+ // from a function call, we have a storage location for the object but no
+ // values for its fields. Check that we don't crash in this case.
+ EXPECT_TRUE(checkDiagnostics(R"cc(
+ struct C {
+ int *_Nullable property() const { return x; }
+ int *_Nullable x = nullptr;
+ };
+ C &foo();
+ void target() {
+ if (foo().property() != nullptr) int x = *foo().property(); // [[unsafe]]
+ }
+ )cc"));
+}
+
TEST(PointerNullabilityTest, MethodNoParamsUndefinedValue) {
EXPECT_TRUE(checkDiagnostics(R"cc(
struct C {