Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e223485

Browse files
authoredFeb 6, 2025
[X86] Extend kCFI with a 3-bit arity indicator (#121070)
Kernel Control Flow Integrity (kCFI) is a feature that hardens indirect calls by comparing a 32-bit hash of the function pointer's type against a hash of the target function's type. If the hashes do not match, the kernel may panic (or log the hash check failure, depending on the kernel's configuration). These hashes are computed at compile time by applying the xxHash64 algorithm to each mangled canonical function (or function pointer) type, then truncating the result to 32 bits. This hash is written into each indirect-callable function header by encoding it as the 32-bit immediate operand to a `MOVri` instruction, e.g.: ``` __cfi_foo: nop nop nop nop nop nop nop nop nop nop nop movl $199571451, %eax # hash of foo's type = 0xBE537FB foo: ... ``` This PR extends x86-based kCFI with a 3-bit arity indicator encoded in the `MOVri` instruction's register (reg) field as follows: | Arity Indicator | Description | Encoding in reg field | | --------------- | --------------- | --------------- | | 0 | 0 parameters | EAX | | 1 | 1 parameter in RDI | ECX | | 2 | 2 parameters in RDI and RSI | EDX | | 3 | 3 parameters in RDI, RSI, and RDX | EBX | | 4 | 4 parameters in RDI, RSI, RDX, and RCX | ESP | | 5 | 5 parameters in RDI, RSI, RDX, RCX, and R8 | EBP | | 6 | 6 parameters in RDI, RSI, RDX, RCX, R8, and R9 | ESI | | 7 | At least one parameter may be passed on the stack | EDI | For example, if `foo` takes 3 register arguments and no stack arguments then the `MOVri` instruction in its kCFI header would instead be written as: ``` movl $199571451, %ebx # hash of foo's type = 0xBE537FB ``` This PR will benefit other CFI approaches that build on kCFI, such as FineIBT. For example, this proposed enhancement to FineIBT must be able to infer (at kernel init time) which registers are live at an indirect call target: https://lkml.org/lkml/2024/9/27/982. If the arity bits are available in the kCFI function header, then this information is trivial to infer. Note that there is another existing PR proposal that includes the 3-bit arity within the existing 32-bit immediate field, which introduces different security properties: #117121.
1 parent 7a87794 commit e223485

File tree

12 files changed

+270
-1
lines changed

12 files changed

+270
-1
lines changed
 

‎clang/docs/ControlFlowIntegrity.rst

+9
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,15 @@ cross-DSO function address equality. These properties make KCFI easier to
336336
adopt in low-level software. KCFI is limited to checking only function
337337
pointers, and isn't compatible with executable-only memory.
338338

339+
``-fsanitize-kcfi-arity``
340+
-----------------------------
341+
342+
For supported targets, this feature extends kCFI by telling the compiler to
343+
record information about each indirect-callable function's arity (i.e., the
344+
number of arguments passed in registers) into the binary. Some kernel CFI
345+
techniques, such as FineIBT, may be able to use this information to provide
346+
enhanced security.
347+
339348
Member Function Pointer Call Checking
340349
=====================================
341350

‎clang/docs/UsersManual.rst

+6
Original file line numberDiff line numberDiff line change
@@ -2223,6 +2223,12 @@ are listed below.
22232223

22242224
This option is currently experimental.
22252225

2226+
.. option:: -fsanitize-kcfi-arity
2227+
2228+
Extends kernel indirect call forward-edge control flow integrity with
2229+
additional function arity information (for supported targets). See
2230+
:doc:`ControlFlowIntegrity` for more details.
2231+
22262232
.. option:: -fstrict-vtable-pointers
22272233

22282234
Enable optimizations based on the strict rules for overwriting polymorphic

‎clang/include/clang/Basic/CodeGenOptions.def

+1
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ CODEGENOPT(SanitizeCfiICallNormalizeIntegers, 1, 0) ///< Normalize integer types
277277
///< CFI icall function signatures
278278
CODEGENOPT(SanitizeCfiCanonicalJumpTables, 1, 0) ///< Make jump table symbols canonical
279279
///< instead of creating a local jump table.
280+
CODEGENOPT(SanitizeKcfiArity, 1, 0) ///< Embed arity in KCFI patchable function prefix
280281
CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage
281282
///< instrumentation.
282283
CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage

‎clang/include/clang/Basic/DiagnosticDriverKinds.td

+2
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ def err_drv_cannot_open_randomize_layout_seed_file : Error<
209209
"cannot read randomize layout seed file '%0'">;
210210
def err_drv_invalid_version_number : Error<
211211
"invalid version number in '%0'">;
212+
def err_drv_kcfi_arity_unsupported_target : Error<
213+
"target '%0' is unsupported by -fsanitize-kcfi-arity">;
212214
def err_drv_no_linker_llvm_support : Error<
213215
"'%0': unable to pass LLVM bit-code files to linker">;
214216
def err_drv_no_ast_support : Error<

‎clang/include/clang/Basic/Features.def

+1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ FEATURE(is_trivially_constructible, LangOpts.CPlusPlus)
254254
FEATURE(is_trivially_copyable, LangOpts.CPlusPlus)
255255
FEATURE(is_union, LangOpts.CPlusPlus)
256256
FEATURE(kcfi, LangOpts.Sanitize.has(SanitizerKind::KCFI))
257+
FEATURE(kcfi_arity, LangOpts.Sanitize.has(SanitizerKind::KCFI))
257258
FEATURE(modules, LangOpts.Modules)
258259
FEATURE(safe_stack, LangOpts.Sanitize.has(SanitizerKind::SafeStack))
259260
FEATURE(shadow_call_stack,

‎clang/include/clang/Driver/Options.td

+4
Original file line numberDiff line numberDiff line change
@@ -2526,6 +2526,10 @@ defm sanitize_cfi_canonical_jump_tables : BoolOption<"f", "sanitize-cfi-canonica
25262526
"Do not make">,
25272527
BothFlags<[], [ClangOption], " the jump table addresses canonical in the symbol table">>,
25282528
Group<f_clang_Group>;
2529+
def fsanitize_kcfi_arity : Flag<["-"], "fsanitize-kcfi-arity">,
2530+
Group<f_clang_Group>,
2531+
HelpText<"Embed function arity information into the KCFI patchable function prefix">,
2532+
MarshallingInfoFlag<CodeGenOpts<"SanitizeKcfiArity">>;
25292533
defm sanitize_stats : BoolOption<"f", "sanitize-stats",
25302534
CodeGenOpts<"SanitizeStats">, DefaultFalse,
25312535
PosFlag<SetTrue, [], [ClangOption], "Enable">,

‎clang/include/clang/Driver/SanitizerArgs.h

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class SanitizerArgs {
4343
bool CfiICallGeneralizePointers = false;
4444
bool CfiICallNormalizeIntegers = false;
4545
bool CfiCanonicalJumpTables = false;
46+
bool KcfiArity = false;
4647
int AsanFieldPadding = 0;
4748
bool SharedRuntime = false;
4849
bool StableABI = false;

‎clang/lib/CodeGen/CodeGenModule.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,8 @@ void CodeGenModule::Release() {
11491149
if (CodeGenOpts.PatchableFunctionEntryOffset)
11501150
getModule().addModuleFlag(llvm::Module::Override, "kcfi-offset",
11511151
CodeGenOpts.PatchableFunctionEntryOffset);
1152+
if (CodeGenOpts.SanitizeKcfiArity)
1153+
getModule().addModuleFlag(llvm::Module::Override, "kcfi-arity", 1);
11521154
}
11531155

11541156
if (CodeGenOpts.CFProtectionReturn &&

‎clang/lib/Driver/SanitizerArgs.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
832832
CfiICallNormalizeIntegers =
833833
Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers);
834834

835+
KcfiArity = Args.hasArg(options::OPT_fsanitize_kcfi_arity);
836+
835837
if (AllAddedKinds & SanitizerKind::CFI && DiagnoseErrors)
836838
D.Diag(diag::err_drv_argument_not_allowed_with)
837839
<< "-fsanitize=kcfi"
@@ -1386,6 +1388,14 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
13861388
if (CfiICallNormalizeIntegers)
13871389
CmdArgs.push_back("-fsanitize-cfi-icall-experimental-normalize-integers");
13881390

1391+
if (KcfiArity) {
1392+
if (!TC.getTriple().isOSLinux() || !TC.getTriple().isArch64Bit()) {
1393+
TC.getDriver().Diag(clang::diag::err_drv_kcfi_arity_unsupported_target)
1394+
<< TC.getTriple().str();
1395+
}
1396+
CmdArgs.push_back("-fsanitize-kcfi-arity");
1397+
}
1398+
13891399
if (CfiCanonicalJumpTables)
13901400
CmdArgs.push_back("-fsanitize-cfi-canonical-jump-tables");
13911401

‎clang/test/CodeGen/kcfi-arity.c

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fsanitize-kcfi-arity -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fsanitize-kcfi-arity -x c++ -o - %s | FileCheck %s
3+
#if !__has_feature(kcfi_arity)
4+
#error Missing kcfi_arity?
5+
#endif
6+
7+
// CHECK: ![[#]] = !{i32 4, !"kcfi-arity", i32 1}

‎llvm/lib/Target/X86/X86AsmPrinter.cpp

+22-1
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,29 @@ void X86AsmPrinter::emitKCFITypeId(const MachineFunction &MF) {
181181
// Embed the type hash in the X86::MOV32ri instruction to avoid special
182182
// casing object file parsers.
183183
EmitKCFITypePadding(MF);
184+
unsigned DestReg = X86::EAX;
185+
186+
if (F.getParent()->getModuleFlag("kcfi-arity")) {
187+
// The ArityToRegMap assumes the 64-bit Linux kernel ABI
188+
const auto &Triple = MF.getTarget().getTargetTriple();
189+
assert(Triple.isArch64Bit() && Triple.isOSLinux());
190+
191+
// Determine the function's arity (i.e., the number of arguments) at the ABI
192+
// level by counting the number of parameters that are passed
193+
// as registers, such as pointers and 64-bit (or smaller) integers. The
194+
// Linux x86-64 ABI allows up to 6 parameters to be passed in GPRs.
195+
// Additional parameters or parameters larger than 64 bits may be passed on
196+
// the stack, in which case the arity is denoted as 7.
197+
const unsigned ArityToRegMap[8] = {X86::EAX, X86::ECX, X86::EDX, X86::EBX,
198+
X86::ESP, X86::EBP, X86::ESI, X86::EDI};
199+
int Arity = MF.getInfo<X86MachineFunctionInfo>()->getArgumentStackSize() > 0
200+
? 7
201+
: MF.getRegInfo().liveins().size();
202+
DestReg = ArityToRegMap[Arity];
203+
}
204+
184205
EmitAndCountInstruction(MCInstBuilder(X86::MOV32ri)
185-
.addReg(X86::EAX)
206+
.addReg(DestReg)
186207
.addImm(MaskKCFIType(Type->getZExtValue())));
187208

188209
if (MAI->hasDotTypeDotSizeDirective()) {

‎llvm/test/CodeGen/X86/kcfi-arity.ll

+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
; RUN: llc -mtriple=x86_64-unknown-linux-gnu -verify-machineinstrs < %s | FileCheck %s --check-prefix=ASM
2+
; RUN: llc -mtriple=x86_64-unknown-linux-gnu -verify-machineinstrs -stop-after=finalize-isel < %s | FileCheck %s --check-prefixes=MIR,ISEL
3+
; RUN: llc -mtriple=x86_64-unknown-linux-gnu -verify-machineinstrs -stop-after=kcfi < %s | FileCheck %s --check-prefixes=MIR,KCFI
4+
5+
; ASM: .p2align 4
6+
; ASM: .type __cfi_f1,@function
7+
; ASM-LABEL: __cfi_f1:
8+
; ASM-NEXT: nop
9+
; ASM-NEXT: nop
10+
; ASM-NEXT: nop
11+
; ASM-NEXT: nop
12+
; ASM-NEXT: nop
13+
; ASM-NEXT: nop
14+
; ASM-NEXT: nop
15+
; ASM-NEXT: nop
16+
; ASM-NEXT: nop
17+
; ASM-NEXT: nop
18+
; ASM-NEXT: nop
19+
; ASM-NEXT: movl $12345678, %ecx
20+
; ASM-LABEL: .Lcfi_func_end0:
21+
; ASM-NEXT: .size __cfi_f1, .Lcfi_func_end0-__cfi_f1
22+
define void @f1(ptr noundef %x) !kcfi_type !1 {
23+
; ASM-LABEL: f1:
24+
; ASM: # %bb.0:
25+
; ASM: movl $4282621618, %r10d # imm = 0xFF439EB2
26+
; ASM-NEXT: addl -4(%rdi), %r10d
27+
; ASM-NEXT: je .Ltmp0
28+
; ASM-NEXT: .Ltmp1:
29+
; ASM-NEXT: ud2
30+
; ASM-NEXT: .section .kcfi_traps,"ao",@progbits,.text
31+
; ASM-NEXT: .Ltmp2:
32+
; ASM-NEXT: .long .Ltmp1-.Ltmp2
33+
; ASM-NEXT: .text
34+
; ASM-NEXT: .Ltmp0:
35+
; ASM-NEXT: callq *%rdi
36+
37+
; MIR-LABEL: name: f1
38+
; MIR: body:
39+
; ISEL: CALL64r %0, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, cfi-type 12345678
40+
; KCFI: BUNDLE{{.*}} {
41+
; KCFI-NEXT: KCFI_CHECK $rdi, 12345678, implicit-def $r10, implicit-def $r11, implicit-def $eflags
42+
; KCFI-NEXT: CALL64r killed $rdi, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp
43+
; KCFI-NEXT: }
44+
call void %x() [ "kcfi"(i32 12345678) ]
45+
ret void
46+
}
47+
48+
; ASM-NOT: __cfi_f2:
49+
define void @f2(ptr noundef %x) {
50+
; ASM-LABEL: f2:
51+
52+
; MIR-LABEL: name: f2
53+
; MIR: body:
54+
; ISEL: TCRETURNri64 %0, 0, csr_64, implicit $rsp, implicit $ssp, cfi-type 12345678
55+
; KCFI: BUNDLE{{.*}} {
56+
; KCFI-NEXT: KCFI_CHECK $rdi, 12345678, implicit-def $r10, implicit-def $r11, implicit-def $eflags
57+
; KCFI-NEXT: TAILJMPr64 killed $rdi, csr_64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp
58+
; KCFI-NEXT: }
59+
tail call void %x() [ "kcfi"(i32 12345678) ]
60+
ret void
61+
}
62+
63+
; ASM-NOT: __cfi_f3:
64+
define void @f3(ptr noundef %x) #0 {
65+
; ASM-LABEL: f3:
66+
; MIR-LABEL: name: f3
67+
; MIR: body:
68+
; ISEL: CALL64pcrel32 &__llvm_retpoline_r11, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, implicit killed $r11, cfi-type 12345678
69+
; KCFI: BUNDLE{{.*}} {
70+
; KCFI-NEXT: KCFI_CHECK $r11, 12345678, implicit-def $r10, implicit-def $r11, implicit-def $eflags
71+
; KCFI-NEXT: CALL64pcrel32 &__llvm_retpoline_r11, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, implicit internal killed $r11
72+
; KCFI-NEXT: }
73+
call void %x() [ "kcfi"(i32 12345678) ]
74+
ret void
75+
}
76+
77+
; ASM-NOT: __cfi_f4:
78+
define void @f4(ptr noundef %x) #0 {
79+
; ASM-LABEL: f4:
80+
; MIR-LABEL: name: f4
81+
; MIR: body:
82+
; ISEL: TCRETURNdi64 &__llvm_retpoline_r11, 0, csr_64, implicit $rsp, implicit $ssp, implicit killed $r11, cfi-type 12345678
83+
; KCFI: BUNDLE{{.*}} {
84+
; KCFI-NEXT: KCFI_CHECK $r11, 12345678, implicit-def $r10, implicit-def $r11, implicit-def $eflags
85+
; KCFI-NEXT: TAILJMPd64 &__llvm_retpoline_r11, csr_64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp, implicit internal killed $r11
86+
; KCFI-NEXT: }
87+
tail call void %x() [ "kcfi"(i32 12345678) ]
88+
ret void
89+
}
90+
91+
;; Ensure we emit Value + 1 for unwanted values (e.g. endbr64 == 4196274163).
92+
; ASM-LABEL: __cfi_f5:
93+
; ASM: movl $4196274164, %ecx # imm = 0xFA1E0FF4
94+
define void @f5(ptr noundef %x) !kcfi_type !2 {
95+
; ASM-LABEL: f5:
96+
; ASM: movl $98693132, %r10d # imm = 0x5E1F00C
97+
tail call void %x() [ "kcfi"(i32 4196274163) ]
98+
ret void
99+
}
100+
101+
;; Ensure we emit Value + 1 for unwanted values (e.g. -endbr64 == 98693133).
102+
; ASM-LABEL: __cfi_f6:
103+
; ASM: movl $98693134, %ecx # imm = 0x5E1F00E
104+
define void @f6(ptr noundef %x) !kcfi_type !3 {
105+
; ASM-LABEL: f6:
106+
; ASM: movl $4196274162, %r10d # imm = 0xFA1E0FF2
107+
tail call void %x() [ "kcfi"(i32 98693133) ]
108+
ret void
109+
}
110+
111+
@g = external local_unnamed_addr global ptr, align 8
112+
113+
define void @f7() {
114+
; MIR-LABEL: name: f7
115+
; MIR: body:
116+
; ISEL: TCRETURNmi64 killed %0, 1, $noreg, 0, $noreg, 0, csr_64, implicit $rsp, implicit $ssp, cfi-type 12345678
117+
; KCFI: $r11 = MOV64rm killed renamable $rax, 1, $noreg, 0, $noreg
118+
; KCFI-NEXT: BUNDLE{{.*}} {
119+
; KCFI-NEXT: KCFI_CHECK $r11, 12345678, implicit-def $r10, implicit-def $r11, implicit-def $eflags
120+
; KCFI-NEXT: TAILJMPr64 internal $r11, csr_64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp
121+
; KCFI-NEXT: }
122+
%1 = load ptr, ptr @g, align 8
123+
tail call void %1() [ "kcfi"(i32 12345678) ]
124+
ret void
125+
}
126+
127+
define void @f8() {
128+
; MIR-LABEL: name: f8
129+
; MIR: body:
130+
; ISEL: CALL64m killed %0, 1, $noreg, 0, $noreg, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, cfi-type 12345678
131+
; KCFI: $r11 = MOV64rm killed renamable $rax, 1, $noreg, 0, $noreg
132+
; KCFI-NEXT: BUNDLE{{.*}} {
133+
; KCFI-NEXT: KCFI_CHECK $r11, 12345678, implicit-def $r10, implicit-def $r11, implicit-def $eflags
134+
; KCFI-NEXT: CALL64r internal $r11, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp
135+
; KCFI-NEXT: }
136+
%1 = load ptr, ptr @g, align 8
137+
call void %1() [ "kcfi"(i32 12345678) ]
138+
ret void
139+
}
140+
141+
%struct.S9 = type { [10 x i64] }
142+
143+
;; Ensure that functions with large (e.g., greater than 8 bytes) arguments passed on the stack are assigned arity=7
144+
; ASM-LABEL: __cfi_f9:
145+
; ASM: movl $199571451, %edi # imm = 0xBE537FB
146+
define dso_local void @f9(ptr noundef byval(%struct.S9) align 8 %s) !kcfi_type !4 {
147+
entry:
148+
ret void
149+
}
150+
151+
;; Ensure that functions with fewer than 7 register arguments and no stack arguments are assigned arity<7
152+
; ASM-LABEL: __cfi_f10:
153+
; ASM: movl $1046421190, %esi # imm = 0x3E5F1EC6
154+
define dso_local void @f10(i32 noundef %v1, i32 noundef %v2, i32 noundef %v3, i32 noundef %v4, i32 noundef %v5, i32 noundef %v6) #0 !kcfi_type !5 {
155+
entry:
156+
%v1.addr = alloca i32, align 4
157+
%v2.addr = alloca i32, align 4
158+
%v3.addr = alloca i32, align 4
159+
%v4.addr = alloca i32, align 4
160+
%v5.addr = alloca i32, align 4
161+
%v6.addr = alloca i32, align 4
162+
store i32 %v1, ptr %v1.addr, align 4
163+
store i32 %v2, ptr %v2.addr, align 4
164+
store i32 %v3, ptr %v3.addr, align 4
165+
store i32 %v4, ptr %v4.addr, align 4
166+
store i32 %v5, ptr %v5.addr, align 4
167+
store i32 %v6, ptr %v6.addr, align 4
168+
ret void
169+
}
170+
171+
;; Ensure that functions with greater than 7 register arguments and no stack arguments are assigned arity=7
172+
; ASM-LABEL: __cfi_f11:
173+
; ASM: movl $1342488295, %edi # imm = 0x5004BEE7
174+
define dso_local void @f11(i32 noundef %v1, i32 noundef %v2, i32 noundef %v3, i32 noundef %v4, i32 noundef %v5, i32 noundef %v6, i32 noundef %v7, i32 noundef %v8) #0 !kcfi_type !6 {
175+
entry:
176+
%v1.addr = alloca i32, align 4
177+
%v2.addr = alloca i32, align 4
178+
%v3.addr = alloca i32, align 4
179+
%v4.addr = alloca i32, align 4
180+
%v5.addr = alloca i32, align 4
181+
%v6.addr = alloca i32, align 4
182+
%v7.addr = alloca i32, align 4
183+
%v8.addr = alloca i32, align 4
184+
store i32 %v1, ptr %v1.addr, align 4
185+
store i32 %v2, ptr %v2.addr, align 4
186+
store i32 %v3, ptr %v3.addr, align 4
187+
store i32 %v4, ptr %v4.addr, align 4
188+
store i32 %v5, ptr %v5.addr, align 4
189+
store i32 %v6, ptr %v6.addr, align 4
190+
store i32 %v7, ptr %v7.addr, align 4
191+
store i32 %v8, ptr %v8.addr, align 4
192+
ret void
193+
}
194+
195+
attributes #0 = { "target-features"="+retpoline-indirect-branches,+retpoline-indirect-calls" }
196+
197+
!llvm.module.flags = !{!0, !7}
198+
!0 = !{i32 4, !"kcfi", i32 1}
199+
!1 = !{i32 12345678}
200+
!2 = !{i32 4196274163}
201+
!3 = !{i32 98693133}
202+
!4 = !{i32 199571451}
203+
!5 = !{i32 1046421190}
204+
!6 = !{i32 1342488295}
205+
!7 = !{i32 4, !"kcfi-arity", i32 1}

0 commit comments

Comments
 (0)
Failed to load comments.