Skip to content

Commit d0043d9

Browse files
[CHERI] Add a sealed type annotation (#109)
This allows us to disallow dereferences and pointer indexing on sealed capabilities at compile time. Builtins that introspect capabilities can all work on a sealed or unsealed capability. Builtins that mutate capabilities are all disallowed on sealed capabilities, with the exception of clear-tag (which works on sealed or unsealed things). Reinterpret cast and C-style (explicit) casts are allowed. Anyone who does an explicit unsafe cast should know what they're doing *anyway* this is another case of that. Implicit casts are also permitted to `void*`. This avoids needing new overloads for things that treat `void*` as opaque values. Casting back from `void*` to something useful already requires a dangerous explicit cast and you should know what you're doing if you do that. Also adds a __has_extension check for the sealed type qualifier. Co-authored-by: Owen Anderson <[email protected]>
1 parent 2cc9bfc commit d0043d9

38 files changed

+726
-363
lines changed

clang/include/clang/AST/Type.h

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,9 @@ enum PointerInterpretationKind {
15941594

15951595
/// The pointer should always be interpreted as an integer.
15961596
PIK_Integer,
1597+
1598+
/// The pointer should be interpreted as a sealed capability.
1599+
PIK_SealedCapability,
15971600
};
15981601

15991602
/// The base class of the type hierarchy.
@@ -1701,13 +1704,13 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
17011704
/// The interpretation to use for this array.
17021705
/// For function parameters only.
17031706
LLVM_PREFERRED_TYPE(PointerInterpretationKind)
1704-
unsigned PIK : 1;
1707+
unsigned PIK : 2;
17051708

17061709
/// Whether the pointer interpretation for this array is set.
17071710
LLVM_PREFERRED_TYPE(bool)
17081711
unsigned HasPIK : 1;
17091712
};
1710-
enum { NumArrayTypeBits = NumTypeBits + 8 };
1713+
enum { NumArrayTypeBits = NumTypeBits + 9 };
17111714

17121715
class ConstantArrayTypeBitfields {
17131716
friend class ConstantArrayType;
@@ -1814,7 +1817,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
18141817
unsigned : NumTypeBits;
18151818

18161819
/// The interpretation (PointerInterpretationKind) to use for this pointer.
1817-
unsigned PIK : 1;
1820+
unsigned PIK : 2;
18181821
};
18191822

18201823
class DependentPointerTypeBitfields {
@@ -1823,7 +1826,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
18231826
unsigned : NumTypeBits;
18241827

18251828
/// The interpretation (PointerInterpretationKind) to use for this pointer.
1826-
unsigned PIK : 1;
1829+
unsigned PIK : 2;
18271830
};
18281831

18291832
class ReferenceTypeBitfields {
@@ -1834,7 +1837,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
18341837

18351838
/// The interpretation (PointerInterpretationKind) to use for the pointer
18361839
/// backing this reference type.
1837-
unsigned PIK : 1;
1840+
unsigned PIK : 2;
18381841

18391842
/// True if the type was originally spelled with an lvalue sigil.
18401843
/// This is never true of rvalue references but can also be false
@@ -2321,6 +2324,9 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
23212324
/// pointers.
23222325
bool isCHERICapabilityType(const ASTContext &Context,
23232326
bool IncludeIntCap = true) const;
2327+
2328+
/// Returns true if this type is a Cheriot sealed capability.
2329+
bool isCHERISealedCapabilityType(const ASTContext &Context) const;
23242330
/// Returns true for __uintcap_t or __intcap_t (and enums/_Atomic with that
23252331
/// underlying type)
23262332
bool isIntCapType() const;
@@ -2974,7 +2980,8 @@ class PointerInterpretationTrait {
29742980

29752981
public:
29762982
bool isCHERICapability() const {
2977-
return getPointerInterpretation() == PIK_Capability;
2983+
return getPointerInterpretation() == PIK_Capability ||
2984+
getPointerInterpretation() == PIK_SealedCapability;
29782985
}
29792986

29802987
PointerInterpretationKind getPointerInterpretation() const {
@@ -2990,7 +2997,8 @@ class OptionalPointerInterpretationTrait {
29902997

29912998
public:
29922999
bool isCHERICapability() const {
2993-
return getPointerInterpretation() == PIK_Capability;
3000+
return getPointerInterpretation() == PIK_Capability ||
3001+
getPointerInterpretation() == PIK_SealedCapability;
29943002
}
29953003

29963004
std::optional<PointerInterpretationKind> getPointerInterpretation() const {

clang/include/clang/Basic/Attr.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,11 @@ def MinimumStack : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
911911
let Documentation = [Undocumented];
912912
}
913913

914+
def CHERISealedCapability : TypeAttr {
915+
let Spellings = [CustomKeyword<"__sealed_capability">];
916+
let Documentation = [Undocumented];
917+
}
918+
914919
def InterruptState : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
915920
let Spellings = [CXX11<"cheriot", "interrupt_state">,
916921
C23<"cheriot", "interrupt_state">,

clang/include/clang/Basic/Builtins.def

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
// D -> volatile
7373
// R -> restrict
7474
// m -> memory capability
75+
// l -> sealed capability
7576

7677
// The third value provided to the macro specifies information about attributes
7778
// of the function. These must be kept in sync with the predicates in the
@@ -1737,17 +1738,17 @@ BUILTIN(__builtin_cheri_offset_set, "v*mvC*mY", "nct")
17371738
BUILTIN(__builtin_cheri_perms_and, "v*mvC*mz", "nct")
17381739
BUILTIN(__builtin_cheri_perms_check, "vvC*mCz", "nct")
17391740
BUILTIN(__builtin_cheri_perms_get, "zvC*m", "nct")
1740-
BUILTIN(__builtin_cheri_seal, "v*mvC*mvC*m", "nct")
1741-
BUILTIN(__builtin_cheri_seal_entry, "v*mvC*m", "nct")
1742-
BUILTIN(__builtin_cheri_sealed_get, "bvC*m", "nct")
1741+
BUILTIN(__builtin_cheri_seal, "v*lvC*mvC*m", "nct")
1742+
BUILTIN(__builtin_cheri_seal_entry, "v*lvC*m", "nct")
1743+
BUILTIN(__builtin_cheri_sealed_get, "bvC*l", "nct")
17431744
BUILTIN(__builtin_cheri_subset_test, "bvC*mvC*m", "nct")
17441745
BUILTIN(__builtin_cheri_tag_clear, "v*mvC*m", "nct")
17451746
BUILTIN(__builtin_cheri_tag_get, "bvC*m", "nct")
17461747
BUILTIN(__builtin_cheri_tag_get_temporal, "bvC*m", "nct")
17471748
BUILTIN(__builtin_cheri_top_get, "zvC*m", "nct")
17481749
BUILTIN(__builtin_cheri_type_check, "vvC*mvC*m", "nct")
17491750
BUILTIN(__builtin_cheri_type_get, "YvC*m", "nct")
1750-
BUILTIN(__builtin_cheri_unseal, "v*mvC*mvC*m", "nct")
1751+
BUILTIN(__builtin_cheri_unseal, "v*mvC*lvC*m", "nct")
17511752

17521753
BUILTIN(__builtin_cheri_callback_create, "v.", "nct")
17531754

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,8 @@ def err_expected_selector_for_method : Error<
325325
"expected selector for Objective-C method">;
326326
def err_expected_property_name : Error<"expected property name">;
327327

328-
def warn_cheri_capability_qualifier_location : Warning<
329-
"use of __capability before the pointer type is deprecated">,
328+
def warn_cheri_qualifier_location : Warning<
329+
"use of %0 before the pointer type is deprecated">,
330330
InGroup<DeprecatedDeclarations>;
331331

332332
def err_unexpected_at : Error<"unexpected '@' in program">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,10 +1388,22 @@ def note_cheri_func_decl_add_types : Note<
13881388
def err_cheri_capability_qualifier_not_supported : Error<
13891389
"use of __capability is not supported without CHERI; "
13901390
"specify an appropriate -march= or -mcpu=">;
1391-
def err_cheri_capability_qualifier_ambiguous : Error<
1392-
"use of __capability is ambiguous">;
1393-
def err_cheri_capability_qualifier_pointers_only : Error<
1394-
"__capability only applies to pointers; type here is %0">;
1391+
def err_cheri_sealed_qualifier_not_supported : Error<
1392+
"use of __sealed_capability is not supported without CHERI; "
1393+
"specify an appropriate -march= or -mcpu=">;
1394+
def err_cheri_qualifier_ambiguous : Error<
1395+
"use of %0 is ambiguous">;
1396+
def err_cheri_qualifier_pointers_only : Error<
1397+
"%0 only applies to pointers; type here is %1">;
1398+
def err_bad_cxx_cast_sealed_qualifier : Error<
1399+
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
1400+
"functional-style cast|addrspace_cast}0 from %1 to %2 changes sealed qualifier">;
1401+
def err_sealed_pointer_cast : Error<
1402+
"cast from %0 to %1 changes sealed qualifier">;
1403+
def err_typecheck_expect_sealed_operand : Error<
1404+
"operand of type %0 where sealed capability is required">;
1405+
def err_typecheck_expect_unsealed_operand : Error<
1406+
"operand of type %0 where unsealed capability is required">;
13951407

13961408
def err_objc_var_decl_inclass :
13971409
Error<"cannot declare variable inside @interface or @protocol">;
@@ -7470,6 +7482,20 @@ def err_typecheck_convert_ptr_to_cap_unrelated_type: Error<"cannot implicitly "
74707482
"or explicitly convert non-capability%select{| reference to}2 type %0 to "
74717483
"unrelated capability type %1">;
74727484

7485+
def err_typecheck_convert_sealed_to_ptr: Error<"converting sealed"
7486+
"%select{| reference to}2 type %0 to non-sealed type %1 without "
7487+
"an explicit unsealing">;
7488+
def err_typecheck_convert_ptr_to_sealed: Error<"converting unsealed"
7489+
"%select{| reference to}2 type %0 to sealed type %1 without "
7490+
"an explicit sealing">;
7491+
def err_sealed_reference: Error<"reference type %0 cannot be sealed">;
7492+
def err_sealed_bad_operator: Error<"invalid operator applied to sealed type %0">;
7493+
def err_sealed_this_pointer: Error<"sealed type %0 cannot be used as 'this' pointer for non-static method calls">;
7494+
def err_sealed_func_pointer: Error<"sealed type %0 cannot be called">;
7495+
def err_sealed_member_access: Error<"cannot access members of sealed type %0">;
7496+
7497+
7498+
74737499
def warn_uintcap_bitwise_and : Warning<
74747500
"using bitwise and on a capability type may give surprising results; "
74757501
"if this is an alignment check use __builtin_{is_aligned,align_up,align_down}(); "

clang/include/clang/Basic/Features.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ FEATURE(experimental_library, LangOpts.ExperimentalLibrary)
245245
FEATURE(capabilities, PP.getTargetInfo().SupportsCapabilities())
246246
FEATURE(pointer_interpretation, PP.getTargetInfo().SupportsCapabilities())
247247
FEATURE(cheri_casts, PP.getTargetInfo().SupportsCapabilities())
248+
// CHERI typed sealed pointers
249+
EXTENSION(cheri_sealed_pointers, PP.getTargetInfo().SupportsCapabilities())
248250

249251
// C11 features supported by other languages as extensions.
250252
EXTENSION(c_alignas, true)

clang/include/clang/Basic/TokenKinds.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,9 @@ KEYWORD(__cheri_input , KEYALL)
344344
// CHERIoT Predefine Expr
345345
KEYWORD(__cheriot_minimum_stack__ , KEYALL)
346346

347+
// Cheriot Qualifiers
348+
KEYWORD(__sealed_capability , KEYALL)
349+
347350
// C++ 2.11p1: Keywords.
348351
KEYWORD(asm , KEYCXX|KEYGNU)
349352
KEYWORD(bool , BOOLSUPPORT|KEYC23)

clang/include/clang/Parse/Parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3002,6 +3002,7 @@ class Parser : public CodeCompletionHandler {
30023002
void ParseOpenCLQualifiers(ParsedAttributes &Attrs);
30033003
void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs);
30043004
void ParseCapabilityQualifier(ParsedAttributes &Attrs);
3005+
void ParseCheriotSealedQualifier(ParsedAttributes &Attrs);
30053006
void ParseCUDAFunctionAttributes(ParsedAttributes &attrs);
30063007
bool isHLSLQualifier(const Token &Tok) const;
30073008
void ParseHLSLQualifiers(ParsedAttributes &Attrs);

clang/lib/AST/ASTContext.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11742,14 +11742,15 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
1174211742
case 'R':
1174311743
Type = Type.withRestrict();
1174411744
break;
11745+
case 'l':
1174511746
case 'm': {
1174611747
Qualifiers Qs = Type.getQualifiers();
1174711748
if (const auto *PT = Type->getAs<PointerType>())
1174811749
Type = Context.getPointerType(PT->getPointeeType(), PIK_Capability);
1174911750
else if (const auto *LRT = Type->getAs<LValueReferenceType>())
11750-
Type = Context.getLValueReferenceType(LRT->getPointeeTypeAsWritten(),
11751-
LRT->isSpelledAsLValue(),
11752-
PIK_Capability);
11751+
Type = Context.getLValueReferenceType(
11752+
LRT->getPointeeTypeAsWritten(), LRT->isSpelledAsLValue(),
11753+
c == 'l' ? PIK_SealedCapability : PIK_Capability);
1175311754
else {
1175411755
const auto *BT = Type->getAs<BuiltinType>();
1175511756
assert(BT &&

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3771,7 +3771,10 @@ void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) {
37713771

37723772
// <type> ::= P <type> # pointer-to
37733773
void CXXNameMangler::mangleType(const PointerType *T) {
3774-
if (Context.shouldMangleCapabilityQualifier() && T->isCHERICapability())
3774+
if (T->getPointerInterpretation() == PIK_SealedCapability)
3775+
Out << "U19__sealed_capability";
3776+
else if (Context.shouldMangleCapabilityQualifier() &&
3777+
T->getPointerInterpretation() == PIK_Capability)
37753778
Out << "U12__capability";
37763779
Out << 'P';
37773780
mangleType(T->getPointeeType());
@@ -3783,16 +3786,21 @@ void CXXNameMangler::mangleType(const ObjCObjectPointerType *T) {
37833786

37843787
// <type> ::= R <type> # reference-to
37853788
void CXXNameMangler::mangleType(const LValueReferenceType *T) {
3786-
if (Context.shouldMangleCapabilityQualifier() && T->isCHERICapability())
3789+
if (T->getPointerInterpretation() == PIK_SealedCapability)
3790+
Out << "U19__sealed_capability";
3791+
else if (Context.shouldMangleCapabilityQualifier() &&
3792+
T->getPointerInterpretation() == PIK_Capability)
37873793
Out << "U12__capability";
37883794
Out << 'R';
37893795
mangleType(T->getPointeeType());
37903796
}
37913797

37923798
// <type> ::= O <type> # rvalue reference-to (C++0x)
37933799
void CXXNameMangler::mangleType(const RValueReferenceType *T) {
3794-
if (Context.shouldMangleCapabilityQualifier() && T->isCHERICapability())
3800+
if (Context.shouldMangleCapabilityQualifier() && T->isCHERICapability()) {
3801+
assert(T->getPointerInterpretation() != PIK_SealedCapability);
37953802
Out << "U12__capability";
3803+
}
37963804
Out << 'O';
37973805
mangleType(T->getPointeeType());
37983806
}
@@ -4243,7 +4251,10 @@ void CXXNameMangler::mangleType(const DependentAddressSpaceType *T) {
42434251
}
42444252

42454253
void CXXNameMangler::mangleType(const DependentPointerType *T) {
4246-
if (Context.shouldMangleCapabilityQualifier() && T->isCHERICapability())
4254+
if (T->getPointerInterpretation() == PIK_SealedCapability)
4255+
Out << "U19__sealed_capability";
4256+
else if (Context.shouldMangleCapabilityQualifier() &&
4257+
T->getPointerInterpretation() == PIK_Capability)
42474258
Out << "U12__capability";
42484259
mangleType(T->getPointerType());
42494260
}

0 commit comments

Comments
 (0)