Skip to content

[Clang][attr] Add 'cfi_salt' attribute #141846

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
Aug 14, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
bfdf16c
[Clang][attr] Add cfi_salt attribute
bwendling Apr 23, 2025
04d2c0b
Don't use AttributedType. Instead add it as a trailing object to the …
bwendling Jun 2, 2025
94d10c5
Merge branch 'main' into kcfi-salt
bwendling Jun 5, 2025
bbce666
Merge branch 'llvm:main' into kcfi-salt
bwendling Jun 25, 2025
e36bc7c
Merge branch 'llvm:main' into kcfi-salt
bwendling Jun 26, 2025
b0c8a2e
Merge branch 'llvm:main' into kcfi-salt
bwendling Jul 2, 2025
9e164e5
Merge branch 'llvm:main' into kcfi-salt
bwendling Jul 7, 2025
eef5f43
Reserve attribute to C-only and rename to 'kcfi_salt', indicating tha…
bwendling Jul 8, 2025
46d0edd
Alphabetize.
bwendling Jul 8, 2025
f4a54d9
Reformat.
bwendling Jul 8, 2025
e9aaaf5
Use correct preferred type and fix the attribute documentation.
bwendling Jul 17, 2025
0b13d3a
Merge branch 'llvm:main' into kcfi-salt
bwendling Jul 21, 2025
cec156a
Rename 'kcfi_salt' to 'cfi_salt' to indicate that it's not just for t…
bwendling Jul 23, 2025
44950cc
Reject function protos that have different cfi_salt values.
bwendling Jul 23, 2025
514523b
fixup! Reject function protos that have different cfi_salt values.
bwendling Jul 30, 2025
f74c5ea
Remove C++ test. Try to get along with only a 'TypeAttr' instead of '…
bwendling Jul 30, 2025
527297f
Use the modern syntax for the attribute. Remove the C++ mangled name …
bwendling Jul 30, 2025
2df94a9
Re-add attributes on function vars and decls.
bwendling Aug 1, 2025
66cb83b
Fix testcase.
bwendling Aug 1, 2025
516aa05
Add extra test.
bwendling Aug 1, 2025
1b1d3ab
Enhance the attribute docs.
bwendling Aug 1, 2025
6d00a7e
Use 'FunctionList' for the Subjects.
bwendling Aug 1, 2025
2e9022d
Use RST instead of MD.
bwendling Aug 1, 2025
7f2de1c
Improve docs. It was totally just me and not Claude rewriting it.
bwendling Aug 1, 2025
44c179d
Add missing backtick.
bwendling Aug 1, 2025
029ee8e
Add tests for a salt that's empty.
bwendling Aug 2, 2025
06e43bd
Change number of arguments check. Add test for it. And move the diagn…
bwendling Aug 4, 2025
132995f
Specify that we accept non-NULL ASCII strings.
bwendling Aug 11, 2025
cd975ea
Add a diagnostic for K&R-style functions without a prototype.
bwendling Aug 11, 2025
abe3bde
Improve the docs by explaining why the salt improves CFI safety.
bwendling Aug 12, 2025
c2dba02
Update clang/test/Sema/attr-cfi-salt.c
bwendling Aug 14, 2025
95698c2
Return 'true' when the argument type isn't a string.
bwendling Aug 14, 2025
09a446a
Merge branch 'main' into kcfi-salt
bwendling Aug 14, 2025
ae91164
Merge branch 'main' into kcfi-salt
bwendling Aug 14, 2025
9bd2c95
Reformat
bwendling Aug 14, 2025
9700cac
Add back accidentally removed code.
bwendling Aug 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 55 additions & 11 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -4631,6 +4631,9 @@ class FunctionType : public Type {
/// [implimits] 8 bits would be enough here.
unsigned NumExceptionType : 10;

LLVM_PREFERRED_TYPE(bool)
unsigned HasExtraAttributeInfo : 1;

LLVM_PREFERRED_TYPE(bool)
unsigned HasArmTypeAttributes : 1;

Expand All @@ -4639,14 +4642,26 @@ class FunctionType : public Type {
unsigned NumFunctionEffects : 4;

FunctionTypeExtraBitfields()
: NumExceptionType(0), HasArmTypeAttributes(false),
EffectsHaveConditions(false), NumFunctionEffects(0) {}
: NumExceptionType(0), HasExtraAttributeInfo(false),
HasArmTypeAttributes(false), EffectsHaveConditions(false),
NumFunctionEffects(0) {}
};

/// A holder for extra information from attributes which aren't part of an
/// \p AttributedType.
struct alignas(void *) FunctionTypeExtraAttributeInfo {
/// A CFI "salt" that differentiates functions with the same prototype.
StringRef CFISalt;

operator bool() const { return !CFISalt.empty(); }

void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddString(CFISalt); }
};

/// The AArch64 SME ACLE (Arm C/C++ Language Extensions) define a number
/// of function type attributes that can be set on function types, including
/// function pointers.
enum AArch64SMETypeAttributes : unsigned {
enum AArch64SMETypeAttributes : uint16_t {
SME_NormalFunction = 0,
SME_PStateSMEnabledMask = 1 << 0,
SME_PStateSMCompatibleMask = 1 << 1,
Expand Down Expand Up @@ -4676,11 +4691,11 @@ class FunctionType : public Type {
};

static ArmStateValue getArmZAState(unsigned AttrBits) {
return (ArmStateValue)((AttrBits & SME_ZAMask) >> SME_ZAShift);
return static_cast<ArmStateValue>((AttrBits & SME_ZAMask) >> SME_ZAShift);
}

static ArmStateValue getArmZT0State(unsigned AttrBits) {
return (ArmStateValue)((AttrBits & SME_ZT0Mask) >> SME_ZT0Shift);
return static_cast<ArmStateValue>((AttrBits & SME_ZT0Mask) >> SME_ZT0Shift);
}

/// A holder for Arm type attributes as described in the Arm C/C++
Expand All @@ -4689,6 +4704,7 @@ class FunctionType : public Type {
struct alignas(void *) FunctionTypeArmAttributes {
/// Any AArch64 SME ACLE type attributes that need to be propagated
/// on declarations and function pointers.
LLVM_PREFERRED_TYPE(uint16_t)
unsigned AArch64SMEAttributes : 9;

FunctionTypeArmAttributes() : AArch64SMEAttributes(SME_NormalFunction) {}
Expand Down Expand Up @@ -5170,6 +5186,7 @@ class FunctionProtoType final
private llvm::TrailingObjects<
FunctionProtoType, QualType, SourceLocation,
FunctionType::FunctionTypeExtraBitfields,
FunctionType::FunctionTypeExtraAttributeInfo,
FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType,
Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers,
FunctionEffect, EffectConditionExpr> {
Expand Down Expand Up @@ -5259,19 +5276,22 @@ class FunctionProtoType final
/// the various bits of extra information about a function prototype.
struct ExtProtoInfo {
FunctionType::ExtInfo ExtInfo;
Qualifiers TypeQuals;
RefQualifierKind RefQualifier = RQ_None;
ExceptionSpecInfo ExceptionSpec;
const ExtParameterInfo *ExtParameterInfos = nullptr;
SourceLocation EllipsisLoc;
FunctionEffectsRef FunctionEffects;
FunctionTypeExtraAttributeInfo ExtraAttributeInfo;

LLVM_PREFERRED_TYPE(bool)
unsigned Variadic : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned HasTrailingReturn : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned CFIUncheckedCallee : 1;
LLVM_PREFERRED_TYPE(uint16_t)
unsigned AArch64SMEAttributes : 9;
Qualifiers TypeQuals;
RefQualifierKind RefQualifier = RQ_None;
ExceptionSpecInfo ExceptionSpec;
const ExtParameterInfo *ExtParameterInfos = nullptr;
SourceLocation EllipsisLoc;
FunctionEffectsRef FunctionEffects;

ExtProtoInfo()
: Variadic(false), HasTrailingReturn(false), CFIUncheckedCallee(false),
Expand All @@ -5296,13 +5316,18 @@ class FunctionProtoType final
bool requiresFunctionProtoTypeExtraBitfields() const {
return ExceptionSpec.Type == EST_Dynamic ||
requiresFunctionProtoTypeArmAttributes() ||
requiresFunctionProtoTypeExtraAttributeInfo() ||
!FunctionEffects.empty();
}

bool requiresFunctionProtoTypeArmAttributes() const {
return AArch64SMEAttributes != SME_NormalFunction;
}

bool requiresFunctionProtoTypeExtraAttributeInfo() const {
return static_cast<bool>(ExtraAttributeInfo);
}

void setArmSMEAttribute(AArch64SMETypeAttributes Kind, bool Enable = true) {
if (Enable)
AArch64SMEAttributes |= Kind;
Expand All @@ -5328,6 +5353,11 @@ class FunctionProtoType final
return hasExtraBitfields();
}

unsigned
numTrailingObjects(OverloadToken<FunctionTypeExtraAttributeInfo>) const {
return hasExtraAttributeInfo();
}

unsigned numTrailingObjects(OverloadToken<ExceptionType>) const {
return getExceptionSpecSize().NumExceptionType;
}
Expand Down Expand Up @@ -5424,6 +5454,12 @@ class FunctionProtoType final

}

bool hasExtraAttributeInfo() const {
return FunctionTypeBits.HasExtraBitfields &&
getTrailingObjects<FunctionTypeExtraBitfields>()
->HasExtraAttributeInfo;
}

bool hasArmTypeAttributes() const {
return FunctionTypeBits.HasExtraBitfields &&
getTrailingObjects<FunctionTypeExtraBitfields>()
Expand Down Expand Up @@ -5457,6 +5493,7 @@ class FunctionProtoType final
EPI.TypeQuals = getMethodQuals();
EPI.RefQualifier = getRefQualifier();
EPI.ExtParameterInfos = getExtParameterInfosOrNull();
EPI.ExtraAttributeInfo = getExtraAttributeInfo();
EPI.AArch64SMEAttributes = getAArch64SMEAttributes();
EPI.FunctionEffects = getFunctionEffects();
return EPI;
Expand Down Expand Up @@ -5644,6 +5681,13 @@ class FunctionProtoType final
return getTrailingObjects<ExtParameterInfo>();
}

/// Return the extra attribute information.
FunctionTypeExtraAttributeInfo getExtraAttributeInfo() const {
if (hasExtraAttributeInfo())
return *getTrailingObjects<FunctionTypeExtraAttributeInfo>();
return FunctionTypeExtraAttributeInfo();
}

/// Return a bitmask describing the SME attributes on the function type, see
/// AArch64SMETypeAttributes for their values.
unsigned getAArch64SMEAttributes() const {
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -3843,6 +3843,13 @@ def CFICanonicalJumpTable : InheritableAttr {
let SimpleHandler = 1;
}

def CFISalt : DeclOrTypeAttr {
let Spellings = [Clang<"cfi_salt">];
let Args = [StringArgument<"Salt">];
let Subjects = SubjectList<[Function, Field, Var, TypedefName], ErrorDiag>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for missing this earlier, but should this be a TypeAttr and only apply to function types? I don't see any documentation or test cases for it being applied to a field, var, or typedef name.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are tests applying to a typedef, unless you mean the placement. But I think this is a relic of the original implementation where it the salt wasn't part of the FunctionType. I'll try to live without it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's specifically about the placement (it's complicated). If this is stuff you already know, feel free to ignore (not trying to mansplain, I just have no idea how much folks know about these kinds of details).

For attributes spelled with __attribute__(()), syntactic placement is not super critical because the attribute will "slide" around to whatever makes the most sense (declaration or type). But for attributes spelled with [[]], placement is actually critical to the semantics. The rules of thumb there are, the attribute appertains to whatever is immediately to the left of the attribute; if the attribute is at the start of the line then it is either a stand-alone attribute (like [[fallthrough]]) or appertains to each declaration in a declaration group. As a concrete example:

[[foo]] int func [[bar]] (int x) [[baz]];

foo appertains to the declaration func, the only thing in the declaration group. bar also applies to func (as a declaration attribute as well). There is no difference in semantics between how either of those attributes are applied; you could put [[foo, bar]] in either place and it would mean exactly the same thing. baz appertains to the type int (int).

So based on this previously being a DeclOrTypeAttr and the Subjects list, I would expect the following:

#define attr [[cfi_salt("I'm being lazy and using a macro")]]

attr void func(); // Appertains to the declaration of func
void func() attr; // Appertains to the type void()

attr int x, y, z; // Appertains to the declarations of x, y, and z
struct S {
  attr int x; // Appertains to the declaration of member x
};

typedef int attr foo; // Appertains to the type int, so anywhere you use foo, you get `int attr`.
typedef int bar attr; // Appertains to the declaration of foo, so anywhere you spell `bar`, you get `bar attr` which is an alias to type `int`

foo f;
bar b;
int i;
f = b; // Requires a conversion from `int` to `int attr`
i = b; // No conversions
i = f; // Requires a conversion from `int attr` to `int`

but this behavior is specific to [[]] spellings; for __attribute__ we could make different decisions if we wanted as to what the attribute actually appertains to.

With your latest changes to use TypeAttr, that will never apply to a declaration and so I think the Subjects list should be FunctionLike (only) because it applies to either function types or function pointer types. For the typedef case, that means:

typedef void (*fp)() attr; // Applies to the function pointer type
// Instead of:
typedef void (*fp attr)(); // Applies to the declaration of `foo`, which would be diagnosed as an ignored attribute

(Again, this is specific to the behavior with the [[]] spelling.)

CC @erichkeane as attributes code owner in case he disagrees with anything I'm saying above or has better explanations.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With your latest changes to use TypeAttr, that will never apply to a declaration and so I think the Subjects list should be FunctionLike (only) because it applies to either function types or function pointer types.

That limits some uses. @kees, is it okay to abandon these constructs?

typedef int (*fp_t)(void);

struct foo {
  fp_t __cfi_salt func;
};

void bar(fp_t __cfi_salt func) {}

Copy link
Collaborator

@AaronBallman AaronBallman Aug 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect those cases to work, at least with the [[]] spelling because that applies the attribute to the type spelled immediately on its left. Those should both resolve to fp_t __cfi_salt aka int (*)(void) __cfi_salt

https://godbolt.org/z/fY7jMGTsj is a similar example showing what I mean.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added them back.

let Documentation = [CFISaltDocs];
}

// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)
// Not all of these attributes will be given a [[]] spelling. The attributes
// which require access to function parameter names cannot use the [[]] spelling
Expand Down
58 changes: 58 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -3639,6 +3639,64 @@ make the function's CFI jump table canonical. See :ref:`the CFI documentation
}];
}

def CFISaltDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Use ``__attribute__((cfi_salt("<salt>")))`` on a function declaration, function
definition, or typedef to help distinguish CFI hashes between functions with
the same type signature.

Example use:

.. code-block:: c

// .h file:
#define __cfi_salt __attribute__((cfi_salt("vogon")))

// Convenient typedefs to avoid nested declarator syntax.
typedef int (*fptr_t)(void); // Non-salted function call.
typedef int (*fptr_salted_t)(void) __cfi_salt;

struct widget_generator {
fptr_t init;
fptr_salted_t exec;
fptr_t teardown;
};

// 1st .c file:
static int internal_init(void) { /* ... */ }
static int internal_salted_exec(void) __cfi_salt { /* ... */ }
static int internal_teardown(void) { /* ... */ }

static struct widget_generator _generator = {
.init = internal_init,
.exec = internal_salted_exec,
.teardown = internal_teardown,
}

struct widget_generator *widget_gen = _generator;

// 2nd .c file:
int generate_a_widget(void) {
int ret;

// Called with non-salted CFI.
ret = widget_gen.init();
if (ret)
return ret;

// Called with salted CFI.
ret = widget_gen.exec();
if (ret)
return ret;

// Called with non-salted CFI.
return widget_gen.teardown();
}

}];
}

def DocCatTypeSafety : DocumentationCategory<"Type Safety Checking"> {
let Content = [{
Clang supports additional attributes to enable checking type safety properties
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5055,10 +5055,12 @@ QualType ASTContext::getFunctionTypeInternal(
EPI.ExceptionSpec.Type, EPI.ExceptionSpec.Exceptions.size());
size_t Size = FunctionProtoType::totalSizeToAlloc<
QualType, SourceLocation, FunctionType::FunctionTypeExtraBitfields,
FunctionType::FunctionTypeExtraAttributeInfo,
FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType,
Expr *, FunctionDecl *, FunctionProtoType::ExtParameterInfo, Qualifiers,
FunctionEffect, EffectConditionExpr>(
NumArgs, EPI.Variadic, EPI.requiresFunctionProtoTypeExtraBitfields(),
EPI.requiresFunctionProtoTypeExtraAttributeInfo(),
EPI.requiresFunctionProtoTypeArmAttributes(), ESH.NumExceptionType,
ESH.NumExprPtr, ESH.NumFunctionDeclPtr,
EPI.ExtParameterInfos ? NumArgs : 0,
Expand Down
14 changes: 13 additions & 1 deletion clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3679,6 +3679,16 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
FunctionTypeBits.HasExtraBitfields = false;
}

// Propagate any extra attribute information.
if (epi.requiresFunctionProtoTypeExtraAttributeInfo()) {
auto &ExtraAttrInfo = *getTrailingObjects<FunctionTypeExtraAttributeInfo>();
ExtraAttrInfo.CFISalt = epi.ExtraAttributeInfo.CFISalt;

// Also set the bit in FunctionTypeExtraBitfields.
auto &ExtraBits = *getTrailingObjects<FunctionTypeExtraBitfields>();
ExtraBits.HasExtraAttributeInfo = true;
}

if (epi.requiresFunctionProtoTypeArmAttributes()) {
auto &ArmTypeAttrs = *getTrailingObjects<FunctionTypeArmAttributes>();
ArmTypeAttrs = FunctionTypeArmAttributes();
Expand Down Expand Up @@ -3896,7 +3906,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
// This is followed by the ext info:
// int
// Finally we have a trailing return type flag (bool)
// combined with AArch64 SME Attributes, to save space:
// combined with AArch64 SME Attributes and extra attribute info, to save
// space:
// int
// combined with any FunctionEffects
//
Expand Down Expand Up @@ -3931,6 +3942,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
}

epi.ExtInfo.Profile(ID);
epi.ExtraAttributeInfo.Profile(ID);

unsigned EffectCount = epi.FunctionEffects.size();
bool HasConds = !epi.FunctionEffects.Conditions.empty();
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2105,6 +2105,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::ExtVectorType:
OS << "ext_vector_type";
break;
case attr::CFISalt:
OS << "cfi_salt(\"" << cast<CFISaltAttr>(T->getAttr())->getSalt() << "\")";
break;
}
OS << "))";
}
Expand Down
14 changes: 10 additions & 4 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2896,10 +2896,16 @@ void CodeGenFunction::EmitSanitizerStatReport(llvm::SanitizerStatKind SSK) {

void CodeGenFunction::EmitKCFIOperandBundle(
const CGCallee &Callee, SmallVectorImpl<llvm::OperandBundleDef> &Bundles) {
const FunctionProtoType *FP =
Callee.getAbstractInfo().getCalleeFunctionProtoType();
if (FP)
Bundles.emplace_back("kcfi", CGM.CreateKCFITypeId(FP->desugar()));
const CGCalleeInfo &CI = Callee.getAbstractInfo();
const FunctionProtoType *FP = CI.getCalleeFunctionProtoType();
if (!FP)
return;

StringRef Salt;
if (const auto &Info = FP->getExtraAttributeInfo())
Salt = Info.CFISalt;

Bundles.emplace_back("kcfi", CGM.CreateKCFITypeId(FP->desugar(), Salt));
}

llvm::Value *
Expand Down
15 changes: 12 additions & 3 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2221,7 +2221,7 @@ llvm::ConstantInt *CodeGenModule::CreateCrossDsoCfiTypeId(llvm::Metadata *MD) {
return llvm::ConstantInt::get(Int64Ty, llvm::MD5Hash(MDS->getString()));
}

llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T) {
llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T, StringRef Salt) {
if (auto *FnType = T->getAs<FunctionProtoType>())
T = getContext().getFunctionType(
FnType->getReturnType(), FnType->getParamTypes(),
Expand All @@ -2232,6 +2232,9 @@ llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T) {
getCXXABI().getMangleContext().mangleCanonicalTypeName(
T, Out, getCodeGenOpts().SanitizeCfiICallNormalizeIntegers);

if (!Salt.empty())
Out << "." << Salt;

if (getCodeGenOpts().SanitizeCfiICallNormalizeIntegers)
Out << ".normalized";

Expand Down Expand Up @@ -2898,9 +2901,15 @@ void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) {
llvm::LLVMContext &Ctx = F->getContext();
llvm::MDBuilder MDB(Ctx);
llvm::StringRef Salt;

if (const auto *FP = FD->getType()->getAs<FunctionProtoType>())
if (const auto &Info = FP->getExtraAttributeInfo())
Salt = Info.CFISalt;

F->setMetadata(llvm::LLVMContext::MD_kcfi_type,
llvm::MDNode::get(
Ctx, MDB.createConstant(CreateKCFITypeId(FD->getType()))));
llvm::MDNode::get(Ctx, MDB.createConstant(CreateKCFITypeId(
FD->getType(), Salt))));
}

static bool allowKCFIIdentifier(StringRef Name) {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1616,7 +1616,7 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::ConstantInt *CreateCrossDsoCfiTypeId(llvm::Metadata *MD);

/// Generate a KCFI type identifier for T.
llvm::ConstantInt *CreateKCFITypeId(QualType T);
llvm::ConstantInt *CreateKCFITypeId(QualType T, StringRef Salt);

/// Create a metadata identifier for the given type. This may either be an
/// MDString (for external identifiers) or a distinct unnamed MDNode (for
Expand Down
16 changes: 16 additions & 0 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr,
case ParsedAttr::AT_ArmOut: \
case ParsedAttr::AT_ArmInOut: \
case ParsedAttr::AT_ArmAgnostic: \
case ParsedAttr::AT_CFISalt: \
case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: \
case ParsedAttr::AT_AnyX86NoCfCheck: \
CALLING_CONV_ATTRS_CASELIST
Expand Down Expand Up @@ -7943,6 +7944,21 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
return true;
}

if (attr.getKind() == ParsedAttr::AT_CFISalt) {
StringRef Argument;
if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
return false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be return true; returning false basically says "try to slide this attribute around to something else until it makes sense" but in this case the attribute is wrong and won't make sense anywhere.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah...I'm not sure why I missed that. Fixed.


const auto *FnTy = unwrapped.get()->getAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
EPI.ExtraAttributeInfo.CFISalt = Argument;

QualType newtype = S.Context.getFunctionType(FnTy->getReturnType(),
FnTy->getParamTypes(), EPI);
type = unwrapped.wrap(S, newtype->getAs<FunctionType>());
return true;
}

if (attr.getKind() == ParsedAttr::AT_ArmStreaming ||
attr.getKind() == ParsedAttr::AT_ArmStreamingCompatible ||
attr.getKind() == ParsedAttr::AT_ArmPreserves ||
Expand Down
Loading
Loading