[clang] [Clang][kcfi] Sign extend KCFI typeid rather than zero extend (PR #136734)
Bill Wendling via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 22 10:50:22 PDT 2025
https://github.com/bwendling created https://github.com/llvm/llvm-project/pull/136734
The KCFI typeid may be negative, but will result in this type of bitcode:
module asm ".weak __kcfi_typeid_func"
module asm ".set __kcfi_typeid_func, 2874394057"
// ...
define dso_local i32 @call_unsigned(ptr noundef %f) #0 !kcfi_type !6 {
// ...
%call = call i32 %0(i32 noundef 37) [ "kcfi"(i32 -1420573239) ]
ret i32 %call
}
declare !kcfi_type !7 noundef i32 @foo(i32 noundef)
// ...
!7 = !{i32 -1420573239}
The __kcfi_typeid_func value doesn't equal the metadata value. Therefore, we sign extend the typeid value rather than zero extend.
This also reorganizes the testcase to remove the "-DAG" checks, which are a bit confusing at first.
>From f858b157de257f6f135db38bc59f631cccc52775 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Tue, 22 Apr 2025 10:39:05 -0700
Subject: [PATCH] [Clang][kcfi] Sign extend KCFI typeid rather than zero extend
The KCFI typeid may be negative, but will result in this type of
bitcode:
module asm ".weak __kcfi_typeid_func"
module asm ".set __kcfi_typeid_func, 2874394057"
// ...
define dso_local i32 @call_unsigned(ptr noundef %f) #0 !kcfi_type !6 {
// ...
%call = call i32 %0(i32 noundef 37) [ "kcfi"(i32 -1420573239) ]
ret i32 %call
}
declare !kcfi_type !7 noundef i32 @foo(i32 noundef)
// ...
!7 = !{i32 -1420573239}
The __kcfi_typeid_func value doesn't equal the metadata value.
Therefore, we sign extend the typeid value rather than zero extend.
This also reorganizes the testcase to remove the "-DAG" checks, which
are a bit confusing at first.
Signed-off-by: Bill Wendling <morbo at google.com>
---
clang/lib/CodeGen/CodeGenModule.cpp | 2 +-
clang/test/CodeGen/kcfi.c | 82 ++++++++++++++++++++---------
2 files changed, 57 insertions(+), 27 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 83d8d4f758195..0422f4ab1cebb 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2931,7 +2931,7 @@ void CodeGenModule::finalizeKCFITypes() {
continue;
std::string Asm = (".weak __kcfi_typeid_" + Name + "\n.set __kcfi_typeid_" +
- Name + ", " + Twine(Type->getZExtValue()) + "\n")
+ Name + ", " + Twine(Type->getSExtValue()) + "\n")
.str();
M.appendModuleInlineAsm(Asm);
}
diff --git a/clang/test/CodeGen/kcfi.c b/clang/test/CodeGen/kcfi.c
index 622843cedba50..058f3277a8119 100644
--- a/clang/test/CodeGen/kcfi.c
+++ b/clang/test/CodeGen/kcfi.c
@@ -8,18 +8,25 @@
/// Must emit __kcfi_typeid symbols for address-taken function declarations
// CHECK: module asm ".weak __kcfi_typeid_[[F4:[a-zA-Z0-9_]+]]"
// CHECK: module asm ".set __kcfi_typeid_[[F4]], [[#%d,HASH:]]"
+// CHECK: module asm ".weak __kcfi_typeid_[[F4_ARG:[a-zA-Z0-9_]+]]"
+// CHECK: module asm ".set __kcfi_typeid_[[F4_ARG]], [[#%d,ARG_HASH:]]"
+
/// Must not __kcfi_typeid symbols for non-address-taken declarations
// CHECK-NOT: module asm ".weak __kcfi_typeid_{{f6|_Z2f6v}}"
// C: @ifunc1 = ifunc i32 (i32), ptr @resolver1
// C: @ifunc2 = ifunc i64 (i64), ptr @resolver2
typedef int (*fn_t)(void);
+typedef int (*fn_u_t)(unsigned int);
-// CHECK: define dso_local{{.*}} i32 @{{f1|_Z2f1v}}(){{.*}} !kcfi_type ![[#TYPE:]]
-int f1(void) { return 0; }
+int f1(void);
-// CHECK: define dso_local{{.*}} i32 @{{f2|_Z2f2v}}(){{.*}} !kcfi_type ![[#TYPE2:]]
-unsigned int f2(void) { return 2; }
+unsigned int f2(void);
+
+static int f3(void);
+
+extern int f4(void);
+extern int f4_arg(unsigned int);
// CHECK-LABEL: define dso_local{{.*}} i32 @{{__call|_Z6__callPFivE}}(ptr{{.*}} %f)
int __call(fn_t f) __attribute__((__no_sanitize__("kcfi"))) {
@@ -27,17 +34,45 @@ int __call(fn_t f) __attribute__((__no_sanitize__("kcfi"))) {
return f();
}
-// CHECK: define dso_local{{.*}} i32 @{{call|_Z4callPFivE}}(ptr{{.*}} %f){{.*}}
+// CHECK-LABEL: define dso_local{{.*}} i32 @{{call|_Z4callPFivE}}(ptr{{.*}} %f)
int call(fn_t f) {
// CHECK: call{{.*}} i32 %{{.}}(){{.*}} [ "kcfi"(i32 [[#HASH]]) ]
return f();
}
-// CHECK-DAG: define internal{{.*}} i32 @{{f3|_ZL2f3v}}(){{.*}} !kcfi_type ![[#TYPE]]
+// CHECK-LABEL: define dso_local{{.*}} i32 @{{call_with_arg|_Z13call_with_argPFijE}}(ptr{{.*}} %f)
+int call_with_arg(fn_u_t f) {
+ // CHECK: call{{.*}} i32 %0(i32 {{.*}}) [ "kcfi"(i32 [[#ARG_HASH]]) ]
+ return f(42);
+}
+
+static int f5(void);
+
+extern int f6(void);
+
+int test(void) {
+ return call(f1) +
+ __call((fn_t)f2) +
+ call(f3) +
+ call(f4) +
+ call_with_arg(f4_arg) +
+ f5() +
+ f6();
+}
+
+// CHECK-LABEL: define dso_local{{.*}} i32 @{{f1|_Z2f1v}}(){{.*}} !kcfi_type ![[#TYPE:]]
+int f1(void) { return 0; }
+
+// CHECK-LABEL: define dso_local{{.*}} i32 @{{f2|_Z2f2v}}(){{.*}} !kcfi_type ![[#TYPE2:]]
+unsigned int f2(void) { return 2; }
+
+// CHECK: define internal{{.*}} i32 @{{f3|_ZL2f3v}}(){{.*}} !kcfi_type ![[#TYPE]]
static int f3(void) { return 1; }
-// CHECK-DAG: declare !kcfi_type ![[#TYPE]]{{.*}} i32 @[[F4]]()
-extern int f4(void);
+// CHECK-LABEL: declare !kcfi_type
+// CHECK-SAME: ![[#TYPE]]{{.*}} i32 @[[F4]]
+// CHECK-LABEL: declare !kcfi_type
+// CHECK-SAME: ![[#ARG_TYPE:]]{{.*}} i32 @[[F4_ARG]]
/// Must not emit !kcfi_type for non-address-taken local functions
// CHECK: define internal{{.*}} i32 @{{f5|_ZL2f5v}}()
@@ -45,8 +80,7 @@ extern int f4(void);
// CHECK-SAME: {
static int f5(void) { return 2; }
-// CHECK-DAG: declare !kcfi_type ![[#TYPE]]{{.*}} i32 @{{f6|_Z2f6v}}()
-extern int f6(void);
+// CHECK: declare !kcfi_type ![[#TYPE]]{{.*}} i32 @{{f6|_Z2f6v}}()
#ifndef __cplusplus
// C: define internal ptr @resolver1() #[[#]] !kcfi_type ![[#]] {
@@ -58,30 +92,26 @@ static void *resolver2(void) { return 0; }
long ifunc2(long) __attribute__((ifunc("resolver2")));
#endif
-int test(void) {
- return call(f1) +
- __call((fn_t)f2) +
- call(f3) +
- call(f4) +
- f5() +
- f6();
-}
-
#ifdef __cplusplus
struct A {
- // MEMBER-DAG: define{{.*}} void @_ZN1A1fEv(ptr{{.*}} %this){{.*}} !kcfi_type ![[#TYPE3:]]
void f() {}
};
void test_member_call(void) {
void (A::* p)() = &A::f;
- // MEMBER-DAG: call void %[[#]](ptr{{.*}} [ "kcfi"(i32 [[#%d,HASH3:]]) ]
+ // MEMBER: call void %[[#]](ptr{{.*}} [ "kcfi"(i32 [[#%d,HASH3:]]) ]
(A().*p)();
}
+
+// MEMBER: define{{.*}} void @_ZN1A1fEv(ptr{{.*}} %this){{.*}} !kcfi_type ![[#TYPE3:]]
#endif
-// CHECK-DAG: ![[#]] = !{i32 4, !"kcfi", i32 1}
-// OFFSET-DAG: ![[#]] = !{i32 4, !"kcfi-offset", i32 3}
-// CHECK-DAG: ![[#TYPE]] = !{i32 [[#HASH]]}
-// CHECK-DAG: ![[#TYPE2]] = !{i32 [[#%d,HASH2:]]}
-// MEMBER-DAG: ![[#TYPE3]] = !{i32 [[#HASH3]]}
+// CHECK: ![[#]] = !{i32 4, !"kcfi", i32 1}
+//
+// OFFSET: ![[#]] = !{i32 4, !"kcfi-offset", i32 3}
+//
+// CHECK: ![[#TYPE]] = !{i32 [[#HASH]]}
+// CHECK: ![[#TYPE2]] = !{i32 [[#%d,HASH2:]]}
+// CHECK: ![[#ARG_TYPE]] = !{i32 [[#ARG_HASH]]}
+//
+// MEMBER: ![[#TYPE3]] = !{i32 [[#HASH3]]}
More information about the cfe-commits
mailing list