[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-09-17 Thread Bill Wendling via cfe-commits

bwendling wrote:

> Maybe nice to call it kcfi_sault?
> 
> -fsanitize=kcfi is completely different from -fsanitize=cfi, so it would be 
> consistent to keep the convention in attributes as well.

A few people suggested naming it `cfi_salt` because it could be used in other 
contexts:

https://github.com/llvm/llvm-project/pull/141846#issuecomment-3085340995
https://github.com/llvm/llvm-project/pull/141846#issuecomment-3085354901

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-09-17 Thread Vitaly Buka via cfe-commits

vitalybuka wrote:

Maybe nice to call it kcfi_sault?

-fsanitize=kcfi is completely different from -fsanitize=cfi, so it would be 
consistent to keep the convention in attributes as well.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-14 Thread Bill Wendling via cfe-commits

bwendling wrote:

Fixed:

To https://github.com/llvm/llvm-project.git
   76dd742f7b32..1e9fc8edd037  main -> main


https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-14 Thread LLVM Continuous Integration via cfe-commits

llvm-ci wrote:

LLVM Buildbot has detected a new failure on builder 
`llvm-clang-x86_64-sie-ubuntu-fast` running on `sie-linux-worker` while 
building `clang` at step 6 "test-build-unified-tree-check-all".

Full details are available at: 
https://lab.llvm.org/buildbot/#/builders/144/builds/32827


Here is the relevant piece of the build log for the reference

```
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
 TEST 'Clang :: Sema/attr-cfi-salt.c' FAILED 

Exit Code: 1

Command Output (stderr):
--
/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang 
-cc1 -internal-isystem 
/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/22/include
 -nostdsysteminc -fsyntax-only -fsanitize=kcfi -verify 
/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/attr-cfi-salt.c
 # RUN: at line 1
+ 
/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang 
-cc1 -internal-isystem 
/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/22/include
 -nostdsysteminc -fsyntax-only -fsanitize=kcfi -verify 
/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/attr-cfi-salt.c
error: 'expected-warning' diagnostics seen but not expected: 
  File 
/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/attr-cfi-salt.c
 Line 16: redefinition of typedef 'bar_t' is a C11 feature
error: 'expected-note' diagnostics seen but not expected: 
  File 
/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/Sema/attr-cfi-salt.c
 Line 15: previous definition is here
2 errors generated.

--




```



https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-14 Thread Bill Wendling via cfe-commits

https://github.com/bwendling closed 
https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-14 Thread Bill Wendling via cfe-commits

https://github.com/bwendling edited 
https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-08 Thread Kees Cook via cfe-commits


@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -fsyntax-only -fsanitize=kcfi -verify %s
+
+#define __cfi_salt(S) __attribute__((cfi_salt(S)))
+
+int bad1() __cfi_salt(); // expected-error{{'cfi_salt' attribute takes one 
argument}}
+int bad2() __cfi_salt(42); // expected-error{{expected string literal as 
argument of 'cfi_salt' attribute}}
+int bad3() __attribute__((cfi_salt("a", "b", "c"))); // 
expected-error{{'cfi_salt' attribute takes one argument}}

kees wrote:

> I think non-null ASCII characters would be good

Agreed: It can both be included in the existing mangle string -> hash step, and 
I expect this to be a "meaningful" string for authors to use (e.g. "sched" or 
"kvm") etc.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-05 Thread Erich Keane via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.
+StringRef Argument;
+if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
+  return false;
+
+// Delay if this is not a function type.
+if (!unwrapped.isFunctionType())
+  return false;
+
+const auto *FnTy = unwrapped.get()->getAs();
+if (!FnTy)

erichkeane wrote:

Ah, hrmph, that is unfortunate.  I'd at least like a test to show that it 
diagnoses for non-prototype functions (even if it doesn't need to be diagnosed 
here because TG takes care of it).

Perhaps at one point we SHOULD start automatically pulling stuff from TG 
here/automating better.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-05 Thread Aaron Ballman via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.
+StringRef Argument;
+if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
+  return false;
+
+// Delay if this is not a function type.
+if (!unwrapped.isFunctionType())
+  return false;
+
+const auto *FnTy = unwrapped.get()->getAs();
+if (!FnTy)

AaronBallman wrote:

>  I wouldn't expect an attribute that doesn't pass the builtin-TableGen'd 
> stuff to reach this function (like for arg counts/appertainment/etc), so if 
> this IS getting here, it either needs to diagnose here, or figure out WHY 
> we're continuing after failing tablegen.

Type attributes do not have as much automagical hookup with tablegen as 
declaration attributes; so IIRC all of them have to do manual processing like 
this. So I do expect to get here (at least, with my psychic debugger), and I 
think we likely need to diagnose explicitly.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-05 Thread Erich Keane via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.
+StringRef Argument;
+if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
+  return false;
+
+// Delay if this is not a function type.
+if (!unwrapped.isFunctionType())
+  return false;
+
+const auto *FnTy = unwrapped.get()->getAs();
+if (!FnTy)

erichkeane wrote:

Huh, interesting, I could have sworn we had a different location for 
no-prototype-attribute handling, but I don't think so anymore (after digging in 
for a few mins).

My bullets still are relevant.  I wouldn't expect an attribute that doesn't 
pass the builtin-TableGen'd stuff to reach this function (like for arg 
counts/appertainment/etc), so if this _IS_ getting here, it either needs to 
diagnose here, or figure out WHY we're continuing after failing tablegen.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-05 Thread Aaron Ballman via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.
+StringRef Argument;
+if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
+  return false;
+
+// Delay if this is not a function type.
+if (!unwrapped.isFunctionType())
+  return false;
+
+const auto *FnTy = unwrapped.get()->getAs();
+if (!FnTy)

AaronBallman wrote:

>From my look at the code paths, I think you can get here with a function 
>without a prototype. For example, this function handles noreturn too, yet: 
>https://godbolt.org/z/q895rn3zr

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-05 Thread Erich Keane via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.
+StringRef Argument;
+if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
+  return false;
+
+// Delay if this is not a function type.
+if (!unwrapped.isFunctionType())
+  return false;
+
+const auto *FnTy = unwrapped.get()->getAs();
+if (!FnTy)

erichkeane wrote:

It DOES look like that, but he is perhaps correct that `handleFunctionTypeAttr` 
only works on prototype-functions?  I just want to make sure that we either:
- diagnose (not silently ignore) here 
- Are already diagnosing elsewhere and don't get here in this case, at which 
point this could be a `castAs`
- Diagnose elsewhere, BUT still get here: we should perhaps understand how that 
happens.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-05 Thread Erich Keane via cfe-commits


@@ -7941,6 +7942,31 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() != 1)

erichkeane wrote:

I'm still a little surprised we actually GET to this.  I would expect whoever 
does the diagnostic here should ensure we don't get to this attribute, and I'd 
like us to understand why that is (that is, that this can get here).

I realize this is all OLD code (this function) that likely was written with 
different expectations, so I want to make sure we're not using those for not a 
good reason.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-05 Thread Aaron Ballman via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.
+StringRef Argument;
+if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
+  return false;
+
+// Delay if this is not a function type.
+if (!unwrapped.isFunctionType())
+  return false;
+
+const auto *FnTy = unwrapped.get()->getAs();
+if (!FnTy)

AaronBallman wrote:

I think what's being asked for is a test case like:
```
// RUN: %clang_cc1 -std=c89 -fsyntax-only -fsanitize=kcfi -verify %s

// K&R C function without a prototype
void func() __attribute__((cfi_salt("pepper"))); // expected-error {{attribute 
only applies to function types with a prototype}}

void (*fp)() __attribute__((cfi_salt("pepper")));  // expected-error 
{{attribute only applies to function pointer types with a prototype}}
```
(or something along those lines). As it stands, it looks like this code will 
silently drop the attribute because `getAs` will return null and we'll early 
return here.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-05 Thread Aaron Ballman via cfe-commits


@@ -3643,6 +3643,95 @@ make the function's CFI jump table canonical. See 
:ref:`the CFI documentation
   }];
 }
 
+def CFISaltDocs : Documentation {
+  let Category = DocCatFunction;
+  let Heading = "cfi_salt";
+  let Label = "langext-cfi_salt";
+  let Content = [{
+The ``cfi_salt`` attribute allows you to add a salt value to Control Flow 
+Integrity (CFI) type hashes to help distinguish between functions with the 
+same type signature. This attribute can be applied to function declarations, 
+function definitions, and function pointer typedefs.
+
+**Syntax:**
+
+* GNU-style: ``__attribute__((cfi_salt("")))``
+* C++11-style: ``[[clang::cfi_salt("")]]``
+
+**Usage:**
+
+The attribute takes a single string literal argument that serves as the salt.
+Functions or function types with different salt values will have different CFI
+hashes, even if they have identical type signatures.
+
+**Motivation:**
+
+In large codebases like the Linux kernel, there are often hundreds of functions
+with identical type signatures that are called indirectly:
+
+.. code-block::
+
+  1662 functions with void (*)(void)
+  1179 functions with int (*)(void)
+   ...
+
+By salting the CFI hashes, you can make CFI more robust by ensuring that
+functions intended for different purposes have distinct CFI identities.
+
+**Type Compatibility:**
+
+* Functions with different salt values are considered to have incompatible 
types
+* Function pointers with different salt values cannot be assigned to each other
+* All declarations of the same function must use the same salt value
+
+**Example:**
+
+.. code-block:: c
+
+  // Header file - define convenience macros
+  #define __cfi_salt(s) __attribute__((cfi_salt(s)))
+  
+  // Typedef for regular function pointers
+  typedef int (*fptr_t)(void);
+  
+  // Typedef for salted function pointers  
+  typedef int (*fptr_salted_t)(void) __cfi_salt("pepper");
+  
+  struct widget_ops {
+fptr_t init;  // Regular CFI
+fptr_salted_t exec;   // Salted CFI
+fptr_t cleanup;   // Regular CFI
+  };
+  
+  // Function implementations
+  static int widget_init(void) { return 0; }
+  static int widget_exec(void) __cfi_salt("pepper") { return 1; }
+  static int widget_cleanup(void) { return 0; }
+  
+  static struct widget_ops ops = {
+.init = widget_init,  // OK - compatible types
+.exec = widget_exec,  // OK - both use "pepper" salt
+.cleanup = widget_cleanup // OK - compatible types
+  };
+  
+  // Using C++11 attribute syntax
+  void secure_callback(void) [[clang::cfi_salt("secure")]];
+  
+  // This would cause a compilation error:
+  // fptr_t bad_ptr = widget_exec;  // Error: incompatible types
+
+**Notes:**
+
+* The salt string can contain any characters, including spaces and quotes

AaronBallman wrote:

I think non-null ASCII characters would be good; we can basically claim it is a 
bucket of non-zero bytes more than a textual string, really. Or, maybe the salt 
should be a 64-bit numeric value? e.g., `__cfi_salt(0xDEADBEEF)` (If that's a 
dumb suggestion, feel free to ignore it, I'm not certain what the backend wants 
to do with the string itself.)

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-05 Thread Aaron Ballman via cfe-commits


@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -fsyntax-only -fsanitize=kcfi -verify %s
+
+#define __cfi_salt(S) __attribute__((cfi_salt(S)))
+
+int bad1() __cfi_salt(); // expected-error{{'cfi_salt' attribute takes one 
argument}}
+int bad2() __cfi_salt(42); // expected-error{{expected string literal as 
argument of 'cfi_salt' attribute}}
+int bad3() __attribute__((cfi_salt("a", "b", "c"))); // 
expected-error{{'cfi_salt' attribute takes one argument}}

AaronBallman wrote:

```suggestion
int bad1(void) __cfi_salt(); // expected-error{{'cfi_salt' attribute takes one 
argument}}
int bad2(void) __cfi_salt(42); // expected-error{{expected string literal as 
argument of 'cfi_salt' attribute}}
int bad3(void) __attribute__((cfi_salt("a", "b", "c"))); // 
expected-error{{'cfi_salt' attribute takes one argument}}
```
This makes it more clear as to what's being tested (it's not the function 
prototype that matters for these tests, it's the attribute argument list).

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits

bwendling wrote:

> > You need to realize that submitted this code for review in May. It's like 
> > that I forgot some of the details of why I wrote something. But what I 
> > wrote was intentionally put there for a reason.
> > There's a new commit. PTAL.
> 
> Honestly, this is a case where I was heavily unmotivated to review your code 
> due to past behavior, and didn't until asked explicitly by Aaron. It waited 
> due to your inability to respect reviewers in the past.

I'm sorry for my behavior. I don't intend to be confrontational, but people 
keep arguing with me about code that I've written intentionally to avoid ICEs 
and the like. But when you wrote this:

> EITHER:
> 1- You're not assuming anything, thus this check should diagnose incorrect 
> argument count.
> 2- This is a 'dead' branch, and should just be an assume.

I found it insulting and lost my temper, because I understood what you're said 
before this. I shouldn't have, but really I know why you want asserts there. I 
didn't make it an assert because it would ICE otherwise.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits

erichkeane wrote:

> You need to realize that submitted this code for review in May. It's like 
> that I forgot some of the details of why I wrote something. But what I wrote 
> was intentionally put there for a reason.
> 
> There's a new commit. PTAL.

Honestly, this is a case where I was heavily unmotivated to review your code 
due to past behavior, and didn't until asked explicitly by Aaron.  It waited 
due to your inability to respect reviewers in the past.



> And if you're flagging this for "changes required", please list those changes.

Due to me "lacking a fundamental understanding of the code" I need to spend 
extensive amounts of time familiarizing myself with "the code" before I can 
release this review.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits

bwendling wrote:

And if you're flagging this for "changes required", please list those changes.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits

bwendling wrote:

You need to realize that submitted this code for review in May. It's like that 
I forgot some of the details of why I wrote something. But what I wrote was 
intentionally put there for a reason.

There's a new commit. PTAL.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.
+StringRef Argument;
+if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
+  return false;
+
+// Delay if this is not a function type.
+if (!unwrapped.isFunctionType())
+  return false;
+
+const auto *FnTy = unwrapped.get()->getAs();
+if (!FnTy)

bwendling wrote:

The thing with this code is that we catch the situations we want it to catch 
and give out other warning messages. Specifically, a function with a different 
attribute in the prototype. A function that doesn't have a prototype is already 
handled by the compiler. There's no change needed here.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits

bwendling wrote:

> Removing my approval-- I thought the changes requested were nits, but amount 
> of discussion shows that was not true.

Wrong. They aren't nits. It's just you lacking a fundamental understanding of 
the code. Sorry for the confusion, but I wrote the code to avoid ICEs. I don't 
simply go around adding dead paths to code.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits

https://github.com/erichkeane requested changes to this pull request.

Removing my approval-- I thought the changes requested were nits, but amount of 
discussion shows that was not true.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)

erichkeane wrote:

What is 'it' in that sentence?  What part asserts?  What example gets here 
without the correct argument count from tablegen?

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits

https://github.com/bwendling edited 
https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)

bwendling wrote:

The code is necessary. If it's not there, it asserts, if an assert, it asserts, 
if it's there the error is printed. So let's just leave it as is.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits

https://github.com/bwendling deleted 
https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)

bwendling wrote:

In fact, it's checked elsewhere, so I'll simply remove it. No need for argument 
number checking here or an assert.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)

erichkeane wrote:

AS written, you're assuming an attribute can get to this point with `0` 
arguments.  I'm saying: IF that is ACTUALLY possible, you need to diagnose.  
SINCE it isn't (I'm quite sure!), this is a dead branch, and thus should be an 
assert, since it is something you're assuming.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)

bwendling wrote:

Of course I'm not assuming anything. I'm not sure what you're getting at. I'll 
make it more explicit.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.
+StringRef Argument;
+if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
+  return false;
+
+// Delay if this is not a function type.
+if (!unwrapped.isFunctionType())
+  return false;
+
+const auto *FnTy = unwrapped.get()->getAs();
+if (!FnTy)

erichkeane wrote:

Exactly :)  In reality, 7958 should be a `castAs`, not a `getAs`.  

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.
+StringRef Argument;
+if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
+  return false;
+
+// Delay if this is not a function type.
+if (!unwrapped.isFunctionType())
+  return false;
+
+const auto *FnTy = unwrapped.get()->getAs();
+if (!FnTy)

bwendling wrote:

Well, the `FnTy` is a `FunctionProtoType`, which is what holds the information. 
If you want an example, look at the attribute handling below this code. 
However, I'm not able to trigger this code path. I suppose I can remove it if 
you like.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)

erichkeane wrote:

The point of assertions is to assert-based-on your assumptions.  

EITHER:
1- You're not assuming anything, thus this check should diagnose incorrect 
argument count.
2- This is a 'dead' branch, and should just be an assume.


https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.
+StringRef Argument;
+if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
+  return false;
+
+// Delay if this is not a function type.
+if (!unwrapped.isFunctionType())
+  return false;
+
+const auto *FnTy = unwrapped.get()->getAs();
+if (!FnTy)

erichkeane wrote:

Then my question is: why the `if(!FnTy)`?  Do we have a case where this matters?

Likely a few of the `return`s here should just be asserts.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.
+StringRef Argument;
+if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
+  return false;
+
+// Delay if this is not a function type.
+if (!unwrapped.isFunctionType())
+  return false;
+
+const auto *FnTy = unwrapped.get()->getAs();
+if (!FnTy)

bwendling wrote:

The attribute is accessible only via the `FunctionProtoType`. To be more 
accurate, it really needs to be on `extern` function forward decls and the 
definition, because otherwise the attribute won't propagate correctly.

I'll add a test case to ensure this.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.

bwendling wrote:

Not sure what I was doing there...copy-n-paste error I guess. :-)

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)

bwendling wrote:

> Perhaps? Alternatively, should this be an `assert(attr.getNumArgs() == 1)` ?

I don't want to do that in Sema. The check will go away in a non-Assert-Release 
build. And the compiler shouldn't ICE just because someone accidentally added 
an extra argument.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Bill Wendling via cfe-commits


@@ -3643,6 +3643,95 @@ make the function's CFI jump table canonical. See 
:ref:`the CFI documentation
   }];
 }
 
+def CFISaltDocs : Documentation {
+  let Category = DocCatFunction;
+  let Heading = "cfi_salt";
+  let Label = "langext-cfi_salt";
+  let Content = [{
+The ``cfi_salt`` attribute allows you to add a salt value to Control Flow 
+Integrity (CFI) type hashes to help distinguish between functions with the 
+same type signature. This attribute can be applied to function declarations, 
+function definitions, and function pointer typedefs.
+
+**Syntax:**
+
+* GNU-style: ``__attribute__((cfi_salt("")))``
+* C++11-style: ``[[clang::cfi_salt("")]]``
+
+**Usage:**
+
+The attribute takes a single string literal argument that serves as the salt.
+Functions or function types with different salt values will have different CFI
+hashes, even if they have identical type signatures.
+
+**Motivation:**
+
+In large codebases like the Linux kernel, there are often hundreds of functions
+with identical type signatures that are called indirectly:
+
+.. code-block::
+
+  1662 functions with void (*)(void)
+  1179 functions with int (*)(void)
+   ...
+
+By salting the CFI hashes, you can make CFI more robust by ensuring that
+functions intended for different purposes have distinct CFI identities.
+
+**Type Compatibility:**
+
+* Functions with different salt values are considered to have incompatible 
types
+* Function pointers with different salt values cannot be assigned to each other
+* All declarations of the same function must use the same salt value
+
+**Example:**
+
+.. code-block:: c
+
+  // Header file - define convenience macros
+  #define __cfi_salt(s) __attribute__((cfi_salt(s)))
+  
+  // Typedef for regular function pointers
+  typedef int (*fptr_t)(void);
+  
+  // Typedef for salted function pointers  
+  typedef int (*fptr_salted_t)(void) __cfi_salt("pepper");
+  
+  struct widget_ops {
+fptr_t init;  // Regular CFI
+fptr_salted_t exec;   // Salted CFI
+fptr_t cleanup;   // Regular CFI
+  };
+  
+  // Function implementations
+  static int widget_init(void) { return 0; }
+  static int widget_exec(void) __cfi_salt("pepper") { return 1; }
+  static int widget_cleanup(void) { return 0; }
+  
+  static struct widget_ops ops = {
+.init = widget_init,  // OK - compatible types
+.exec = widget_exec,  // OK - both use "pepper" salt
+.cleanup = widget_cleanup // OK - compatible types
+  };
+  
+  // Using C++11 attribute syntax
+  void secure_callback(void) [[clang::cfi_salt("secure")]];
+  
+  // This would cause a compilation error:
+  // fptr_t bad_ptr = widget_exec;  // Error: incompatible types
+
+**Notes:**
+
+* The salt string can contain any characters, including spaces and quotes

bwendling wrote:

Unicode, wide-characters, an excessive amount of characters (think "War and 
Peace"), etc. I'm thinking of backing off of this claim and simply say non-null 
ASCII characters, unless we need can support those easily (we're using 
`StringRef`...).

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.

erichkeane wrote:

Extraneous/inaccurate comment.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits


@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -fsyntax-only -fsanitize=kcfi -verify %s
+
+#define __cfi_salt(S) __attribute__((cfi_salt(S)))
+
+int bad1() __cfi_salt();
+// expected-error@-1{{'cfi_salt' attribute takes one argument}}
+int bad2() __cfi_salt(42);
+// expected-error@-1{{expected string literal as argument of 'cfi_salt' 
attribute}}
+
+int foo(int a, int b) __cfi_salt("pepper"); // ok
+int foo(int a, int b) __cfi_salt("pepper"); // ok
+
+typedef int (*bar_t)(void) __cfi_salt("pepper"); // ok
+typedef int (*bar_t)(void) __cfi_salt("pepper"); // ok
+
+// FIXME: Should we allow this?
+// int b(void) __cfi_salt("salt 'n") __cfi_salt("pepper");
+// bar_t bar_fn __cfi_salt("salt 'n");
+
+int baz __cfi_salt("salt");
+// expected-warning@-1{{'cfi_salt' only applies to function types}}
+
+int baz_fn(int a, int b) __cfi_salt("salt 'n");
+// expected-note@-1{{previous declaration is here}}

erichkeane wrote:

I have a VERY strong preference for putting the 'note' immediately after the 
'error' textually and doing whatever it takes to get the '@' to work right (I 
typically suggest our bookmark feature, but with these that is obviously not 
necessary).

For example, while reading this test, it took me an unfortunate amount of time 
to figure out which error this went with.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits

https://github.com/erichkeane approved this pull request.

A few small things, but this is going to be LGTM pretty quickly.

Approve pending my 4 comments.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)
+  return true;
+
+// Delay if this is not a function type.
+StringRef Argument;
+if (!S.checkStringLiteralArgumentAttr(attr, 0, Argument))
+  return false;
+
+// Delay if this is not a function type.
+if (!unwrapped.isFunctionType())
+  return false;
+
+const auto *FnTy = unwrapped.get()->getAs();
+if (!FnTy)

erichkeane wrote:

So this is intentionally disallowing functions without a prototype?  Do you 
have a test for that?  Will it diagnose?

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits

https://github.com/erichkeane edited 
https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Erich Keane via cfe-commits


@@ -7941,6 +7942,32 @@ static bool handleFunctionTypeAttr(TypeProcessingState 
&state, ParsedAttr &attr,
 return true;
   }
 
+  if (attr.getKind() == ParsedAttr::AT_CFISalt) {
+if (attr.getNumArgs() == 0)

erichkeane wrote:

```suggestion
if (attr.getNumArgs() != 1)
```

Perhaps?  Alternatively, should this be an `assert(attr.getNumArgs() == 1)` ? 

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman commented:

This is looking reasonable to me. Some minor questions on the documentation, 
but otherwise I leave it to @erichkeane for the final sign off.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Aaron Ballman via cfe-commits


@@ -3643,6 +3643,95 @@ make the function's CFI jump table canonical. See 
:ref:`the CFI documentation
   }];
 }
 
+def CFISaltDocs : Documentation {
+  let Category = DocCatFunction;
+  let Heading = "cfi_salt";
+  let Label = "langext-cfi_salt";
+  let Content = [{
+The ``cfi_salt`` attribute allows you to add a salt value to Control Flow 
+Integrity (CFI) type hashes to help distinguish between functions with the 
+same type signature. This attribute can be applied to function declarations, 
+function definitions, and function pointer typedefs.
+
+**Syntax:**
+
+* GNU-style: ``__attribute__((cfi_salt("")))``
+* C++11-style: ``[[clang::cfi_salt("")]]``
+
+**Usage:**
+
+The attribute takes a single string literal argument that serves as the salt.
+Functions or function types with different salt values will have different CFI
+hashes, even if they have identical type signatures.
+
+**Motivation:**
+
+In large codebases like the Linux kernel, there are often hundreds of functions
+with identical type signatures that are called indirectly:
+
+.. code-block::
+
+  1662 functions with void (*)(void)
+  1179 functions with int (*)(void)
+   ...
+
+By salting the CFI hashes, you can make CFI more robust by ensuring that
+functions intended for different purposes have distinct CFI identities.
+
+**Type Compatibility:**
+
+* Functions with different salt values are considered to have incompatible 
types
+* Function pointers with different salt values cannot be assigned to each other
+* All declarations of the same function must use the same salt value
+
+**Example:**
+
+.. code-block:: c
+
+  // Header file - define convenience macros
+  #define __cfi_salt(s) __attribute__((cfi_salt(s)))
+  
+  // Typedef for regular function pointers
+  typedef int (*fptr_t)(void);
+  
+  // Typedef for salted function pointers  
+  typedef int (*fptr_salted_t)(void) __cfi_salt("pepper");
+  
+  struct widget_ops {
+fptr_t init;  // Regular CFI
+fptr_salted_t exec;   // Salted CFI
+fptr_t cleanup;   // Regular CFI
+  };
+  
+  // Function implementations
+  static int widget_init(void) { return 0; }
+  static int widget_exec(void) __cfi_salt("pepper") { return 1; }
+  static int widget_cleanup(void) { return 0; }
+  
+  static struct widget_ops ops = {
+.init = widget_init,  // OK - compatible types
+.exec = widget_exec,  // OK - both use "pepper" salt
+.cleanup = widget_cleanup // OK - compatible types
+  };
+  
+  // Using C++11 attribute syntax
+  void secure_callback(void) [[clang::cfi_salt("secure")]];
+  
+  // This would cause a compilation error:
+  // fptr_t bad_ptr = widget_exec;  // Error: incompatible types
+
+**Notes:**
+
+* The salt string can contain any characters, including spaces and quotes

AaronBallman wrote:

Embedded nulls? (If so, we should have a test case for that situation.) Also, 
do we need to say anything about the text encoding? (Any other weird things we 
need to be aware of @cor3ntin?)

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add 'cfi_salt' attribute (PR #141846)

2025-08-04 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-07-08 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/141846

>From bfdf16cee252dc6491f15c0715c7a39538fbf120 Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 23 Apr 2025 13:14:24 -0700
Subject: [PATCH 1/5] [Clang][attr] Add cfi_salt attribute

The new 'cfi_salt' attribute is used to differentiate between two
functions with the same type signature. It's applied to the function
declaration, function definition, and function typedefs of the function
to ensure the "salt" is passed through to code generation.

Simple example:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

extern int foo(void) __cfi_salt;
int f1_salt(void) __cfi_salt { /* ... */ }

Example of using this in a structure:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

// Convenient typedefs to avoid nested declarator syntax.
typedef int (*fptr_t)(void);
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();
}

Link: https://github.com/ClangBuiltLinux/linux/issues/1736
Link: https://github.com/KSPP/linux/issues/365
Signed-off-by: Bill Wendling 
---
 clang/include/clang/Basic/Attr.td |   7 +
 clang/include/clang/Basic/AttrDocs.td |  58 
 clang/lib/AST/TypePrinter.cpp |   3 +
 clang/lib/CodeGen/CGCall.h|   7 +
 clang/lib/CodeGen/CGExpr.cpp  |   5 +-
 clang/lib/CodeGen/CGExprCXX.cpp   |  14 +-
 clang/lib/CodeGen/CodeGenFunction.cpp |  35 -
 clang/lib/CodeGen/CodeGenModule.cpp   |  15 +-
 clang/lib/CodeGen/CodeGenModule.h |   2 +-
 clang/lib/Sema/SemaDeclAttr.cpp   |  27 
 clang/test/CodeGen/kcfi-salt.c| 190 ++
 11 files changed, 345 insertions(+), 18 deletions(-)
 create mode 100644 clang/test/CodeGen/kcfi-salt.c

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index db02449a3dd12..b3a35ec3a16a4 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3830,6 +3830,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>;
+  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
diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 65d66dd398ad1..4c3a488076c54 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -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("")))`` 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

[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-07-08 Thread via cfe-commits

github-actions[bot] wrote:




:warning: C/C++ code formatter, clang-format found issues in your code. 
:warning:



You can test this locally with the following command:


``bash
git-clang-format --diff HEAD~1 HEAD --extensions c,cpp,h -- 
clang/test/CodeGen/kcfi-salt.c clang/include/clang/AST/Type.h 
clang/lib/AST/ASTContext.cpp clang/lib/AST/Type.cpp 
clang/lib/AST/TypePrinter.cpp clang/lib/CodeGen/CodeGenFunction.cpp 
clang/lib/CodeGen/CodeGenModule.cpp clang/lib/CodeGen/CodeGenModule.h 
clang/lib/Sema/SemaType.cpp
``





View the diff from clang-format here.


``diff
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 345b2232c..5ed61e8af 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2107,7 +2107,8 @@ void TypePrinter::printAttributedAfter(const 
AttributedType *T,
 OS << "ext_vector_type";
 break;
   case attr::KCFISalt:
-OS << "kcfi_salt(\"" << cast(T->getAttr())->getSalt() << 
"\")";
+OS << "kcfi_salt(\"" << cast(T->getAttr())->getSalt()
+   << "\")";
 break;
   }
   OS << "))";

``




https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-07-08 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/141846

>From bfdf16cee252dc6491f15c0715c7a39538fbf120 Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 23 Apr 2025 13:14:24 -0700
Subject: [PATCH 1/4] [Clang][attr] Add cfi_salt attribute

The new 'cfi_salt' attribute is used to differentiate between two
functions with the same type signature. It's applied to the function
declaration, function definition, and function typedefs of the function
to ensure the "salt" is passed through to code generation.

Simple example:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

extern int foo(void) __cfi_salt;
int f1_salt(void) __cfi_salt { /* ... */ }

Example of using this in a structure:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

// Convenient typedefs to avoid nested declarator syntax.
typedef int (*fptr_t)(void);
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();
}

Link: https://github.com/ClangBuiltLinux/linux/issues/1736
Link: https://github.com/KSPP/linux/issues/365
Signed-off-by: Bill Wendling 
---
 clang/include/clang/Basic/Attr.td |   7 +
 clang/include/clang/Basic/AttrDocs.td |  58 
 clang/lib/AST/TypePrinter.cpp |   3 +
 clang/lib/CodeGen/CGCall.h|   7 +
 clang/lib/CodeGen/CGExpr.cpp  |   5 +-
 clang/lib/CodeGen/CGExprCXX.cpp   |  14 +-
 clang/lib/CodeGen/CodeGenFunction.cpp |  35 -
 clang/lib/CodeGen/CodeGenModule.cpp   |  15 +-
 clang/lib/CodeGen/CodeGenModule.h |   2 +-
 clang/lib/Sema/SemaDeclAttr.cpp   |  27 
 clang/test/CodeGen/kcfi-salt.c| 190 ++
 11 files changed, 345 insertions(+), 18 deletions(-)
 create mode 100644 clang/test/CodeGen/kcfi-salt.c

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index db02449a3dd12..b3a35ec3a16a4 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3830,6 +3830,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>;
+  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
diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 65d66dd398ad1..4c3a488076c54 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -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("")))`` 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

[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-07-08 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/141846

>From bfdf16cee252dc6491f15c0715c7a39538fbf120 Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 23 Apr 2025 13:14:24 -0700
Subject: [PATCH 1/3] [Clang][attr] Add cfi_salt attribute

The new 'cfi_salt' attribute is used to differentiate between two
functions with the same type signature. It's applied to the function
declaration, function definition, and function typedefs of the function
to ensure the "salt" is passed through to code generation.

Simple example:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

extern int foo(void) __cfi_salt;
int f1_salt(void) __cfi_salt { /* ... */ }

Example of using this in a structure:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

// Convenient typedefs to avoid nested declarator syntax.
typedef int (*fptr_t)(void);
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();
}

Link: https://github.com/ClangBuiltLinux/linux/issues/1736
Link: https://github.com/KSPP/linux/issues/365
Signed-off-by: Bill Wendling 
---
 clang/include/clang/Basic/Attr.td |   7 +
 clang/include/clang/Basic/AttrDocs.td |  58 
 clang/lib/AST/TypePrinter.cpp |   3 +
 clang/lib/CodeGen/CGCall.h|   7 +
 clang/lib/CodeGen/CGExpr.cpp  |   5 +-
 clang/lib/CodeGen/CGExprCXX.cpp   |  14 +-
 clang/lib/CodeGen/CodeGenFunction.cpp |  35 -
 clang/lib/CodeGen/CodeGenModule.cpp   |  15 +-
 clang/lib/CodeGen/CodeGenModule.h |   2 +-
 clang/lib/Sema/SemaDeclAttr.cpp   |  27 
 clang/test/CodeGen/kcfi-salt.c| 190 ++
 11 files changed, 345 insertions(+), 18 deletions(-)
 create mode 100644 clang/test/CodeGen/kcfi-salt.c

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index db02449a3dd12..b3a35ec3a16a4 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3830,6 +3830,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>;
+  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
diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 65d66dd398ad1..4c3a488076c54 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -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("")))`` 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

[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-07-02 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/141846

>From bfdf16cee252dc6491f15c0715c7a39538fbf120 Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 23 Apr 2025 13:14:24 -0700
Subject: [PATCH 1/2] [Clang][attr] Add cfi_salt attribute

The new 'cfi_salt' attribute is used to differentiate between two
functions with the same type signature. It's applied to the function
declaration, function definition, and function typedefs of the function
to ensure the "salt" is passed through to code generation.

Simple example:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

extern int foo(void) __cfi_salt;
int f1_salt(void) __cfi_salt { /* ... */ }

Example of using this in a structure:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

// Convenient typedefs to avoid nested declarator syntax.
typedef int (*fptr_t)(void);
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();
}

Link: https://github.com/ClangBuiltLinux/linux/issues/1736
Link: https://github.com/KSPP/linux/issues/365
Signed-off-by: Bill Wendling 
---
 clang/include/clang/Basic/Attr.td |   7 +
 clang/include/clang/Basic/AttrDocs.td |  58 
 clang/lib/AST/TypePrinter.cpp |   3 +
 clang/lib/CodeGen/CGCall.h|   7 +
 clang/lib/CodeGen/CGExpr.cpp  |   5 +-
 clang/lib/CodeGen/CGExprCXX.cpp   |  14 +-
 clang/lib/CodeGen/CodeGenFunction.cpp |  35 -
 clang/lib/CodeGen/CodeGenModule.cpp   |  15 +-
 clang/lib/CodeGen/CodeGenModule.h |   2 +-
 clang/lib/Sema/SemaDeclAttr.cpp   |  27 
 clang/test/CodeGen/kcfi-salt.c| 190 ++
 11 files changed, 345 insertions(+), 18 deletions(-)
 create mode 100644 clang/test/CodeGen/kcfi-salt.c

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index db02449a3dd12..b3a35ec3a16a4 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3830,6 +3830,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>;
+  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
diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 65d66dd398ad1..4c3a488076c54 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -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("")))`` 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

[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-07-01 Thread Bill Wendling via cfe-commits


@@ -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("")))`` on a function declaration, function

bwendling wrote:

> > I'm going to see if the attribute could be restricted to C
> 
> If you do restrict to C, then that should be all of the CFI attributes which 
> are restricted to C? If so, we should definitely move on that before Clang 21 
> is released.

I don't see why *all* CFI attributes should be restricted to C. There may be 
some which can be for both, depending on circumstances.

I may change the name of this attribute 'kcfi_seed' to indicate that it's 
fairly specifically meant for kernel code.

> > As for modules/PCH files, those are C++ features, correct? I literally have 
> > no experience with them.
> 
> Modules are a C++ feature, but PCH files are both C and C++ (precompiled 
> headers). Basically, when you include a PCH file it's the same as including a 
> textual header but instead you're including a serialized binary blob 
> representing the textual header, so you can run into the same situations with 
> invalid redeclarations. But I _think_ that's handled in a sufficiently 
> generic way that you should be fine without any custom logic.

This would be a generic problem for all PCH's then; not just this one.

> > Re name mangling:
> 
> This goes back to whether it's impacting the function type. Generally that's 
> only an issue in C++, but we have the `overloadable` attribute which allows 
> for overloading in C. And the way that's implemented is that it basically 
> uses the C++ logic, including name mangling. So we may have to care about it, 
> but if the salt attribute is not part of the function type, then there's no 
> overloads and no need to worry.

Okay, sure.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-07-01 Thread Aaron Ballman via cfe-commits


@@ -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("")))`` on a function declaration, function

AaronBallman wrote:

>  I'm going to see if the attribute could be restricted to C

If you do restrict to C, then that should be all of the CFI attributes which 
are restricted to C? If so, we should definitely move on that before Clang 21 
is released.

> As for modules/PCH files, those are C++ features, correct? I literally have 
> no experience with them.

Modules are a C++ feature, but PCH files are both C and C++ (precompiled 
headers). Basically, when you include a PCH file it's the same as including a 
textual header but instead you're including a serialized binary blob 
representing the textual header, so you can run into the same situations with 
invalid redeclarations. But I *think* that's handled in a sufficiently generic 
way that you should be fine without any custom logic.

> Re name mangling:

This goes back to whether it's impacting the function type. Generally that's 
only an issue in C++, but we have the `overloadable` attribute which allows for 
overloading in C. And the way that's implemented is that it basically uses the 
C++ logic, including name mangling. So we may have to care about it, but if the 
salt attribute is not part of the function type, then there's no overloads and 
no need to worry.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-06-30 Thread Bill Wendling via cfe-commits


@@ -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("")))`` on a function declaration, function

bwendling wrote:

All good questions. I'm going to see if the attribute could be restricted to C, 
as I don't think there's a good way to handle any of the issues with virtual 
functions you mention here.

As for modules/PCH files, those are C++ features, correct? I literally have no 
experience with them.

Re name mangling: Probably not, as that would be a departure from other 
attributes, which typically don't interact with name mangling. The example you 
gave in C would result in a runtime error. Not ideal, but possibly the correct 
behavior.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-06-10 Thread Aaron Ballman via cfe-commits

AaronBallman wrote:

> @AaronBallman I know of no other CFI attribute requests. 

Excellent, glad to hear there's not some massive set of changes waiting in the 
wings.

> (But keep in mind that I'm not the CFI expert I play on TV.)

Sorry, but you touched it last, so you own it. I don't make the rules. ;-) (I 
kid, I kid)

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-06-09 Thread Bill Wendling via cfe-commits

bwendling wrote:

@AaronBallman I know of no other CFI attribute requests. (But keep in mind that 
I'm not the CFI expert I play on TV.)

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-06-09 Thread Aaron Ballman via cfe-commits

AaronBallman wrote:

> Also, this is ANOTHER bit on function types that we're using for CFI. I'm 
> wondering if this is actually a generally useful enough feature to be using 
> this much compiler resources.
> 
> @AaronBallman ?

I think CFI is pretty important for security posture (it basically tries to 
ensure that indirect jumps don't go to unintended locations). So I think it's 
useful, but I am also a bit worried that we're missing the big picture of how 
much work needs to be done to fully support CFI. @bwendling do you expect to 
land more related attributes after this one?

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-06-05 Thread Bill Wendling via cfe-commits

bwendling wrote:

@erichkeane If the Arm attribute code were merged into `ExtraAttributeInfo`, it 
would save us a bit in `FunctionTypeExtraBitfields`.

I can add more testing I suppose, but the tests I have here are a copy of the 
current CFI tests, which test all of the ways CFI is used. So I'm not sure how 
much more needs to be done... The important thing that's tested here is that 
the CFI code changes in a deterministic way when the "salt" is added. It's not 
a test for all of CFI.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-06-05 Thread Erich Keane via cfe-commits

https://github.com/erichkeane commented:

Testing seems insufficient, particularly around conversion rules/etc of these 
types.  I would like to see quite a bit more for Sema/inside of templates/how 
this applies to instantiations of all these things, etc.

Also, this is ANOTHER bit on function types that we're using for CFI.  I'm 
wondering if this is actually a generally useful enough feature to be using 
this much compiler resources.

@AaronBallman ?

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-06-04 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/141846

>From bfdf16cee252dc6491f15c0715c7a39538fbf120 Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 23 Apr 2025 13:14:24 -0700
Subject: [PATCH 1/2] [Clang][attr] Add cfi_salt attribute

The new 'cfi_salt' attribute is used to differentiate between two
functions with the same type signature. It's applied to the function
declaration, function definition, and function typedefs of the function
to ensure the "salt" is passed through to code generation.

Simple example:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

extern int foo(void) __cfi_salt;
int f1_salt(void) __cfi_salt { /* ... */ }

Example of using this in a structure:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

// Convenient typedefs to avoid nested declarator syntax.
typedef int (*fptr_t)(void);
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();
}

Link: https://github.com/ClangBuiltLinux/linux/issues/1736
Link: https://github.com/KSPP/linux/issues/365
Signed-off-by: Bill Wendling 
---
 clang/include/clang/Basic/Attr.td |   7 +
 clang/include/clang/Basic/AttrDocs.td |  58 
 clang/lib/AST/TypePrinter.cpp |   3 +
 clang/lib/CodeGen/CGCall.h|   7 +
 clang/lib/CodeGen/CGExpr.cpp  |   5 +-
 clang/lib/CodeGen/CGExprCXX.cpp   |  14 +-
 clang/lib/CodeGen/CodeGenFunction.cpp |  35 -
 clang/lib/CodeGen/CodeGenModule.cpp   |  15 +-
 clang/lib/CodeGen/CodeGenModule.h |   2 +-
 clang/lib/Sema/SemaDeclAttr.cpp   |  27 
 clang/test/CodeGen/kcfi-salt.c| 190 ++
 11 files changed, 345 insertions(+), 18 deletions(-)
 create mode 100644 clang/test/CodeGen/kcfi-salt.c

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index db02449a3dd12..b3a35ec3a16a4 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3830,6 +3830,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>;
+  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
diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 65d66dd398ad1..4c3a488076c54 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -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("")))`` 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

[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-06-04 Thread Bill Wendling via cfe-commits

bwendling wrote:

I moved the `cfi_salt` into the `FunctionProtoType` fields. I left it open for 
further additions. One bit of optimization I could do is merge the Arm stuff 
into this new struct, but wanted to do something a bit less cluttered first.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-06-04 Thread Bill Wendling via cfe-commits

https://github.com/bwendling updated 
https://github.com/llvm/llvm-project/pull/141846

>From bfdf16cee252dc6491f15c0715c7a39538fbf120 Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 23 Apr 2025 13:14:24 -0700
Subject: [PATCH 1/2] [Clang][attr] Add cfi_salt attribute

The new 'cfi_salt' attribute is used to differentiate between two
functions with the same type signature. It's applied to the function
declaration, function definition, and function typedefs of the function
to ensure the "salt" is passed through to code generation.

Simple example:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

extern int foo(void) __cfi_salt;
int f1_salt(void) __cfi_salt { /* ... */ }

Example of using this in a structure:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

// Convenient typedefs to avoid nested declarator syntax.
typedef int (*fptr_t)(void);
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();
}

Link: https://github.com/ClangBuiltLinux/linux/issues/1736
Link: https://github.com/KSPP/linux/issues/365
Signed-off-by: Bill Wendling 
---
 clang/include/clang/Basic/Attr.td |   7 +
 clang/include/clang/Basic/AttrDocs.td |  58 
 clang/lib/AST/TypePrinter.cpp |   3 +
 clang/lib/CodeGen/CGCall.h|   7 +
 clang/lib/CodeGen/CGExpr.cpp  |   5 +-
 clang/lib/CodeGen/CGExprCXX.cpp   |  14 +-
 clang/lib/CodeGen/CodeGenFunction.cpp |  35 -
 clang/lib/CodeGen/CodeGenModule.cpp   |  15 +-
 clang/lib/CodeGen/CodeGenModule.h |   2 +-
 clang/lib/Sema/SemaDeclAttr.cpp   |  27 
 clang/test/CodeGen/kcfi-salt.c| 190 ++
 11 files changed, 345 insertions(+), 18 deletions(-)
 create mode 100644 clang/test/CodeGen/kcfi-salt.c

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index db02449a3dd12..b3a35ec3a16a4 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3830,6 +3830,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>;
+  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
diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 65d66dd398ad1..4c3a488076c54 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -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("")))`` 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

[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-05-28 Thread Eli Friedman via cfe-commits

efriedma-quic wrote:

Something along the lines of FunctionTypeArmAttributes seems fine.

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-05-28 Thread Bill Wendling via cfe-commits

bwendling wrote:

@efriedma-quic Okay, I'm not entirely sure I understand @erichkeane's concerns, 
but that's fine. Are you suggesting adding the salt information to the 
`FunctionType` instead?

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-05-28 Thread Eli Friedman via cfe-commits

efriedma-quic wrote:

See #135836 for discussion of why you can't use AttributedType like this.  CC 
@PiJoules

https://github.com/llvm/llvm-project/pull/141846
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-05-28 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Bill Wendling (bwendling)


Changes

The new 'cfi_salt' attribute is used to differentiate between two functions 
with the same type signature. It's applied to the function declaration, 
function definition, and function typedefs of the function to ensure the "salt" 
is passed through to code generation.

Simple example:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

extern int foo(void) __cfi_salt;
int f1_salt(void) __cfi_salt { /* ... */ }

Example of using this in a structure:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

// Convenient typedefs to avoid nested declarator syntax.
typedef int (*fptr_t)(void);
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();
}

Link: https://github.com/ClangBuiltLinux/linux/issues/1736
Link: https://github.com/KSPP/linux/issues/365

---
Full diff: https://github.com/llvm/llvm-project/pull/141846.diff


11 Files Affected:

- (modified) clang/include/clang/Basic/Attr.td (+7) 
- (modified) clang/include/clang/Basic/AttrDocs.td (+58) 
- (modified) clang/lib/AST/TypePrinter.cpp (+3) 
- (modified) clang/lib/CodeGen/CGCall.h (+7) 
- (modified) clang/lib/CodeGen/CGExpr.cpp (+3-2) 
- (modified) clang/lib/CodeGen/CGExprCXX.cpp (+6-8) 
- (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+31-4) 
- (modified) clang/lib/CodeGen/CodeGenModule.cpp (+12-3) 
- (modified) clang/lib/CodeGen/CodeGenModule.h (+1-1) 
- (modified) clang/lib/Sema/SemaDeclAttr.cpp (+27) 
- (added) clang/test/CodeGen/kcfi-salt.c (+190) 


``diff
diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index db02449a3dd12..b3a35ec3a16a4 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3830,6 +3830,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>;
+  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
diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 65d66dd398ad1..4c3a488076c54 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -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("")))`` 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 : DocumentationCategor

[clang] [Clang][attr] Add cfi_salt attribute (PR #141846)

2025-05-28 Thread Bill Wendling via cfe-commits

https://github.com/bwendling created 
https://github.com/llvm/llvm-project/pull/141846

The new 'cfi_salt' attribute is used to differentiate between two functions 
with the same type signature. It's applied to the function declaration, 
function definition, and function typedefs of the function to ensure the "salt" 
is passed through to code generation.

Simple example:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

extern int foo(void) __cfi_salt;
int f1_salt(void) __cfi_salt { /* ... */ }

Example of using this in a structure:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

// Convenient typedefs to avoid nested declarator syntax.
typedef int (*fptr_t)(void);
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();
}

Link: https://github.com/ClangBuiltLinux/linux/issues/1736
Link: https://github.com/KSPP/linux/issues/365

>From bfdf16cee252dc6491f15c0715c7a39538fbf120 Mon Sep 17 00:00:00 2001
From: Bill Wendling 
Date: Wed, 23 Apr 2025 13:14:24 -0700
Subject: [PATCH] [Clang][attr] Add cfi_salt attribute

The new 'cfi_salt' attribute is used to differentiate between two
functions with the same type signature. It's applied to the function
declaration, function definition, and function typedefs of the function
to ensure the "salt" is passed through to code generation.

Simple example:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

extern int foo(void) __cfi_salt;
int f1_salt(void) __cfi_salt { /* ... */ }

Example of using this in a structure:

#define __cfi_salt __attribute__((cfi_salt("pepper")))

// Convenient typedefs to avoid nested declarator syntax.
typedef int (*fptr_t)(void);
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();
}

Link: https://github.com/ClangBuiltLinux/linux/issues/1736
Link: https://github.com/KSPP/linux/issues/365
Signed-off-by: Bill Wendling 
---
 clang/include/clang/Basic/Attr.td |   7 +
 clang/include/clang/Basic/AttrDocs.td |  58 
 clang/lib/AST/TypePrinter.cpp |   3 +
 clang/lib/CodeGen/CGCall.h|   7 +
 clang/lib/CodeGen/CGExpr.cpp  |   5 +-
 clang/lib/CodeGen/CGExprCXX.cpp   |  14 +-
 clang/lib/CodeGen/CodeGenFunction.cpp |  35 -
 clang/lib/CodeGen/CodeGenModule.cpp   |  15 +-
 clang/lib/CodeGen/CodeGenModule.h |   2 +-
 clang/lib/Sema/SemaDeclAttr.cpp   |  27 
 clang/test/CodeGen/kcfi-salt.c| 190 ++
 11 files changed, 345 insertions(+), 18 deletions(-)
 create mode 100644 clang/test/CodeGen/kcfi-salt.c

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index db02449a3dd12..b3a35ec3a16a4 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3830,6 +3830,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>;
+  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