Skip to content

Commit 7cc6c45

Browse files
author
v01dxyz
committed
CHERICompartmentName: only take into account attr from DeclChunk instead of Decl
Otherwise, the attribute is silently ignored when the attribute follows a pointer return type such as: void *__attribute__((cheri_compartment("my_compartment"))) f(); A unittest case is added to never let that slip again.
1 parent a58d179 commit 7cc6c45

File tree

3 files changed

+99
-3
lines changed

3 files changed

+99
-3
lines changed

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2392,11 +2392,28 @@ static void handleCHERICompartmentName(Sema &S, Decl *D, const ParsedAttr &Attr,
23922392
Sema::DeclAttributeLocation DAL) {
23932393
// cheri_compartment is both:
23942394
//
2395-
// * a Declaration attribute: marks the function as a compartment entry point
2395+
// * a Declaration attribute: marks the function as a compartment
2396+
// entry point
23962397
// * a Function Type attribute: affects the calling convention
23972398
//
2398-
// That's the reason why we don't short-circuit with hasDeclarator
2399-
// (as other handlers do).
2399+
// That's the reason why we don't short-circuit using hasDeclarator
2400+
// (as other handlers do) as Sema::GetTypeForDeclarator only does
2401+
// the Function Type part.
2402+
//
2403+
// BUT because it is a Function Type attribute, when the attribute
2404+
// is initially attached to the DeclSpec, Sema::GetTypeForDeclarator
2405+
// distributes it to the first DeclChunk which is a function. Thus,
2406+
// the attribute is always be present at the DeclChunk level (but
2407+
// not always at the DeclSpec level). In order to not possibly
2408+
// process it twice, we always skip the DeclSpec level.
2409+
//
2410+
// **Attention**: The attribute is not always initially attached to
2411+
// the DeclSpec especially when it follows a pointer:
2412+
//
2413+
// - cheri_compartment(...) void f(): attached to DeclSpec
2414+
// - void * cheri_compartment(...) f(): attached to DeclChunk
2415+
if (DAL != Sema::DAL_DeclSpec)
2416+
return;
24002417

24012418
StringRef Str;
24022419
SourceLocation LiteralLoc;

clang/unittests/AST/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ add_clang_unittest(ASTTests
3636
TemplateNameTest.cpp
3737
TypePrinterTest.cpp
3838
UnresolvedSetTest.cpp
39+
40+
cheri/AttrTest.cpp
3941
)
4042

4143
clang_target_link_libraries(ASTTests
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===- unittests/AST/cheri/AttrTests.cpp --- CHERI Attribute tests --------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "clang/AST/Attr.h"
10+
#include "clang/ASTMatchers/ASTMatchFinder.h"
11+
#include "clang/ASTMatchers/ASTMatchers.h"
12+
#include "clang/Basic/AttrKinds.h"
13+
#include "clang/Tooling/Tooling.h"
14+
#include "gmock/gmock.h"
15+
#include "gtest/gtest.h"
16+
17+
using namespace clang;
18+
19+
namespace {
20+
21+
using clang::ast_matchers::constantExpr;
22+
using clang::ast_matchers::equals;
23+
using clang::ast_matchers::functionDecl;
24+
using clang::ast_matchers::has;
25+
using clang::ast_matchers::hasDescendant;
26+
using clang::ast_matchers::hasName;
27+
using clang::ast_matchers::integerLiteral;
28+
using clang::ast_matchers::match;
29+
using clang::ast_matchers::selectFirst;
30+
using clang::ast_matchers::stringLiteral;
31+
using clang::ast_matchers::varDecl;
32+
using clang::tooling::buildASTFromCode;
33+
using clang::tooling::buildASTFromCodeWithArgs;
34+
35+
template <typename Attr>
36+
testing::AssertionResult HasAttribute(const FunctionDecl *FD,
37+
const std::string attrName) {
38+
if (FD->hasAttr<Attr>())
39+
return testing::AssertionSuccess();
40+
41+
return testing::AssertionFailure()
42+
<< *FD << " doesn't have a " << attrName << " attribute";
43+
}
44+
45+
TEST(Attr, CHERICompartmentName) {
46+
// cheri_compartment name is a strange attribute which is both:
47+
//
48+
// * a function type attribute: affects the calling convention
49+
// * a function declaration attribute: marks the function as an compartment
50+
// entrypoint
51+
//
52+
// Thus this attribute is both handled by SemaType and SemaDeclAttr and in
53+
// order to not output twice a diagnosis we have to handle it specially. The
54+
// following test ensure we don't skip silently the attribute.
55+
56+
auto AST = buildASTFromCode(R"cpp(
57+
#define cheri_compartment(name) __attribute__((cheri_compartment(name)))
58+
#define default_compartment cheri_compartment("default_compartment")
59+
60+
void default_compartment f_00();
61+
default_compartment void f_01();
62+
default_compartment void *f_03();
63+
void default_compartment *f_04();
64+
void * default_compartment f_05();
65+
)cpp");
66+
67+
{
68+
for (auto Node : match(functionDecl().bind("fn"), AST->getASTContext())) {
69+
const FunctionDecl *FD = Node.getNodeAs<FunctionDecl>("fn");
70+
71+
EXPECT_TRUE(
72+
HasAttribute<CHERICompartmentNameAttr>(FD, "cheri_compartment"));
73+
};
74+
}
75+
}
76+
77+
} // namespace

0 commit comments

Comments
 (0)