[clang] [clang][analyzer] Add 'Strict' option to 'core.DivideZero' checker (PR #176727)
Davide Cunial via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 19 02:51:19 PST 2026
https://github.com/capitan-davide updated https://github.com/llvm/llvm-project/pull/176727
>From 5a74b6b6e28685a6ee55bc4baa581828e1fbfbac Mon Sep 17 00:00:00 2001
From: Davide Cunial <dcunial at proton.me>
Date: Mon, 19 Jan 2026 10:35:45 +0000
Subject: [PATCH] [clang][analyzer] Add 'Strict' option to 'core.DivideZero'
checker
With the option 'Strict' the checker warns every
time the denominator of a division is potentially
zero.
---
.../clang/StaticAnalyzer/Checkers/Checkers.td | 8 ++++++
.../Checkers/DivZeroChecker.cpp | 25 +++++++++++++------
clang/test/Analysis/analyzer-config.c | 1 +
3 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index e1662e0792e69..116b51eb655e0 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -214,6 +214,14 @@ def VLASizeChecker : Checker<"VLASize">,
def DivZeroChecker : Checker<"DivideZero">,
HelpText<"Check for division by zero">,
+ CheckerOptions<[
+ CmdLineOption<Boolean,
+ "Strict",
+ "Warn on all potential divisions by zero i.e., if zero "
+ "falls within the range of possible divisor values.",
+ "false",
+ InAlpha>,
+ ]>,
Documentation<HasDocumentation>;
def UndefResultChecker : Checker<"UndefinedBinaryOperatorResult">,
diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index ab90615f63182..777576153fab2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -13,6 +13,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Checkers/Taint.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
@@ -42,6 +43,11 @@ class DivZeroChecker : public CheckerFamily<check::PreStmt<BinaryOperator>> {
/// Identifies this checker family for debugging purposes.
StringRef getDebugTag() const override { return "DivZeroChecker"; }
+
+public:
+ /// In strict mode, the checker warns about all potential divisions by zero
+ /// i.e., if zero falls within the range of possible divisor values.
+ bool Strict = true;
};
} // end anonymous namespace
@@ -73,7 +79,7 @@ void DivZeroChecker::reportTaintBug(
auto R =
std::make_unique<PathSensitiveBugReport>(TaintedDivChecker, Msg, N);
bugreporter::trackExpressionValue(N, getDenomExpr(N), *R);
- for (auto Sym : TaintedSyms)
+ for (const auto *Sym : TaintedSyms)
R->markInteresting(Sym);
C.emitReport(std::move(R));
}
@@ -82,10 +88,7 @@ void DivZeroChecker::reportTaintBug(
void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
CheckerContext &C) const {
BinaryOperator::Opcode Op = B->getOpcode();
- if (Op != BO_Div &&
- Op != BO_Rem &&
- Op != BO_DivAssign &&
- Op != BO_RemAssign)
+ if (Op != BO_Div && Op != BO_Rem && Op != BO_DivAssign && Op != BO_RemAssign)
return;
if (!B->getRHS()->getType()->isScalarType())
@@ -112,11 +115,13 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
if ((stateNotZero && stateZero)) {
std::vector<SymbolRef> taintedSyms = getTaintedSymbols(C.getState(), *DV);
- if (!taintedSyms.empty()) {
+ if (Strict) {
+ reportBug("Potential division by zero", stateZero, C);
+ } else if (!taintedSyms.empty()) {
reportTaintBug("Division by a tainted value, possibly zero", stateZero, C,
taintedSyms);
- // Fallthrough to continue analysis in case of non-zero denominator.
}
+ // Fallthrough to continue analysis in case of non-zero denominator.
}
// If we get here, then the denom should not be zero. We abandon the implicit
@@ -125,7 +130,11 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
}
void ento::registerDivZeroChecker(CheckerManager &Mgr) {
- Mgr.getChecker<DivZeroChecker>()->DivideZeroChecker.enable(Mgr);
+ auto *Chk = Mgr.getChecker<DivZeroChecker>();
+ CheckerNameRef ChkName = Mgr.getCurrentCheckerName();
+ Chk->Strict =
+ Mgr.getAnalyzerOptions().getcheckerBooleanOption(ChkName, "Strict");
+ Chk->DivideZeroChecker.enable(Mgr);
}
bool ento::shouldRegisterDivZeroChecker(const CheckerManager &) { return true; }
diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c
index 4e1f5336a9040..37cc514216e12 100644
--- a/clang/test/Analysis/analyzer-config.c
+++ b/clang/test/Analysis/analyzer-config.c
@@ -38,6 +38,7 @@
// CHECK-NEXT: core.CallAndMessage:NilReceiver = true
// CHECK-NEXT: core.CallAndMessage:ParameterCount = true
// CHECK-NEXT: core.CallAndMessage:UndefReceiver = true
+// CHECK-NEXT: core.DivideZero:Strict = false
// CHECK-NEXT: cplusplus.Move:WarnOn = KnownsAndLocals
// CHECK-NEXT: cplusplus.SmartPtrModeling:ModelSmartPtrDereference = false
// CHECK-NEXT: crosscheck-with-z3 = false
More information about the cfe-commits
mailing list