https://github.com/kees created https://github.com/llvm/llvm-project/pull/214827
-fsanitize-kcfi-hash= is a CC1Option that selects the hash algorithm used to derive KCFI type IDs (xxHash64 or FNV-1a), but the driver never claimed or forwarded it. As a result, invocations like clang -fsanitize=kcfi -fsanitize-kcfi-hash=FNV-1a foo.c silently dropped the flag with an "argument unused during compilation" warning; users had to route it through -Xclang to reach cc1. This is particularly awkward for build systems (e.g. the Linux kernel) that want to select FNV-1a for -fsanitize=kcfi builds. Handle the option in SanitizerArgs alongside -fsanitize-kcfi-arity: capture the last-specified value when KCFI is enabled and forward it to cc1 as -fsanitize-kcfi-hash=<value>. Values are still validated by cc1's tablegen-driven Values<"xxHash64,FNV-1a"> checker, so bad values produce the usual "invalid value" diagnostic. When -fsanitize=kcfi is not specified, the flag remains unclaimed and triggers -Wunused-command-line-argument, matching the behavior of the sibling -fsanitize-kcfi-arity option. Extend clang/test/Driver/fsanitize-cfi.c (which already covers other KCFI-mode cc1 arg forwarding, e.g. -fsanitize-cfi-icall-generalize- pointers) with forwarding, last-wins, invalid-value, and unused-when-no-KCFI cases for both -fsanitize-kcfi-hash= and -fsanitize-kcfi-arity. The latter had no prior driver-side coverage. Assisted-by: Claude Opus 4.7 >From 751c11296b301750da0a26d4363d4ef313ad9123 Mon Sep 17 00:00:00 2001 From: Kees Cook <[email protected]> Date: Fri, 7 Aug 2026 11:37:22 -0700 Subject: [PATCH] [Driver][KCFI] Forward -fsanitize-kcfi-hash= to cc1 -fsanitize-kcfi-hash= is a CC1Option that selects the hash algorithm used to derive KCFI type IDs (xxHash64 or FNV-1a), but the driver never claimed or forwarded it. As a result, invocations like clang -fsanitize=kcfi -fsanitize-kcfi-hash=FNV-1a foo.c silently dropped the flag with an "argument unused during compilation" warning; users had to route it through -Xclang to reach cc1. This is particularly awkward for build systems (e.g. the Linux kernel) that want to select FNV-1a for -fsanitize=kcfi builds. Handle the option in SanitizerArgs alongside -fsanitize-kcfi-arity: capture the last-specified value when KCFI is enabled and forward it to cc1 as -fsanitize-kcfi-hash=<value>. Values are still validated by cc1's tablegen-driven Values<"xxHash64,FNV-1a"> checker, so bad values produce the usual "invalid value" diagnostic. When -fsanitize=kcfi is not specified, the flag remains unclaimed and triggers -Wunused-command-line-argument, matching the behavior of the sibling -fsanitize-kcfi-arity option. Extend clang/test/Driver/fsanitize-cfi.c (which already covers other KCFI-mode cc1 arg forwarding, e.g. -fsanitize-cfi-icall-generalize- pointers) with forwarding, last-wins, invalid-value, and unused-when-no-KCFI cases for both -fsanitize-kcfi-hash= and -fsanitize-kcfi-arity. The latter had no prior driver-side coverage. Assisted-by: Claude Opus 4.7 --- clang/include/clang/Driver/SanitizerArgs.h | 1 + clang/lib/Driver/SanitizerArgs.cpp | 6 +++++ clang/test/Driver/fsanitize-cfi.c | 28 ++++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 6a01b3e36d44c..b0ab97a2d5d45 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -49,6 +49,7 @@ class SanitizerArgs { bool CfiICallNormalizeIntegers = false; bool CfiCanonicalJumpTables = false; bool KcfiArity = false; + std::string KcfiHash; int AsanFieldPadding = 0; bool SharedRuntime = false; bool StableABI = false; diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index c77ba78122a81..07d9ab9594482 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -964,6 +964,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, KcfiArity = Args.hasArg(options::OPT_fsanitize_kcfi_arity); + if (const Arg *A = Args.getLastArg(options::OPT_fsanitize_kcfi_hash_EQ)) + KcfiHash = A->getValue(); + if (AllAddedKinds & SanitizerKind::CFI && DiagnoseErrors) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fsanitize=kcfi" @@ -1573,6 +1576,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, CmdArgs.push_back("-fsanitize-kcfi-arity"); } + if (!KcfiHash.empty()) + CmdArgs.push_back(Args.MakeArgString("-fsanitize-kcfi-hash=" + KcfiHash)); + if (CfiCanonicalJumpTables) CmdArgs.push_back("-fsanitize-cfi-canonical-jump-tables"); diff --git a/clang/test/Driver/fsanitize-cfi.c b/clang/test/Driver/fsanitize-cfi.c index c58ad3b8c2f1c..def3e61908ee7 100644 --- a/clang/test/Driver/fsanitize-cfi.c +++ b/clang/test/Driver/fsanitize-cfi.c @@ -96,3 +96,31 @@ // RUN: not %clang --target=x86_64-linux-gnu -fsanitize=kcfi,function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-KCFI-FUNCTION // CHECK-KCFI-FUNCTION: error: invalid argument '-fsanitize=kcfi' not allowed with '-fsanitize=function' + +// -fsanitize-kcfi-arity is forwarded to cc1 when KCFI is enabled. +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=kcfi -fsanitize-kcfi-arity %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-KCFI-ARITY +// CHECK-KCFI-ARITY: "-fsanitize-kcfi-arity" + +// Without -fsanitize=kcfi, -fsanitize-kcfi-arity is unused. +// RUN: %clang --target=x86_64-linux-gnu -fsanitize-kcfi-arity -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-KCFI-ARITY-UNUSED +// CHECK-KCFI-ARITY-UNUSED: warning: argument unused during compilation: '-fsanitize-kcfi-arity' + +// -fsanitize-kcfi-hash= is forwarded to cc1 when KCFI is enabled. +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=kcfi -fsanitize-kcfi-hash=FNV-1a %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-KCFI-HASH-FNV +// CHECK-KCFI-HASH-FNV: "-fsanitize-kcfi-hash=FNV-1a" + +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=kcfi -fsanitize-kcfi-hash=xxHash64 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-KCFI-HASH-XXHASH +// CHECK-KCFI-HASH-XXHASH: "-fsanitize-kcfi-hash=xxHash64" + +// If -fsanitize-kcfi-hash= is given more than once, the last value wins. +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=kcfi -fsanitize-kcfi-hash=xxHash64 -fsanitize-kcfi-hash=FNV-1a %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-KCFI-HASH-LAST +// CHECK-KCFI-HASH-LAST: "-fsanitize-kcfi-hash=FNV-1a" +// CHECK-KCFI-HASH-LAST-NOT: "-fsanitize-kcfi-hash=xxHash64" + +// Invalid values are diagnosed by cc1 (driver forwards verbatim). +// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=kcfi -fsanitize-kcfi-hash=bogus -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-KCFI-HASH-BAD +// CHECK-KCFI-HASH-BAD: error: invalid value 'bogus' in '-fsanitize-kcfi-hash=bogus' + +// Without -fsanitize=kcfi, -fsanitize-kcfi-hash= is unused. +// RUN: %clang --target=x86_64-linux-gnu -fsanitize-kcfi-hash=FNV-1a -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-KCFI-HASH-UNUSED +// CHECK-KCFI-HASH-UNUSED: warning: argument unused during compilation: '-fsanitize-kcfi-hash=FNV-1a' _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
