Require that both sides of initialization/assignment are of supported types.
Crashes happen if we try to get PointerValues for unsupported types, and if the decls are not of a supported type, we can't collect anything useful.
Also skip compound assignments, which mostly aren't used with pointers and are better addressed for nullability purposes by requiring that pointer arithmetic is done only on Nonnull pointers.
PiperOrigin-RevId: 580970370
Change-Id: I03ef284762328ab72c422c89264efb78adadf9f9
diff --git a/nullability/inference/collect_evidence.cc b/nullability/inference/collect_evidence.cc
index 6d1bd93..81a9f5b 100644
--- a/nullability/inference/collect_evidence.cc
+++ b/nullability/inference/collect_evidence.cc
@@ -137,6 +137,9 @@
std::vector<std::pair<PointerTypeNullability, Slot>> &InferableSlots,
Evidence::Kind EvidenceKind, llvm::function_ref<EvidenceEmitter> Emit) {
auto &A = Env.getDataflowAnalysisContext().arena();
+ CHECK(hasPointerNullState(Value))
+ << "Value should be the value of an expression. Cannot collect evidence "
+ "for nonnull-ness if there is no null state.";
auto *IsNull = getPointerNullState(Value).IsNull;
// If `IsNull` is top, we can't infer anything about it.
if (IsNull == nullptr) return;
@@ -396,8 +399,19 @@
if (auto *DeclStmt = dyn_cast_or_null<clang::DeclStmt>(CFGStmt->getStmt())) {
for (auto *Decl : DeclStmt->decls()) {
if (auto *VarDecl = dyn_cast_or_null<clang::VarDecl>(Decl);
- VarDecl && isSupportedPointerType(VarDecl->getType()) &&
- VarDecl->hasInit()) {
+ VarDecl && VarDecl->hasInit()) {
+ bool DeclTypeSupported = isSupportedPointerType(VarDecl->getType());
+ bool InitTypeSupported =
+ isSupportedPointerType(VarDecl->getInit()->getType());
+ if (!DeclTypeSupported) return;
+ if (!InitTypeSupported) {
+ // TODO: we could perhaps support pointer initialization from numeric
+ // values, but this is very rare and not the most useful for
+ // nullability.
+ llvm::errs() << "Unsupported init type: "
+ << VarDecl->getInit()->getType() << "\n";
+ return;
+ }
auto *PV = getPointerValueFromExpr(VarDecl->getInit(), Env);
if (!PV) return;
TypeNullability TypeNullability =
@@ -413,8 +427,20 @@
// Assignment to existing decl.
if (auto *BinaryOperator =
dyn_cast_or_null<clang::BinaryOperator>(CFGStmt->getStmt());
- BinaryOperator && BinaryOperator->isAssignmentOp() &&
- isSupportedPointerType(BinaryOperator->getLHS()->getType())) {
+ BinaryOperator &&
+ BinaryOperator->getOpcode() == clang::BinaryOperatorKind::BO_Assign) {
+ bool LhsSupported =
+ isSupportedPointerType(BinaryOperator->getLHS()->getType());
+ bool RhsSupported =
+ isSupportedPointerType(BinaryOperator->getRHS()->getType());
+ if (!LhsSupported) return;
+ if (!RhsSupported) {
+ // TODO: we could perhaps support pointer assignments to numeric
+ // values, but this is very rare and not the most useful for
+ // nullability.
+ llvm::errs() << "Unsupported RHS type: "
+ << BinaryOperator->getRHS()->getType() << "\n";
+ }
auto *PV = getPointerValueFromExpr(BinaryOperator->getRHS(), Env);
if (!PV) return;
TypeNullability TypeNullability;
diff --git a/nullability/inference/collect_evidence_test.cc b/nullability/inference/collect_evidence_test.cc
index fd5b285..85389cb 100644
--- a/nullability/inference/collect_evidence_test.cc
+++ b/nullability/inference/collect_evidence_test.cc
@@ -575,6 +575,34 @@
EXPECT_THAT(collectEvidenceFromTargetFunction(Src), IsEmpty());
}
+TEST(CollectEvidenceFromImplementationTest, IrrelevantAssignments) {
+ static constexpr llvm::StringRef Src = R"cc(
+ struct S {
+ S(int* i);
+ };
+
+ void target(int* p) {
+ int* a = p; // No useful information.
+
+ // We don't collect if types on either side are not a supported pointer
+ // type.
+ int* b = 0;
+ int c = 4;
+ bool d = false;
+ S e = a;
+
+ // We don't collect from compound assignments.
+ b += 8;
+ }
+ )cc";
+ EXPECT_THAT(
+ collectEvidenceFromTargetFunction(Src),
+ // From the constructor call constructing an S; no evidence from
+ // assignments.
+ UnorderedElementsAre(evidence(paramSlot(0), Evidence::UNKNOWN_ARGUMENT,
+ functionNamed("S"))));
+}
+
// A crash repro involving callable parameters.
TEST(CollectEvidenceFromImplementationTest, FunctionPointerParam) {
static constexpr llvm::StringRef Src = R"cc(