https://github.com/vgvassilev created
https://github.com/llvm/llvm-project/pull/208909
AttributeCommonInfo::getAttributeSpellingListIndex() aborts for an unknown
attribute that has a scope, such as [[ns::foo]]. It calls
calculateAttributeSpellingListIndex(), which runs name/scope string-switches
generated for the known attributes. Those switches intentionally have no
default: getScopeFromNormalizedScopeName() falls off the end and hits
llvm_unreachable ("Fell off the end of a string-switch") for the unknown scope.
Any caller that asks a scoped unknown attribute for its spelling index
therefore crashes. An unrecognized attribute has no entry in those tables and
carries a single no-spelling, so short-circuit
calculateAttributeSpellingListIndex() for UnknownAttribute and return index 0
before the switches run.
Add a unit test that constructs an unknown scoped AttributeCommonInfo and asks
for its spelling index; it aborts without the fix.
>From 405c07fa60e8a16b7e6b92e19864901b183029dd Mon Sep 17 00:00:00 2001
From: Vassil Vassilev <[email protected]>
Date: Sat, 11 Jul 2026 12:38:09 +0000
Subject: [PATCH] [Basic] Fix crash computing the spelling index of an unknown
scoped attribute
AttributeCommonInfo::getAttributeSpellingListIndex() aborts for an unknown
attribute that has a scope, such as [[ns::foo]]. It calls
calculateAttributeSpellingListIndex(), which runs name/scope string-switches
generated for the known attributes. Those switches intentionally have no
default: getScopeFromNormalizedScopeName() falls off the end and hits
llvm_unreachable ("Fell off the end of a string-switch") for the unknown scope.
Any caller that asks a scoped unknown attribute for its spelling index therefore
crashes. An unrecognized attribute has no entry in those tables and carries a
single no-spelling, so short-circuit calculateAttributeSpellingListIndex() for
UnknownAttribute and return index 0 before the switches run.
Add a unit test that constructs an unknown scoped AttributeCommonInfo and asks
for its spelling index; it aborts without the fix.
---
clang/lib/Basic/Attributes.cpp | 9 ++++++
clang/unittests/Basic/AttributesTest.cpp | 39 ++++++++++++++++++++++++
clang/unittests/Basic/CMakeLists.txt | 1 +
3 files changed, 49 insertions(+)
create mode 100644 clang/unittests/Basic/AttributesTest.cpp
diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp
index 5878a4e3f83a4..8ee45a338c57c 100644
--- a/clang/lib/Basic/Attributes.cpp
+++ b/clang/lib/Basic/Attributes.cpp
@@ -240,6 +240,15 @@ getScopeFromNormalizedScopeName(StringRef ScopeName) {
}
unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
+ // An unknown attribute (getParsedKind() == UnknownAttribute) has no entry in
+ // the generated spelling tables. The name/scope StringSwitches below assume
a
+ // known attribute and intentionally have no default, so computing an index
+ // for an unknown *scoped* attribute such as [[ns::foo]] would fall off the
+ // end (getScopeFromNormalizedScopeName aborts). It has a single no-spelling,
+ // so report index 0 instead.
+ if (getParsedKind() == AttributeCommonInfo::UnknownAttribute)
+ return 0;
+
// Both variables will be used in tablegen generated
// attribute spell list index matching code.
auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax());
diff --git a/clang/unittests/Basic/AttributesTest.cpp
b/clang/unittests/Basic/AttributesTest.cpp
new file mode 100644
index 0000000000000..3968be012ad12
--- /dev/null
+++ b/clang/unittests/Basic/AttributesTest.cpp
@@ -0,0 +1,39 @@
+//===- unittests/Basic/AttributesTest.cpp - Attribute parsing tests
-------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/AttributeCommonInfo.h"
+#include "clang/Basic/AttributeScopeInfo.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+
+namespace {
+
+// getAttributeSpellingListIndex() must not crash for an unknown *scoped*
+// attribute such as [[ns::foo]]. Such an attribute has no entry in the
+// generated spelling tables, and the name/scope string-switches used to
compute
+// the index have no default case; the computation must short-circuit for an
+// unknown attribute and report the single no-spelling instead of falling off
+// the end of a switch.
+TEST(AttributesTest, UnknownScopedAttributeSpellingIndex) {
+ LangOptions LangOpts;
+ IdentifierTable Idents(LangOpts);
+ const IdentifierInfo *Name = &Idents.get("foo");
+ const IdentifierInfo *Scope = &Idents.get("ns");
+
+ AttributeCommonInfo CI(Name, AttributeScopeInfo(Scope, SourceLocation()),
+ SourceRange(), AttributeCommonInfo::Form::CXX11());
+
+ ASSERT_EQ(CI.getParsedKind(), AttributeCommonInfo::UnknownAttribute);
+ EXPECT_EQ(CI.getAttributeSpellingListIndex(), 0u);
+}
+
+} // namespace
diff --git a/clang/unittests/Basic/CMakeLists.txt
b/clang/unittests/Basic/CMakeLists.txt
index 32dce09866892..d2f500c6c013e 100644
--- a/clang/unittests/Basic/CMakeLists.txt
+++ b/clang/unittests/Basic/CMakeLists.txt
@@ -2,6 +2,7 @@
# distinct target enables faster iteration times at low cost.
add_distinct_clang_unittest(BasicTests
AtomicLineLoggerTest.cpp
+ AttributesTest.cpp
CharInfoTest.cpp
DarwinSDKInfoTest.cpp
DiagnosticTest.cpp
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits