[clang] [llvm] Fix KCFI types for generated functions with integer normalization (PR #104826)

Sami Tolvanen via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 20 11:27:27 PDT 2024


https://github.com/samitolvanen updated https://github.com/llvm/llvm-project/pull/104826

>From 0f7dfc3f908651a70602f4f64a0ae06616544eeb Mon Sep 17 00:00:00 2001
From: Sami Tolvanen <samitolvanen at google.com>
Date: Fri, 16 Aug 2024 20:45:05 +0000
Subject: [PATCH 1/3] Fix KCFI types for generated functions with integer
 normalization

With -fsanitize-cfi-icall-experimental-normalize-integers, Clang
appends ".normalized" to KCFI types in CodeGenModule::CreateKCFITypeId,
which changes type hashes also for functions that don't have integer
types in their signatures. However, llvm::setKCFIType does not take
integer normalization into account, which means LLVM generated
functions with KCFI types, e.g. sanitizer constructors, will fail KCFI
checks when integer normalization is enabled in Clang.

Add a kcfi-normalized module flag to indicate integer normalization is
used, and append ".normalized" to KCFI types also in llvm::setKCFIType
to fix the type mismatch.
---
 clang/lib/CodeGen/CodeGenModule.cpp       |  2 ++
 clang/test/CodeGen/kcfi-normalize.c       |  1 +
 llvm/lib/Transforms/Utils/ModuleUtils.cpp | 12 +++++++-----
 3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 0b61ef0f89989c..7eca77dc9a86fe 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1136,6 +1136,8 @@ void CodeGenModule::Release() {
 
   if (LangOpts.Sanitize.has(SanitizerKind::KCFI)) {
     getModule().addModuleFlag(llvm::Module::Override, "kcfi", 1);
+    if (CodeGenOpts.SanitizeCfiICallNormalizeIntegers)
+      getModule().addModuleFlag(llvm::Module::Override, "kcfi-normalized", 1);
     // KCFI assumes patchable-function-prefix is the same for all indirectly
     // called functions. Store the expected offset for code generation.
     if (CodeGenOpts.PatchableFunctionEntryOffset)
diff --git a/clang/test/CodeGen/kcfi-normalize.c b/clang/test/CodeGen/kcfi-normalize.c
index 7660c908a7bdd5..62b907dbfb9286 100644
--- a/clang/test/CodeGen/kcfi-normalize.c
+++ b/clang/test/CodeGen/kcfi-normalize.c
@@ -28,6 +28,7 @@ void baz(void (*fn)(int, int, int), int arg1, int arg2, int arg3) {
     fn(arg1, arg2, arg3);
 }
 
+// CHECK: ![[#]] = !{i32 4, !"kcfi-normalized", i32 1}
 // CHECK: ![[TYPE1]] = !{i32 -1143117868}
 // CHECK: ![[TYPE2]] = !{i32 -460921415}
 // CHECK: ![[TYPE3]] = !{i32 -333839615}
diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
index 309cf8e70b979c..de8f00f415c357 100644
--- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp
+++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
@@ -205,11 +205,13 @@ void llvm::setKCFIType(Module &M, Function &F, StringRef MangledType) {
   // Matches CodeGenModule::CreateKCFITypeId in Clang.
   LLVMContext &Ctx = M.getContext();
   MDBuilder MDB(Ctx);
-  F.setMetadata(
-      LLVMContext::MD_kcfi_type,
-      MDNode::get(Ctx, MDB.createConstant(ConstantInt::get(
-                           Type::getInt32Ty(Ctx),
-                           static_cast<uint32_t>(xxHash64(MangledType))))));
+  std::string Type = MangledType.str();
+  if (M.getModuleFlag("kcfi-normalized"))
+    Type += ".normalized";
+  F.setMetadata(LLVMContext::MD_kcfi_type,
+                MDNode::get(Ctx, MDB.createConstant(ConstantInt::get(
+                                     Type::getInt32Ty(Ctx),
+                                     static_cast<uint32_t>(xxHash64(Type))))));
   // If the module was compiled with -fpatchable-function-entry, ensure
   // we use the same patchable-function-prefix.
   if (auto *MD = mdconst::extract_or_null<ConstantInt>(

>From d4bc7f8c95b116ccf6418f05073efcf2e0de7c90 Mon Sep 17 00:00:00 2001
From: Sami Tolvanen <samitolvanen at google.com>
Date: Tue, 20 Aug 2024 18:23:11 +0000
Subject: [PATCH 2/3] amend! Fix KCFI types for generated functions with
 integer normalization

Fix KCFI types for generated functions with integer normalization

With -fsanitize-cfi-icall-experimental-normalize-integers, Clang
appends ".normalized" to KCFI types in CodeGenModule::CreateKCFITypeId,
which changes type hashes also for functions that don't have integer
types in their signatures. However, llvm::setKCFIType does not take
integer normalization into account, which means LLVM generated
functions with KCFI types, e.g. sanitizer constructors, will fail KCFI
checks when integer normalization is enabled in Clang.

Add a cfi-normalize-integers module flag to indicate integer
normalization is used, and append ".normalized" to KCFI types also in
llvm::setKCFIType to fix the type mismatch.
---
 clang/lib/CodeGen/CodeGenModule.cpp       | 7 +++++--
 clang/test/CodeGen/kcfi-normalize.c       | 2 +-
 llvm/lib/Transforms/Utils/ModuleUtils.cpp | 2 +-
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 7eca77dc9a86fe..0d3b896af8aa39 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1134,10 +1134,13 @@ void CodeGenModule::Release() {
                               CodeGenOpts.SanitizeCfiCanonicalJumpTables);
   }
 
+  if (CodeGenOpts.SanitizeCfiICallNormalizeIntegers) {
+    getModule().addModuleFlag(llvm::Module::Override, "cfi-normalize-integers",
+                              1);
+  }
+
   if (LangOpts.Sanitize.has(SanitizerKind::KCFI)) {
     getModule().addModuleFlag(llvm::Module::Override, "kcfi", 1);
-    if (CodeGenOpts.SanitizeCfiICallNormalizeIntegers)
-      getModule().addModuleFlag(llvm::Module::Override, "kcfi-normalized", 1);
     // KCFI assumes patchable-function-prefix is the same for all indirectly
     // called functions. Store the expected offset for code generation.
     if (CodeGenOpts.PatchableFunctionEntryOffset)
diff --git a/clang/test/CodeGen/kcfi-normalize.c b/clang/test/CodeGen/kcfi-normalize.c
index 62b907dbfb9286..b9150e88f6ab5f 100644
--- a/clang/test/CodeGen/kcfi-normalize.c
+++ b/clang/test/CodeGen/kcfi-normalize.c
@@ -28,7 +28,7 @@ void baz(void (*fn)(int, int, int), int arg1, int arg2, int arg3) {
     fn(arg1, arg2, arg3);
 }
 
-// CHECK: ![[#]] = !{i32 4, !"kcfi-normalized", i32 1}
+// CHECK: ![[#]] = !{i32 4, !"cfi-normalize-integers", i32 1}
 // CHECK: ![[TYPE1]] = !{i32 -1143117868}
 // CHECK: ![[TYPE2]] = !{i32 -460921415}
 // CHECK: ![[TYPE3]] = !{i32 -333839615}
diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
index de8f00f415c357..7249571f344938 100644
--- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp
+++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
@@ -206,7 +206,7 @@ void llvm::setKCFIType(Module &M, Function &F, StringRef MangledType) {
   LLVMContext &Ctx = M.getContext();
   MDBuilder MDB(Ctx);
   std::string Type = MangledType.str();
-  if (M.getModuleFlag("kcfi-normalized"))
+  if (M.getModuleFlag("cfi-normalize-integers"))
     Type += ".normalized";
   F.setMetadata(LLVMContext::MD_kcfi_type,
                 MDNode::get(Ctx, MDB.createConstant(ConstantInt::get(

>From fb08adad4918808d22210b9a2f9f6cbc1ea33b5e Mon Sep 17 00:00:00 2001
From: Sami Tolvanen <samitolvanen at google.com>
Date: Tue, 20 Aug 2024 18:24:35 +0000
Subject: [PATCH 3/3] fixup! Fix KCFI types for generated functions with
 integer normalization

---
 .../GCOVProfiling/kcfi-normalize.ll           | 35 +++++++++++++++++++
 llvm/test/Transforms/GCOVProfiling/kcfi.ll    |  8 +++--
 2 files changed, 40 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll

diff --git a/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll b/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll
new file mode 100644
index 00000000000000..19122b920d1ca4
--- /dev/null
+++ b/llvm/test/Transforms/GCOVProfiling/kcfi-normalize.ll
@@ -0,0 +1,35 @@
+;; Ensure __llvm_gcov_(writeout|reset|init) have the correct !kcfi_type
+;; with integer normalization.
+; RUN: mkdir -p %t && cd %t
+; RUN: opt < %s -S -passes=insert-gcov-profiling | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+
+define dso_local void @empty() !dbg !5 {
+entry:
+  ret void, !dbg !8
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !9, !10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "a.c", directory: "")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = distinct !DISubprogram(name: "empty", scope: !1, file: !1, line: 1, type: !6, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
+!6 = !DISubroutineType(types: !7)
+!7 = !{null}
+!8 = !DILocation(line: 2, column: 1, scope: !5)
+!9 = !{i32 4, !"kcfi", i32 1}
+!10 = !{i32 4, !"cfi-normalize-integers", i32 1}
+
+; CHECK: define internal void @__llvm_gcov_writeout()
+; CHECK-SAME: !kcfi_type ![[#TYPE:]]
+; CHECK: define internal void @__llvm_gcov_reset()
+; CHECK-SAME: !kcfi_type ![[#TYPE]]
+; CHECK: define internal void @__llvm_gcov_init()
+; CHECK-SAME: !kcfi_type ![[#TYPE]]
+
+; CHECK: ![[#TYPE]] = !{i32 -440107680}
diff --git a/llvm/test/Transforms/GCOVProfiling/kcfi.ll b/llvm/test/Transforms/GCOVProfiling/kcfi.ll
index b25f40f05d5bc4..1b97d25294cd65 100644
--- a/llvm/test/Transforms/GCOVProfiling/kcfi.ll
+++ b/llvm/test/Transforms/GCOVProfiling/kcfi.ll
@@ -24,8 +24,10 @@ entry:
 !9 = !{i32 4, !"kcfi", i32 1}
 
 ; CHECK: define internal void @__llvm_gcov_writeout()
-; CHECK-SAME: !kcfi_type
+; CHECK-SAME: !kcfi_type ![[#TYPE:]]
 ; CHECK: define internal void @__llvm_gcov_reset()
-; CHECK-SAME: !kcfi_type
+; CHECK-SAME: !kcfi_type ![[#TYPE]]
 ; CHECK: define internal void @__llvm_gcov_init()
-; CHECK-SAME: !kcfi_type
+; CHECK-SAME: !kcfi_type ![[#TYPE]]
+
+; CHECK: ![[#TYPE]] = !{i32 -1522505972}



More information about the cfe-commits mailing list