[clang] [clang][analyzer] Added Abstract VAList region normalization into MemRegionManager (PR #181948)
[ Taha. Dostifam‍ ] via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 17 17:13:22 PST 2026
https://github.com/tahadostifam created https://github.com/llvm/llvm-project/pull/181948
# Added Abstract VAList region normalization into MemRegionManager
Component: `clang` `static analyzer`
The Clang Static Analyzer's `VAListChecker` currently contains **checker-local logic** to normalize va_list memory regions (handling ElementRegion wrappers). This logic is marked with:
> TODO: In the future this should be abstracted away by the analyzer.
At [VAListChecker.cpp](https://github.com/llvm/llvm-project/blob/main/clang/lib/StaticAnalyzer/Checkers/VAListChecker.cpp#L179)
I implemented a small abstraction in MemRegionManager and adjusted VAListChecker to use it. The change compiles and basic analyzer runs with --analyze work as expected.
## Changes
- New helper in MemRegionManager
In `clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h`
```cpp
/// Strips ElementRegion wrappers from VA lists
/// Returning canonical base region.
MemRegion *getVAListRegion(const MemRegion *Reg);
```
In `clang/lib/StaticAnalyzer/Core/MemRegion.cpp`:
```cpp
MemRegion *MemRegionManager::getVAListRegion(const MemRegion *Reg) {
if (!Reg) return nullptr;
if (const ElementRegion *EReg = dyn_cast<ElementRegion>(Reg)) {
return getVAListRegion(EReg->getSuperRegion());
}
if (const DeclRegion *DeclReg = dyn_cast<DeclRegion>(Reg)) {
if (isa<ParmVarDecl>(DeclReg->getDecl())) {
return const_cast<MemRegion*>(Reg);
}
}
return const_cast<MemRegion*>(Reg);
}
```
- And now VAListChecker uses engine helper method
In clang/lib/StaticAnalyzer/Checkers/VAListChecker.cpp:
```cpp
const MemRegion *VAListChecker::getVAListAsRegion(SVal SV, const Expr *E,
CheckerContext &C) const {
const MemRegion *Reg = SV.getAsRegion();
if (!Reg)
return nullptr;
MemRegionManager &MRMgr = Reg->getMemRegionManager();
return MRMgr.getVAListRegion(Reg);
}
```
The previous checker-local logic that inspected `CastExpr`, `ParmVarDecl`, and `ElementRegion` has been removed.
## Small test cases
I used a small `va_list`-based example to test the new getVAListRegion logic:
```cpp
#include <stdarg.h>
void test_array_model(va_list ap) {
char *p = (char *)ap;
*p = 0;
}
void foo(va_list args) {
char *p = (char *)args;
*p = 0;
}
void test_nested(va_list ap) {
char (*arr)[1] = (char (*)[1])ap;
(*arr)[0] = 0;
}
int main() {
return 0;
}
```
Built and analyzed with my patched Clang:
```bash
./bin/clang --analyze va_list_test.c
```
The analyzer runs successfully on this test, and the VAList-related code paths work without crashes or unexpected diagnostics.
>From 840c5688410a9c50853f286f68f9f394d7f128b5 Mon Sep 17 00:00:00 2001
From: "Taha. Dostifam" <mr.tahadostifam at gmail.com>
Date: Wed, 18 Feb 2026 02:08:20 +0330
Subject: [PATCH 1/2] [clang][analyzer] Add MemRegionManager::getVAListRegion()
---
.../Core/PathSensitive/MemRegion.h | 4 ++++
.../StaticAnalyzer/Checkers/VAListChecker.cpp | 19 +++++--------------
clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 16 ++++++++++++++++
3 files changed, 25 insertions(+), 14 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index c59413abc352d..1cd2ea9324755 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -133,6 +133,10 @@ class MemRegion : public llvm::FoldingSetNode {
return dyn_cast<MemSpace>(getRawMemorySpace());
}
+ /// Strips ElementRegion wrappers from VA lists
+ /// Returning canonical base region.
+ MemRegion *getVAListRegion(const MemRegion *Reg);
+
/// Returns the most specific memory space for this memory region in the given
/// ProgramStateRef. We may infer a more accurate memory space for unknown
/// space regions and associate this in the State.
diff --git a/clang/lib/StaticAnalyzer/Checkers/VAListChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VAListChecker.cpp
index 503fa5de868f2..0041c714e13ca 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VAListChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VAListChecker.cpp
@@ -176,20 +176,11 @@ const MemRegion *VAListChecker::getVAListAsRegion(SVal SV, const Expr *E,
const MemRegion *Reg = SV.getAsRegion();
if (!Reg)
return nullptr;
- // TODO: In the future this should be abstracted away by the analyzer.
- bool VAListModelledAsArray = false;
- if (const auto *Cast = dyn_cast<CastExpr>(E)) {
- QualType Ty = Cast->getType();
- VAListModelledAsArray =
- Ty->isPointerType() && Ty->getPointeeType()->isRecordType();
- }
- if (const auto *DeclReg = Reg->getAs<DeclRegion>()) {
- if (isa<ParmVarDecl>(DeclReg->getDecl()))
- Reg = C.getState()->getSVal(SV.castAs<Loc>()).getAsRegion();
- }
- // Some VarRegion based VA lists reach here as ElementRegions.
- const auto *EReg = dyn_cast_or_null<ElementRegion>(Reg);
- return (EReg && VAListModelledAsArray) ? EReg->getSuperRegion() : Reg;
+
+ return C.getAnalysisManager()
+ .getRegionStore()
+ .getMemRegionManager()
+ .getVAListRegion(Reg);
}
void VAListChecker::checkPreStmt(const VAArgExpr *VAA,
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index f20e79ae675a4..7c1dcccd9fec7 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1888,3 +1888,19 @@ bool RegionAndSymbolInvalidationTraits::hasTrait(const MemRegion *MR,
return false;
}
+
+MemRegion *MemRegionManager::getVAListRegion(const MemRegion *Reg) {
+ if (!Reg) return nullptr;
+
+ if (const ElementRegion *EReg = dyn_cast<ElementRegion>(Reg)) {
+ return getVAListRegion(EReg->getSuperRegion());
+ }
+
+ if (const DeclRegion *DeclReg = dyn_cast<DeclRegion>(Reg)) {
+ if (isa<ParmVarDecl>(DeclReg->getDecl())) {
+ return const_cast<MemRegion*>(Reg);
+ }
+ }
+
+ return const_cast<MemRegion*>(Reg);
+}
\ No newline at end of file
>From b06739eaf0e2db514475feb62a7b4eb4bb46afaf Mon Sep 17 00:00:00 2001
From: "Taha. Dostifam" <mr.tahadostifam at gmail.com>
Date: Wed, 18 Feb 2026 04:28:36 +0330
Subject: [PATCH 2/2] [clang][analyzer] Fix MemRegionManager::getVAListRegion()
---
.../clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h | 8 ++++----
clang/lib/StaticAnalyzer/Checkers/VAListChecker.cpp | 6 ++----
2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 1cd2ea9324755..925f75d65dac7 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -133,10 +133,6 @@ class MemRegion : public llvm::FoldingSetNode {
return dyn_cast<MemSpace>(getRawMemorySpace());
}
- /// Strips ElementRegion wrappers from VA lists
- /// Returning canonical base region.
- MemRegion *getVAListRegion(const MemRegion *Reg);
-
/// Returns the most specific memory space for this memory region in the given
/// ProgramStateRef. We may infer a more accurate memory space for unknown
/// space regions and associate this in the State.
@@ -1608,6 +1604,10 @@ class MemRegionManager {
getCXXDerivedObjectRegion(const CXXRecordDecl *BaseClass,
const SubRegion *Super);
+ /// Strips ElementRegion wrappers from VA lists
+ /// Returning canonical base region.
+ MemRegion *getVAListRegion(const MemRegion *Reg);
+
const FunctionCodeRegion *getFunctionCodeRegion(const NamedDecl *FD);
const BlockCodeRegion *getBlockCodeRegion(const BlockDecl *BD,
CanQualType locTy,
diff --git a/clang/lib/StaticAnalyzer/Checkers/VAListChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VAListChecker.cpp
index 0041c714e13ca..321ba2d21059e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VAListChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VAListChecker.cpp
@@ -177,10 +177,8 @@ const MemRegion *VAListChecker::getVAListAsRegion(SVal SV, const Expr *E,
if (!Reg)
return nullptr;
- return C.getAnalysisManager()
- .getRegionStore()
- .getMemRegionManager()
- .getVAListRegion(Reg);
+ MemRegionManager &MRMgr = Reg->getMemRegionManager();
+ return MRMgr.getVAListRegion(Reg);
}
void VAListChecker::checkPreStmt(const VAArgExpr *VAA,
More information about the cfe-commits
mailing list