https://github.com/Hao-Chen2337 created
https://github.com/llvm/llvm-project/pull/215724
## Summary
This PR fixes a crash in clangd / clang-tidy: running the
`bugprone-pointer-arithmetic-on-polymorphic-object` check on code that does
pointer arithmetic on a pointer to an **incomplete type** (a type that is
forward-declared but never defined) makes the matcher hit an assertion and
abort.
I searched the known issues and did not find an existing report for this bug
(not 100% sure, but I did not find one). I first hit it in the clangd VS Code
extension — clangd kept crashing and restarting when opening certain files. To
rule out an extension-specific problem, I built an assertions-enabled clangd
from the latest official source and ran it standalone with `--check`; the crash
reproduces reliably on both Windows and Linux.
## Fix
First, the assertion (assertions-enabled build):
```
clang-tidy: .../clang/include/clang/AST/DeclCXX.h:463:
clang::CXXRecordDecl::DefinitionData& clang::CXXRecordDecl::data() const:
Assertion `DD && "queried property of class with no definition"' failed.
ASTMatcher: Matching 'bugprone-pointer-arithmetic-on-polymorphic-object'
against: ArraySubscriptExpr : <...repro.cpp:4:26, col:29>
```
In a release build (e.g. clangd 22.1.6) the same path is a silent SIGSEGV, exit
code 0xC0000005.
Minimal reproducer (create the files in a temp directory first):
```
mkdir -p /tmp/repro && cd /tmp/repro
cat > repro.cpp <<'EOF'
#include <map>
std::map<const Incomplete *, int> m;
struct Incomplete;
void f(Incomplete * p) { m[p]; }
EOF
cat > .clang-tidy <<'EOF'
Checks: 'bugprone-pointer-arithmetic-on-polymorphic-object'
EOF
```
Then reproduce (use the path to your own clangd / clang-tidy):
```
clangd --check=repro.cpp
clang-tidy repro.cpp
-checks='bugprone-pointer-arithmetic-on-polymorphic-object' --
```
> Note: do not put a `compile_commands.json` in the directory (with a real
> compile command the crash does not reproduce), and run from that directory.
The problem is in the check's two custom matchers:
```
AST_MATCHER(CXXRecordDecl, isAbstract) { return Node.isAbstract(); }
AST_MATCHER(CXXRecordDecl, isPolymorphic){ return Node.isPolymorphic(); }
```
They call `CXXRecordDecl::isAbstract()/isPolymorphic()`, which access
`CXXRecordDecl::data()`. An incomplete type has no `DefinitionData`, so
`data()` dereferences null.
The fix guards both matchers with `hasDefinition()`: a class without a
definition is simply treated as not polymorphic/abstract, so `data()` is never
reached.
```
AST_MATCHER(CXXRecordDecl, isAbstract) {
return Node.hasDefinition() && Node.isAbstract();
}
AST_MATCHER(CXXRecordDecl, isPolymorphic) {
return Node.hasDefinition() && Node.isPolymorphic();
}
```
This follows the same guard pattern as the fix for #140685 (PR #205973).
## Test
Added a regression case to each of the two test variants, covering the two
matcher paths of the check.
The regression code is intentionally ill-formed — pointer arithmetic on an
incomplete type is already a compile error. Why keep it in a template?
- If the code sits at file scope, the compiler error-recovers it the moment it
sees the error, so the expression leaves no usable AST node and the matcher
never sees it — the crash cannot be reproduced. Inside an uninstantiated
template, the body is not semantically checked yet (template bodies are only
analysed on instantiation), so the node survives and the matcher reaches it.
- As a bonus, since the template is never instantiated, the intentional compile
error is not reported either, so the test does not need
`-expect-clang-tidy-error`.
Verified: both cases crash before the fix (red) and pass after it (green).
>From f1ab8c7ff4783ab86e0dc1f2fc0df121154c170a Mon Sep 17 00:00:00 2001
From: Hao-Chen2337 <[email protected]>
Date: Wed, 12 Aug 2026 11:13:14 +0800
Subject: [PATCH] [clang-tidy] Fix crash on pointer arithmetic with an
incomplete type in bugprone-pointer-arithmetic-on-polymorphic-object
---
.../PointerArithmeticOnPolymorphicObjectCheck.cpp | 8 ++++++--
.../pointer-arithmetic-on-polymorphic-object-all.cpp | 12 ++++++++++++
...er-arithmetic-on-polymorphic-object-decl-only.cpp | 12 ++++++++++++
3 files changed, 30 insertions(+), 2 deletions(-)
diff --git
a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index ef5fee9f3d2c3..e54a77953283a 100644
---
a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
+++
b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -15,8 +15,12 @@ using namespace clang::ast_matchers;
namespace clang::tidy::bugprone {
namespace {
-AST_MATCHER(CXXRecordDecl, isAbstract) { return Node.isAbstract(); }
-AST_MATCHER(CXXRecordDecl, isPolymorphic) { return Node.isPolymorphic(); }
+AST_MATCHER(CXXRecordDecl, isAbstract) {
+ return Node.hasDefinition() && Node.isAbstract();
+}
+AST_MATCHER(CXXRecordDecl, isPolymorphic) {
+ return Node.hasDefinition() && Node.isPolymorphic();
+}
} // namespace
PointerArithmeticOnPolymorphicObjectCheck::
diff --git
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
index f8163a2fd3fb8..ccdc8e5761b59 100644
---
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
+++
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
@@ -150,3 +150,15 @@ struct TemplateHolder : Base {
(void)x;
}
};
+
+// Regression test: pointer arithmetic on a pointer to an incomplete type must
+// not crash the matcher. Kept in a template: the ill-formed subscript survives
+// in the AST only in a lazily-analysed template body.
+template <typename T>
+struct IncompletePointeeCrash {
+ struct Incomplete;
+ void f(Incomplete *p) {
+ p[0];
+ // no-warning
+ }
+};
diff --git
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
index 48757bbc9b10e..5a14f0617d950 100644
---
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
+++
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
@@ -139,3 +139,15 @@ void typeAliases(BaseAlias *b, DerivedAlias *d,
FinalDerivedAlias *fd,
fdp += 1;
// no-warning
}
+
+// Regression test: pointer arithmetic on a pointer to an incomplete type must
+// not crash the matcher. Kept in a template: the ill-formed subscript survives
+// in the AST only in a lazily-analysed template body.
+template <typename T>
+struct IncompletePointeeCrash {
+ struct Incomplete;
+ void f(Incomplete *p) {
+ p[0];
+ // no-warning
+ }
+};
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits