[clang] [analyzer] Model strchr/strrchr/memchr/strstr/strpbrk/strchrnul (PR #207267)

Balázs Benics via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 3 10:04:41 PDT 2026


================
@@ -2617,6 +2639,54 @@ void CStringChecker::evalStrsep(CheckerContext &C,
   C.addTransition(State);
 }
 
+void CStringChecker::evalStrchrCommon(CheckerContext &C, const CallEvent &Call,
+                                      StringRef FnName,
+                                      bool CanReturnNull) const {
+  CurrentFunctionDescription = FnName;
+  ProgramStateRef State = C.getState();
+  const StackFrame *SF = C.getStackFrame();
+  SValBuilder &SVB = C.getSValBuilder();
+  ASTContext &Ctx = C.getASTContext();
+  const Expr *CE = Call.getOriginExpr();
+  assert(CE);
+
+  // These functions always return a pointer.
+  if (!CE->getType()->isPointerType())
+    return;
+
+  // The first argument must be non-null for all functions in this family.
+  SourceArgExpr Src = {{Call.getArgExpr(0), 0}};
+  SVal SrcVal = State->getSVal(Src.Expression, SF);
+  State = checkNonNull(C, State, Src, SrcVal);
+  if (!State)
+    return;
+
+  // NULL (no-match) branch.
+  if (CanReturnNull) {
+    ProgramStateRef NullState =
+        State->BindExpr(CE, SF, SVB.makeNullWithType(CE->getType()));
+    C.addTransition(NullState);
+  }
+
+  // Found branch: a pointer within the source; needs a Loc for the arithmetic.
+  std::optional<Loc> SrcLoc = SrcVal.getAs<Loc>();
+  if (!SrcLoc) {
+    SVal Result = SVB.conjureSymbolVal(Call, C.blockCount());
+    State = State->BindExpr(CE, SF, Result);
+    C.addTransition(State);
+    return;
+  }
+
+  // The result is: Src + SymOffset
----------------
steakhal wrote:

As per requested, added the dead code in 6a1e926e5ad44de0fa3ccca22d2c78e4bbfe32ef

https://github.com/llvm/llvm-project/pull/207267


More information about the cfe-commits mailing list