[nullability] When merging null states, first check if both pointers have null states.
The newly added test reproduces a crash that was observed when running without
the fix.
PiperOrigin-RevId: 539935363
diff --git a/nullability/pointer_nullability_analysis.cc b/nullability/pointer_nullability_analysis.cc
index 4343199..a1ae8d0 100644
--- a/nullability/pointer_nullability_analysis.cc
+++ b/nullability/pointer_nullability_analysis.cc
@@ -725,6 +725,11 @@
return false;
}
+ if (!hasPointerNullState(cast<PointerValue>(Val1)) ||
+ !hasPointerNullState(cast<PointerValue>(Val2))) {
+ return false;
+ }
+
auto [Known1, Null1] = getPointerNullState(cast<PointerValue>(Val1));
auto [Known2, Null2] = getPointerNullState(cast<PointerValue>(Val2));
diff --git a/nullability/test/fields.cc b/nullability/test/fields.cc
index e1f3f15..80fb8bd 100644
--- a/nullability/test/fields.cc
+++ b/nullability/test/fields.cc
@@ -105,6 +105,27 @@
)cc"));
}
+// This is a crash repro. It sets up a situation where we're merging pointers
+// that don't have a null state to check that we don't crash in this case.
+TEST(PointerNullabilityTest, MergePointersWithoutNullState) {
+ EXPECT_TRUE(checkDiagnostics(R"cc(
+ struct S {
+ void *p;
+ };
+ void target(bool cond) {
+ S src, dst;
+ if (cond) dst = src;
+
+ // `dst` has different values in the two branches that merge here, so we
+ // will attempt to merge the values of `dst.p` from the two branches.
+
+ // These lines are only here to ensure that `p` is modeled.
+ S unrelated;
+ unrelated.p;
+ }
+ )cc"));
+}
+
} // namespace
} // namespace nullability
} // namespace tidy