https://github.com/rjodinchr updated https://github.com/llvm/llvm-project/pull/238331
>From e84ead27e59e38649f1ea8c1cfd13b42dc7764a6 Mon Sep 17 00:00:00 2001 From: Romaric Jodin <[email protected]> Date: Tue, 3 Nov 2026 11:51:54 +0100 Subject: [PATCH] [AST] Avoid casting tagged DeclGroup pointer to Decl* in DeclGroupRef DeclGroupRef::getFromOpaquePtr(void *Ptr) previously converted the opaque pointer directly via static_cast<Decl *>(Ptr) before storing it in D, even when the low tag bit of Ptr is DeclGroupKind (0x1) and Ptr actually points to a tagged DeclGroup allocation rather than a Decl. Because Decl is a polymorphic class, building with Control Flow Integrity (-fsanitize=cfi-derived-cast / -fsanitize=cfi-unrelated-cast) instruments static_cast<Decl *>(Ptr) to verify the vtable pointer at *Ptr. When Ptr is a tagged DeclGroup * (whose alignment is 8 bytes and whose low bit is 1), dereferencing the unaligned tagged address as a Decl * fails the CFI vtable check at runtime. Inspect the tag bit in getFromOpaquePtr(void *Ptr) first and construct the DeclGroupRef via DeclGroupRef(reinterpret_cast<DeclGroup *>(...)) when the kind is DeclGroupKind, only casting to Decl * when the pointer actually represents a single Decl. Add a unit test in DeclTest covering DeclGroupRef::getFromOpaquePtr round-trips for both single-decl and multi-decl groups. --- clang/include/clang/AST/DeclGroup.h | 7 ++++--- clang/unittests/AST/DeclTest.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/AST/DeclGroup.h b/clang/include/clang/AST/DeclGroup.h index 6637599f0cd0c8..f6ba6aeedc8310 100644 --- a/clang/include/clang/AST/DeclGroup.h +++ b/clang/include/clang/AST/DeclGroup.h @@ -120,9 +120,10 @@ class DeclGroupRef { void *getAsOpaquePtr() const { return D; } static DeclGroupRef getFromOpaquePtr(void *Ptr) { - DeclGroupRef X; - X.D = static_cast<Decl*>(Ptr); - return X; + if ((reinterpret_cast<uintptr_t>(Ptr) & Mask) == SingleDeclKind) + return DeclGroupRef(static_cast<Decl *>(Ptr)); + return DeclGroupRef(reinterpret_cast<DeclGroup *>( + reinterpret_cast<uintptr_t>(Ptr) & ~Mask)); } }; diff --git a/clang/unittests/AST/DeclTest.cpp b/clang/unittests/AST/DeclTest.cpp index 195b8ab4c4e661..ad3cdeb91a1d14 100644 --- a/clang/unittests/AST/DeclTest.cpp +++ b/clang/unittests/AST/DeclTest.cpp @@ -1029,3 +1029,30 @@ TEST(Decl, ObjCPropertyDeclNameForDiagnostic) { /*Qualified=*/true); EXPECT_EQ(ExtPQualifiedOS.str(), "-[MyClass extensionProp]"); } + +TEST(Decl, DeclGroupRefOpaquePtrRoundTrip) { + auto AST = tooling::buildASTFromCode("int a, b;"); + ASTContext &Ctx = AST->getASTContext(); + + auto *A = const_cast<VarDecl *>( + selectFirst<VarDecl>("a", match(varDecl(hasName("a")).bind("a"), Ctx))); + auto *B = const_cast<VarDecl *>( + selectFirst<VarDecl>("b", match(varDecl(hasName("b")).bind("b"), Ctx))); + ASSERT_NE(A, nullptr); + ASSERT_NE(B, nullptr); + + DeclGroupRef Single(A); + DeclGroupRef SingleRoundTrip = + DeclGroupRef::getFromOpaquePtr(Single.getAsOpaquePtr()); + EXPECT_TRUE(SingleRoundTrip.isSingleDecl()); + EXPECT_EQ(SingleRoundTrip.getSingleDecl(), A); + + Decl *Decls[] = {A, B}; + DeclGroupRef Group = DeclGroupRef::Create(Ctx, Decls, 2); + DeclGroupRef GroupRoundTrip = + DeclGroupRef::getFromOpaquePtr(Group.getAsOpaquePtr()); + ASSERT_TRUE(GroupRoundTrip.isDeclGroup()); + ASSERT_EQ(std::distance(GroupRoundTrip.begin(), GroupRoundTrip.end()), 2); + EXPECT_EQ(GroupRoundTrip.begin()[0], A); + EXPECT_EQ(GroupRoundTrip.begin()[1], B); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
