Skip to content

Commit 55dea62

Browse files
committed
CFI: Fix ICE: encode_const: unexpected type [usize
Fixes rust-lang#100778 and rust-lang#113366, and complements rust-lang#106547 by adding support for encoding const parameters.
1 parent b3c7a7e commit 55dea62

File tree

3 files changed

+104
-34
lines changed

3 files changed

+104
-34
lines changed

compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs

+45-34
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
///
88
/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
99
/// see design document in the tracking issue #89653.
10-
use core::fmt::Display;
1110
use rustc_data_structures::base_n;
1211
use rustc_data_structures::fx::FxHashMap;
1312
use rustc_hir as hir;
13+
use rustc_middle::ty::layout::IntegerExt;
1414
use rustc_middle::ty::{
1515
self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind,
1616
TermKind, Ty, TyCtxt, UintTy,
@@ -19,6 +19,7 @@ use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef};
1919
use rustc_span::def_id::DefId;
2020
use rustc_span::sym;
2121
use rustc_target::abi::call::{Conv, FnAbi};
22+
use rustc_target::abi::Integer;
2223
use rustc_target::spec::abi::Abi;
2324
use std::fmt::Write as _;
2425

@@ -93,44 +94,54 @@ fn encode_const<'tcx>(
9394
dict: &mut FxHashMap<DictKey<'tcx>, usize>,
9495
options: EncodeTyOptions,
9596
) -> String {
96-
// L<element-type>[n]<element-value>E as literal argument
97+
// L<element-type>[n][<element-value>]E as literal argument
9798
let mut s = String::from('L');
9899

99-
// Element type
100-
s.push_str(&encode_ty(tcx, c.ty(), dict, options));
100+
match c.kind() {
101+
// Const parameters
102+
ty::ConstKind::Param(..) => {
103+
// L<element-type>E as literal argument
101104

102-
// The only allowed types of const parameters are bool, u8, u16, u32, u64, u128, usize i8, i16,
103-
// i32, i64, i128, isize, and char. The bool value false is encoded as 0 and true as 1.
104-
fn push_signed_value<T: Display + PartialOrd>(s: &mut String, value: T, zero: T) {
105-
if value < zero {
106-
s.push('n')
107-
};
108-
let _ = write!(s, "{value}");
109-
}
110-
111-
fn push_unsigned_value<T: Display>(s: &mut String, value: T) {
112-
let _ = write!(s, "{value}");
113-
}
105+
// Element type
106+
s.push_str(&encode_ty(tcx, c.ty(), dict, options));
107+
}
114108

115-
if let Some(scalar_int) = c.try_to_scalar_int() {
116-
let signed = c.ty().is_signed();
117-
match scalar_int.size().bits() {
118-
8 if signed => push_signed_value(&mut s, scalar_int.try_to_i8().unwrap(), 0),
119-
16 if signed => push_signed_value(&mut s, scalar_int.try_to_i16().unwrap(), 0),
120-
32 if signed => push_signed_value(&mut s, scalar_int.try_to_i32().unwrap(), 0),
121-
64 if signed => push_signed_value(&mut s, scalar_int.try_to_i64().unwrap(), 0),
122-
128 if signed => push_signed_value(&mut s, scalar_int.try_to_i128().unwrap(), 0),
123-
8 => push_unsigned_value(&mut s, scalar_int.try_to_u8().unwrap()),
124-
16 => push_unsigned_value(&mut s, scalar_int.try_to_u16().unwrap()),
125-
32 => push_unsigned_value(&mut s, scalar_int.try_to_u32().unwrap()),
126-
64 => push_unsigned_value(&mut s, scalar_int.try_to_u64().unwrap()),
127-
128 => push_unsigned_value(&mut s, scalar_int.try_to_u128().unwrap()),
128-
_ => {
129-
bug!("encode_const: unexpected size `{:?}`", scalar_int.size().bits());
109+
// Literal arguments
110+
ty::ConstKind::Value(..) => {
111+
// L<element-type>[n]<element-value>E as literal argument
112+
113+
// Element type
114+
s.push_str(&encode_ty(tcx, c.ty(), dict, options));
115+
116+
// The only allowed types of const values are bool, u8, u16, u32,
117+
// u64, u128, usize i8, i16, i32, i64, i128, isize, and char. The
118+
// bool value false is encoded as 0 and true as 1.
119+
match c.ty().kind() {
120+
ty::Int(ity) => {
121+
let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all(), c.ty());
122+
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
123+
if val < 0 {
124+
s.push('n');
125+
}
126+
let _ = write!(s, "{val}");
127+
}
128+
ty::Uint(_) => {
129+
let val = c.eval_bits(tcx, ty::ParamEnv::reveal_all(), c.ty());
130+
let _ = write!(s, "{val}");
131+
}
132+
ty::Bool => {
133+
let val = c.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap();
134+
let _ = write!(s, "{val}");
135+
}
136+
_ => {
137+
bug!("encode_const: unexpected type `{:?}`", c.ty());
138+
}
130139
}
131-
};
132-
} else {
133-
bug!("encode_const: unexpected type `{:?}`", c.ty());
140+
}
141+
142+
_ => {
143+
bug!("encode_const: unexpected kind `{:?}`", c.kind());
144+
}
134145
}
135146

136147
// Close the "L..E" pair

tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs

+29
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ impl<'a, T, U> Trait4<'a, U> for T {
5353
}
5454
}
5555

56+
pub trait Trait5<T, const N: usize> {
57+
fn quux(&self, _: &[T; N]);
58+
}
59+
60+
#[derive(Copy, Clone)]
61+
pub struct Type5;
62+
63+
impl<T, U, const N: usize> Trait5<U, N> for T {
64+
fn quux(&self, _: &[U; N]) {
65+
}
66+
}
67+
5668
pub fn foo1(a: &dyn Trait1) {
5769
a.foo();
5870
// CHECK-LABEL: define{{.*}}4foo1{{.*}}!type !{{[0-9]+}}
@@ -114,7 +126,24 @@ pub fn bar4<'a>() {
114126
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]")
115127
}
116128

129+
pub fn foo5(a: &dyn Trait5<Type5, 32>) {
130+
let b = &[Type5; 32];
131+
a.quux(&b);
132+
// CHECK-LABEL: define{{.*}}4foo5{{.*}}!type !{{[0-9]+}}
133+
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]")
134+
}
135+
136+
pub fn bar5() {
137+
let a = &[Type5; 32];
138+
foo5(&a);
139+
let b = &a as &dyn Trait5<Type5, 32>;
140+
b.quux(&a);
141+
// CHECK-LABEL: define{{.*}}4bar5{{.*}}!type !{{[0-9]+}}
142+
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]")
143+
}
144+
117145
// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE1]]"}
118146
// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE2]]"}
119147
// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE3]]"}
120148
// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE4]]"}
149+
// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE5]]"}

tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs

+30
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ impl<'a, T, U> Trait4<'a, U> for T {
7777
}
7878
}
7979

80+
pub trait Trait5<T, const N: usize> {
81+
fn quux(&self, _: &[T; N]);
82+
}
83+
84+
pub struct Type5;
85+
86+
impl Copy for Type5 {}
87+
88+
impl<T, U, const N: usize> Trait5<U, N> for T {
89+
fn quux(&self, _: &[U; N]) {
90+
}
91+
}
92+
8093
pub fn foo1(a: &dyn Trait1) {
8194
a.foo();
8295
// CHECK-LABEL: define{{.*}}4foo1{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
@@ -138,7 +151,24 @@ pub fn bar4<'a>() {
138151
// CHECK: call align 4 {{ptr|i32\*}} %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}, {{\{\}\*|ptr|%Type4\*}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ]
139152
}
140153

154+
pub fn foo5(a: &dyn Trait5<Type5, 32>) {
155+
let b = &[Type5; 32];
156+
a.quux(&b);
157+
// CHECK-LABEL: define{{.*}}4foo5{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
158+
// CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, {{\{\}\*|ptr|\[32 x %Type5\]\*}} align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ]
159+
}
160+
161+
pub fn bar5() {
162+
let a = &[Type5; 32];
163+
foo5(&a);
164+
let b = &a as &dyn Trait5<Type5, 32>;
165+
b.quux(&a);
166+
// CHECK-LABEL: define{{.*}}4bar5{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
167+
// CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, {{\{\}\*|ptr|\[32 x %Type5\]\*}} align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ]
168+
}
169+
141170
// CHECK: !{{[0-9]+}} = !{i32 [[TYPE1]]}
142171
// CHECK: !{{[0-9]+}} = !{i32 [[TYPE2]]}
143172
// CHECK: !{{[0-9]+}} = !{i32 [[TYPE3]]}
144173
// CHECK: !{{[0-9]+}} = !{i32 [[TYPE4]]}
174+
// CHECK: !{{[0-9]+}} = !{i32 [[TYPE5]]}

0 commit comments

Comments
 (0)