[clang] [clang][analyzer] Add checker 'core.NullPointerArithm' (PR #157129)
Balázs Kéri via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 8 09:24:11 PDT 2025
================
@@ -379,6 +386,111 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
C.addTransition(State, this);
}
+void DereferenceChecker::checkPreStmt(const BinaryOperator *Op,
+ CheckerContext &C) const {
+ if (!Op->isAdditiveOp())
+ return;
+ const Expr *E1 = Op->getLHS();
+ const Expr *E2 = Op->getRHS();
+ QualType T1 = E1->getType().getCanonicalType();
+ QualType T2 = E2->getType().getCanonicalType();
+ if (T1->isIntegerType() && T2->isIntegerType())
+ return;
+ if (!T1->isPointerType() && !T1->isIntegerType() && !T2->isPointerType() &&
+ !T2->isIntegerType())
+ return;
+
+ ProgramStateRef State = C.getState();
+ SVal V1 = State->getSVal(E1, C.getLocationContext());
+ SVal V2 = State->getSVal(E2, C.getLocationContext());
+ if (V1.isUndef() || V2.isUndef())
+ return;
+
+ ConditionTruthVal V1IsNull = State->isNull(V1);
+ ConditionTruthVal V2IsNull = State->isNull(V2);
+ bool IsConstrained = true;
+
+ // Check cases 'NULL + x' and 'NULL - x'
+ if (T1->isPointerType() && T2->isIntegerType()) {
+ if (!V1IsNull.isConstrainedTrue() || V2IsNull.isConstrainedTrue())
+ return;
+ IsConstrained = V2IsNull.isConstrainedFalse();
+ }
+
+ // Check case 'x + NULL'
+ if (T1->isIntegerType() && T2->isPointerType()) {
+ if (V1IsNull.isConstrainedTrue() || !V2IsNull.isConstrainedTrue())
+ return;
+ IsConstrained = V1IsNull.isConstrainedFalse();
+ }
+
+ // Check case 'NULL - p' or 'p - NULL'
+ if (T1->isPointerType() && T2->isPointerType()) {
+ if (!V1IsNull.isConstrainedTrue() && !V2IsNull.isConstrainedTrue())
+ return;
+ if (V1IsNull.isConstrainedTrue() && V2IsNull.isConstrainedTrue())
+ return;
+ IsConstrained =
+ V1IsNull.isConstrainedFalse() || V2IsNull.isConstrainedFalse();
+ }
+
+ SmallString<100> Buf;
+ llvm::raw_svector_ostream Out(Buf);
+ SmallVector<SourceRange, 2> Ranges;
+
+ auto AddSubExprStr = [&](const Expr *E, bool IsPointer,
+ ConditionTruthVal IsNull) {
+ if (IsNull.isConstrainedTrue()) {
+ if (IsPointer)
+ Out << "null pointer";
+ else
+ Out << "zero";
+ } else {
+ if (!IsNull.isConstrainedFalse())
+ Out << "probably ";
+ if (IsPointer)
+ Out << "non-null pointer";
+ else
+ Out << "nonzero integer value";
+ }
+ if (IsPointer)
+ AddDerefSource(Out, Ranges, E, State.get(), C.getLocationContext(),
+ false);
+ };
+
+ if (Op->getOpcode() == BO_Add)
+ Out << "Addition of a ";
+ else
+ Out << "Subtraction of a ";
+ AddSubExprStr(E1, T1->isPointerType(), V1IsNull);
+ Out << " and a ";
+ AddSubExprStr(E2, T2->isPointerType(), V2IsNull);
+
+ if (IsConstrained)
+ Out << " results ";
+ else
+ Out << " may result ";
+ Out << "in undefined behavior";
+
+ ExplodedNode *N = C.generateErrorNode(State);
+ if (!N)
+ return;
+ auto BR = std::make_unique<PathSensitiveBugReport>(NullPointerArithmBug,
+ Buf.str(), N);
+
+ if (T1->isPointerType())
+ bugreporter::trackExpressionValue(N, E1, *BR);
+ if (T2->isPointerType())
+ bugreporter::trackExpressionValue(N, E2, *BR);
+
+ for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I)
+ BR->addRange(*I);
----------------
balazske wrote:
Code was copied from an existing function.
https://github.com/llvm/llvm-project/pull/157129
More information about the cfe-commits
mailing list