Skip to content

Commit 95a992a

Browse files
committedSep 16, 2022
Auto merge of #97800 - pnkfelix:issue-97463-fix-aarch64-call-abi-does-not-zeroext, r=wesleywiser
Aarch64 call abi does not zeroext (and one cannot assume it does so) Fix #97463
2 parents 4d4e51e + a2de75a commit 95a992a

File tree

11 files changed

+423
-11
lines changed

11 files changed

+423
-11
lines changed
 

‎compiler/rustc_target/src/abi/call/aarch64.rs

+34-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
22
use crate::abi::{HasDataLayout, TyAbiInterface};
33

4+
/// Given integer-types M and register width N (e.g. M=u16 and N=32 bits), the
5+
/// `ParamExtension` policy specifies how a uM value should be treated when
6+
/// passed via register or stack-slot of width N. See also rust-lang/rust#97463.
7+
#[derive(Copy, Clone, PartialEq)]
8+
pub enum ParamExtension {
9+
/// Indicates that when passing an i8/i16, either as a function argument or
10+
/// as a return value, it must be sign-extended to 32 bits, and likewise a
11+
/// u8/u16 must be zero-extended to 32-bits. (This variant is here to
12+
/// accommodate Apple's deviation from the usual AArch64 ABI as defined by
13+
/// ARM.)
14+
///
15+
/// See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
16+
ExtendTo32Bits,
17+
18+
/// Indicates that no sign- nor zero-extension is performed: if a value of
19+
/// type with bitwidth M is passed as function argument or return value,
20+
/// then M bits are copied into the least significant M bits, and the
21+
/// remaining bits of the register (or word of memory) are untouched.
22+
NoExtension,
23+
}
24+
425
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
526
where
627
Ty: TyAbiInterface<'a, C> + Copy,
@@ -24,13 +45,16 @@ where
2445
})
2546
}
2647

27-
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
48+
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, param_policy: ParamExtension)
2849
where
2950
Ty: TyAbiInterface<'a, C> + Copy,
3051
C: HasDataLayout,
3152
{
3253
if !ret.layout.is_aggregate() {
33-
ret.extend_integer_width_to(32);
54+
match param_policy {
55+
ParamExtension::ExtendTo32Bits => ret.extend_integer_width_to(32),
56+
ParamExtension::NoExtension => {}
57+
}
3458
return;
3559
}
3660
if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
@@ -46,13 +70,16 @@ where
4670
ret.make_indirect();
4771
}
4872

49-
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
73+
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, param_policy: ParamExtension)
5074
where
5175
Ty: TyAbiInterface<'a, C> + Copy,
5276
C: HasDataLayout,
5377
{
5478
if !arg.layout.is_aggregate() {
55-
arg.extend_integer_width_to(32);
79+
match param_policy {
80+
ParamExtension::ExtendTo32Bits => arg.extend_integer_width_to(32),
81+
ParamExtension::NoExtension => {}
82+
}
5683
return;
5784
}
5885
if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
@@ -68,19 +95,19 @@ where
6895
arg.make_indirect();
6996
}
7097

71-
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
98+
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, param_policy: ParamExtension)
7299
where
73100
Ty: TyAbiInterface<'a, C> + Copy,
74101
C: HasDataLayout,
75102
{
76103
if !fn_abi.ret.is_ignore() {
77-
classify_ret(cx, &mut fn_abi.ret);
104+
classify_ret(cx, &mut fn_abi.ret, param_policy);
78105
}
79106

80107
for arg in fn_abi.args.iter_mut() {
81108
if arg.is_ignore() {
82109
continue;
83110
}
84-
classify_arg(cx, arg);
111+
classify_arg(cx, arg, param_policy);
85112
}
86113
}

‎compiler/rustc_target/src/abi/call/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,14 @@ impl<'a, Ty> FnAbi<'a, Ty> {
685685
}
686686
}
687687
},
688-
"aarch64" => aarch64::compute_abi_info(cx, self),
688+
"aarch64" => {
689+
let param_policy = if cx.target_spec().is_like_osx {
690+
aarch64::ParamExtension::ExtendTo32Bits
691+
} else {
692+
aarch64::ParamExtension::NoExtension
693+
};
694+
aarch64::compute_abi_info(cx, self, param_policy)
695+
}
689696
"amdgpu" => amdgpu::compute_abi_info(cx, self),
690697
"arm" => arm::compute_abi_info(cx, self),
691698
"avr" => avr::compute_abi_info(self),

‎compiler/rustc_target/src/spec/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,8 @@ pub struct TargetOptions {
13521352
pub abi_return_struct_as_int: bool,
13531353
/// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS,
13541354
/// in particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false.
1355+
/// Also indiates whether to use Apple-specific ABI changes, such as extending function
1356+
/// parameters to 32-bits.
13551357
pub is_like_osx: bool,
13561358
/// Whether the target toolchain is like Solaris's.
13571359
/// Only useful for compiling against Illumos/Solaris,

‎src/test/auxiliary/rust_test_helpers.c

+12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Helper functions used only in tests
22

33
#include <stdint.h>
4+
#include <stdlib.h>
45
#include <assert.h>
56
#include <stdarg.h>
67

@@ -415,3 +416,14 @@ rust_dbg_unpack_option_u64u64(struct U8TaggedEnumOptionU64U64 o, uint64_t *a, ui
415416
return 0;
416417
}
417418
}
419+
420+
uint16_t issue_97463_leak_uninit_data(uint32_t a, uint32_t b, uint32_t c) {
421+
struct bloc { uint16_t a; uint16_t b; uint16_t c; };
422+
struct bloc *data = malloc(sizeof(struct bloc));
423+
424+
data->a = a & 0xFFFF;
425+
data->b = b & 0xFFFF;
426+
data->c = c & 0xFFFF;
427+
428+
return data->b; /* leak data */
429+
}

‎src/test/codegen/abi-repr-ext.rs

+44-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,56 @@
11
// compile-flags: -O
22

3-
#![crate_type="lib"]
3+
// revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv
4+
5+
//[x86_64] compile-flags: --target x86_64-unknown-uefi
6+
//[x86_64] needs-llvm-components: x86
7+
//[i686] compile-flags: --target i686-unknown-linux-musl
8+
//[i686] needs-llvm-components: x86
9+
//[aarch64-windows] compile-flags: --target aarch64-pc-windows-msvc
10+
//[aarch64-windows] needs-llvm-components: aarch64
11+
//[aarch64-linux] compile-flags: --target aarch64-unknown-linux-gnu
12+
//[aarch64-linux] needs-llvm-components: aarch64
13+
//[aarch64-apple] compile-flags: --target aarch64-apple-darwin
14+
//[aarch64-apple] needs-llvm-components: aarch64
15+
//[arm] compile-flags: --target armv7r-none-eabi
16+
//[arm] needs-llvm-components: arm
17+
//[riscv] compile-flags: --target riscv64gc-unknown-none-elf
18+
//[riscv] needs-llvm-components: riscv
19+
20+
// See bottom of file for a corresponding C source file that is meant to yield
21+
// equivalent declarations.
22+
#![feature(no_core, lang_items)]
23+
#![crate_type = "lib"]
24+
#![no_std]
25+
#![no_core]
26+
27+
#[lang="sized"] trait Sized { }
28+
#[lang="freeze"] trait Freeze { }
29+
#[lang="copy"] trait Copy { }
430

531
#[repr(i8)]
632
pub enum Type {
733
Type1 = 0,
834
Type2 = 1
935
}
1036

11-
// CHECK: define{{( dso_local)?}} noundef signext i8 @test()
37+
// To accommodate rust#97800, one might consider writing the below as:
38+
//
39+
// `define{{( dso_local)?}} noundef{{( signext)?}} i8 @test()`
40+
//
41+
// but based on rust#80556, it seems important to actually check for the
42+
// presence of the `signext` for those targets where we expect it.
43+
44+
// CHECK: define{{( dso_local)?}} noundef
45+
// x86_64-SAME: signext
46+
// aarch64-apple-SAME: signext
47+
// aarch64-windows-NOT: signext
48+
// aarch64-linux-NOT: signext
49+
// arm-SAME: signext
50+
// riscv-SAME: signext
51+
// CHECK-SAME: i8 @test()
52+
53+
1254
#[no_mangle]
1355
pub extern "C" fn test() -> Type {
1456
Type::Type1

‎src/test/codegen/pic-relocation-model.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ pub fn call_foreign_fn() -> u8 {
1010
}
1111
}
1212

13-
// CHECK: declare zeroext i8 @foreign_fn()
13+
// (Allow but do not require `zeroext` here, because it is not worth effort to
14+
// spell out which targets have it and which ones do not; see rust#97800.)
15+
16+
// CHECK: declare{{( zeroext)?}} i8 @foreign_fn()
1417
extern "C" {fn foreign_fn() -> u8;}
1518

1619
// CHECK: !{i32 {{[78]}}, !"PIC Level", i32 2}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
// compile-flags: -Cno-prepopulate-passes
2+
3+
// revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv
4+
5+
//[x86_64] compile-flags: --target x86_64-unknown-uefi
6+
//[x86_64] needs-llvm-components: x86
7+
//[i686] compile-flags: --target i686-unknown-linux-musl
8+
//[i686] needs-llvm-components: x86
9+
//[aarch64-windows] compile-flags: --target aarch64-pc-windows-msvc
10+
//[aarch64-windows] needs-llvm-components: aarch64
11+
//[aarch64-linux] compile-flags: --target aarch64-unknown-linux-gnu
12+
//[aarch64-linux] needs-llvm-components: aarch64
13+
//[aarch64-apple] compile-flags: --target aarch64-apple-darwin
14+
//[aarch64-apple] needs-llvm-components: aarch64
15+
//[arm] compile-flags: --target armv7r-none-eabi
16+
//[arm] needs-llvm-components: arm
17+
//[riscv] compile-flags: --target riscv64gc-unknown-none-elf
18+
//[riscv] needs-llvm-components: riscv
19+
20+
// See bottom of file for a corresponding C source file that is meant to yield
21+
// equivalent declarations.
22+
#![feature(no_core, lang_items)]
23+
#![crate_type = "lib"]
24+
#![no_std]
25+
#![no_core]
26+
27+
#[lang="sized"] trait Sized { }
28+
#[lang="freeze"] trait Freeze { }
29+
#[lang="copy"] trait Copy { }
30+
31+
// The patterns in this file are written in the style of a table to make the
32+
// uniformities and distinctions more apparent.
33+
//
34+
// ZERO/SIGN-EXTENDING TO 32 BITS NON-EXTENDING
35+
// ============================== =======================
36+
// x86_64: void @c_arg_u8(i8 zeroext %_a)
37+
// i686: void @c_arg_u8(i8 zeroext %_a)
38+
// aarch64-apple: void @c_arg_u8(i8 zeroext %_a)
39+
// aarch64-windows: void @c_arg_u8(i8 %_a)
40+
// aarch64-linux: void @c_arg_u8(i8 %_a)
41+
// arm: void @c_arg_u8(i8 zeroext %_a)
42+
// riscv: void @c_arg_u8(i8 zeroext %_a)
43+
#[no_mangle] pub extern "C" fn c_arg_u8(_a: u8) { }
44+
45+
// x86_64: void @c_arg_u16(i16 zeroext %_a)
46+
// i686: void @c_arg_u16(i16 zeroext %_a)
47+
// aarch64-apple: void @c_arg_u16(i16 zeroext %_a)
48+
// aarch64-windows: void @c_arg_u16(i16 %_a)
49+
// aarch64-linux: void @c_arg_u16(i16 %_a)
50+
// arm: void @c_arg_u16(i16 zeroext %_a)
51+
// riscv: void @c_arg_u16(i16 zeroext %_a)
52+
#[no_mangle] pub extern "C" fn c_arg_u16(_a: u16) { }
53+
54+
// x86_64: void @c_arg_u32(i32 %_a)
55+
// i686: void @c_arg_u32(i32 %_a)
56+
// aarch64-apple: void @c_arg_u32(i32 %_a)
57+
// aarch64-windows: void @c_arg_u32(i32 %_a)
58+
// aarch64-linux: void @c_arg_u32(i32 %_a)
59+
// arm: void @c_arg_u32(i32 %_a)
60+
// riscv: void @c_arg_u32(i32 signext %_a)
61+
#[no_mangle] pub extern "C" fn c_arg_u32(_a: u32) { }
62+
63+
// x86_64: void @c_arg_u64(i64 %_a)
64+
// i686: void @c_arg_u64(i64 %_a)
65+
// aarch64-apple: void @c_arg_u64(i64 %_a)
66+
// aarch64-windows: void @c_arg_u64(i64 %_a)
67+
// aarch64-linux: void @c_arg_u64(i64 %_a)
68+
// arm: void @c_arg_u64(i64 %_a)
69+
// riscv: void @c_arg_u64(i64 %_a)
70+
#[no_mangle] pub extern "C" fn c_arg_u64(_a: u64) { }
71+
72+
// x86_64: void @c_arg_i8(i8 signext %_a)
73+
// i686: void @c_arg_i8(i8 signext %_a)
74+
// aarch64-apple: void @c_arg_i8(i8 signext %_a)
75+
// aarch64-windows: void @c_arg_i8(i8 %_a)
76+
// aarch64-linux: void @c_arg_i8(i8 %_a)
77+
// arm: void @c_arg_i8(i8 signext %_a)
78+
// riscv: void @c_arg_i8(i8 signext %_a)
79+
#[no_mangle] pub extern "C" fn c_arg_i8(_a: i8) { }
80+
81+
// x86_64: void @c_arg_i16(i16 signext %_a)
82+
// i686: void @c_arg_i16(i16 signext %_a)
83+
// aarch64-apple: void @c_arg_i16(i16 signext %_a)
84+
// aarch64-windows: void @c_arg_i16(i16 %_a)
85+
// aarch64-linux: void @c_arg_i16(i16 %_a)
86+
// arm: void @c_arg_i16(i16 signext %_a)
87+
// riscv: void @c_arg_i16(i16 signext %_a)
88+
#[no_mangle] pub extern "C" fn c_arg_i16(_a: i16) { }
89+
90+
// x86_64: void @c_arg_i32(i32 %_a)
91+
// i686: void @c_arg_i32(i32 %_a)
92+
// aarch64-apple: void @c_arg_i32(i32 %_a)
93+
// aarch64-windows: void @c_arg_i32(i32 %_a)
94+
// aarch64-linux: void @c_arg_i32(i32 %_a)
95+
// arm: void @c_arg_i32(i32 %_a)
96+
// riscv: void @c_arg_i32(i32 signext %_a)
97+
#[no_mangle] pub extern "C" fn c_arg_i32(_a: i32) { }
98+
99+
// x86_64: void @c_arg_i64(i64 %_a)
100+
// i686: void @c_arg_i64(i64 %_a)
101+
// aarch64-apple: void @c_arg_i64(i64 %_a)
102+
// aarch64-windows: void @c_arg_i64(i64 %_a)
103+
// aarch64-linux: void @c_arg_i64(i64 %_a)
104+
// arm: void @c_arg_i64(i64 %_a)
105+
// riscv: void @c_arg_i64(i64 %_a)
106+
#[no_mangle] pub extern "C" fn c_arg_i64(_a: i64) { }
107+
108+
// x86_64: zeroext i8 @c_ret_u8()
109+
// i686: zeroext i8 @c_ret_u8()
110+
// aarch64-apple: zeroext i8 @c_ret_u8()
111+
// aarch64-windows: i8 @c_ret_u8()
112+
// aarch64-linux: i8 @c_ret_u8()
113+
// arm: zeroext i8 @c_ret_u8()
114+
// riscv: zeroext i8 @c_ret_u8()
115+
#[no_mangle] pub extern "C" fn c_ret_u8() -> u8 { 0 }
116+
117+
// x86_64: zeroext i16 @c_ret_u16()
118+
// i686: zeroext i16 @c_ret_u16()
119+
// aarch64-apple: zeroext i16 @c_ret_u16()
120+
// aarch64-windows: i16 @c_ret_u16()
121+
// aarch64-linux: i16 @c_ret_u16()
122+
// arm: zeroext i16 @c_ret_u16()
123+
// riscv: zeroext i16 @c_ret_u16()
124+
#[no_mangle] pub extern "C" fn c_ret_u16() -> u16 { 0 }
125+
126+
// x86_64: i32 @c_ret_u32()
127+
// i686: i32 @c_ret_u32()
128+
// aarch64-apple: i32 @c_ret_u32()
129+
// aarch64-windows: i32 @c_ret_u32()
130+
// aarch64-linux: i32 @c_ret_u32()
131+
// arm: i32 @c_ret_u32()
132+
// riscv: signext i32 @c_ret_u32()
133+
#[no_mangle] pub extern "C" fn c_ret_u32() -> u32 { 0 }
134+
135+
// x86_64: i64 @c_ret_u64()
136+
// i686: i64 @c_ret_u64()
137+
// aarch64-apple: i64 @c_ret_u64()
138+
// aarch64-windows: i64 @c_ret_u64()
139+
// aarch64-linux: i64 @c_ret_u64()
140+
// arm: i64 @c_ret_u64()
141+
// riscv: i64 @c_ret_u64()
142+
#[no_mangle] pub extern "C" fn c_ret_u64() -> u64 { 0 }
143+
144+
// x86_64: signext i8 @c_ret_i8()
145+
// i686: signext i8 @c_ret_i8()
146+
// aarch64-apple: signext i8 @c_ret_i8()
147+
// aarch64-windows: i8 @c_ret_i8()
148+
// aarch64-linux: i8 @c_ret_i8()
149+
// arm: signext i8 @c_ret_i8()
150+
// riscv: signext i8 @c_ret_i8()
151+
#[no_mangle] pub extern "C" fn c_ret_i8() -> i8 { 0 }
152+
153+
// x86_64: signext i16 @c_ret_i16()
154+
// i686: signext i16 @c_ret_i16()
155+
// aarch64-apple: signext i16 @c_ret_i16()
156+
// aarch64-windows: i16 @c_ret_i16()
157+
// aarch64-linux: i16 @c_ret_i16()
158+
// arm: signext i16 @c_ret_i16()
159+
// riscv: signext i16 @c_ret_i16()
160+
#[no_mangle] pub extern "C" fn c_ret_i16() -> i16 { 0 }
161+
162+
// x86_64: i32 @c_ret_i32()
163+
// i686: i32 @c_ret_i32()
164+
// aarch64-apple: i32 @c_ret_i32()
165+
// aarch64-windows: i32 @c_ret_i32()
166+
// aarch64-linux: i32 @c_ret_i32()
167+
// arm: i32 @c_ret_i32()
168+
// riscv: signext i32 @c_ret_i32()
169+
#[no_mangle] pub extern "C" fn c_ret_i32() -> i32 { 0 }
170+
171+
// x86_64: i64 @c_ret_i64()
172+
// i686: i64 @c_ret_i64()
173+
// aarch64-apple: i64 @c_ret_i64()
174+
// aarch64-windows: i64 @c_ret_i64()
175+
// aarch64-linux: i64 @c_ret_i64()
176+
// arm: i64 @c_ret_i64()
177+
// riscv: i64 @c_ret_i64()
178+
#[no_mangle] pub extern "C" fn c_ret_i64() -> i64 { 0 }
179+
180+
const C_SOURCE_FILE: &'static str = r##"
181+
#include <stdlib.h>
182+
#include <stdint.h>
183+
#include <stdio.h>
184+
185+
void c_arg_u8(uint8_t _a) { }
186+
void c_arg_u16(uint16_t _a) { }
187+
void c_arg_u32(uint32_t _a) { }
188+
void c_arg_u64(uint64_t _a) { }
189+
190+
void c_arg_i8(int8_t _a) { }
191+
void c_arg_i16(int16_t _a) { }
192+
void c_arg_i32(int32_t _a) { }
193+
void c_arg_i64(int64_t _a) { }
194+
195+
uint8_t c_ret_u8() { return 0; }
196+
uint16_t c_ret_u16() { return 0; }
197+
uint32_t c_ret_u32() { return 0; }
198+
uint64_t c_ret_u64() { return 0; }
199+
200+
int8_t c_ret_i8() { return 0; }
201+
int16_t c_ret_i16() { return 0; }
202+
int32_t c_ret_i32() { return 0; }
203+
int64_t c_ret_i64() { return 0; }
204+
"##;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-include ../tools.mk
2+
3+
# ignore-msvc
4+
5+
# The issue exercised by this test, rust-lang/rust#97463, explicitly needs `-O`
6+
# flags (like `-O3`) to reproduce. Thus, we call $(CC) instead of nicer
7+
# alternatives provided by tools.mk like using `COMPILE_OBJ` or using a
8+
# `NATIVE_STATICLIB` dependency.
9+
10+
all:
11+
$(CC) -c -O3 -o $(TMPDIR)/bad.o bad.c
12+
$(AR) rcs $(TMPDIR)/libbad.a $(TMPDIR)/bad.o
13+
$(RUSTC) param_passing.rs -L$(TMPDIR) -lbad -C opt-level=3
14+
$(call RUN,param_passing)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include <stdlib.h>
2+
#include <stdint.h>
3+
#include <stdio.h>
4+
5+
6+
struct bloc {
7+
uint16_t a;
8+
uint16_t b;
9+
uint16_t c;
10+
};
11+
12+
uint16_t c_read_value(uint32_t a, uint32_t b, uint32_t c) {
13+
struct bloc *data = malloc(sizeof(struct bloc));
14+
15+
data->a = a & 0xFFFF;
16+
data->b = b & 0xFFFF;
17+
data->c = c & 0xFFFF;
18+
19+
printf("C struct: a = %u, b = %u, c = %u\n",
20+
(unsigned) data->a, (unsigned) data->b, (unsigned) data->c);
21+
printf("C function returns %u\n", (unsigned) data->b);
22+
23+
return data->b; /* leak data */
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// NOTE: Exposing the bug encoded in this test is sensitive to
2+
// LLVM optimization choices. See additional note below for an
3+
// example.
4+
5+
#[link(name = "bad")]
6+
extern "C" {
7+
pub fn c_read_value(a: u32, b: u32, c: u32) -> u16;
8+
}
9+
10+
fn main() {
11+
const C1: usize = 0x327b23c6;
12+
const C2: usize = C1 & 0xFFFF;
13+
14+
let r1: usize = 0x0;
15+
let r2: usize = C1;
16+
let r3: usize = 0x0;
17+
let value: u16 = unsafe { c_read_value(r1 as u32, r2 as u32, r3 as u32) };
18+
19+
// NOTE: as an example of the sensitivity of this test to optimization choices,
20+
// uncommenting this block of code makes the bug go away on pnkfelix's machine.
21+
// (But observing via `dbg!` doesn't hide the bug. At least sometimes.)
22+
/*
23+
println!("{}", value);
24+
println!("{}", value as usize);
25+
println!("{}", usize::from(value));
26+
println!("{}", (value as usize) & 0xFFFF);
27+
*/
28+
29+
let d1 = value;
30+
let d2 = value as usize;
31+
let d3 = usize::from(value);
32+
let d4 = (value as usize) & 0xFFFF;
33+
34+
let d = (&d1, &d2, &d3, &d4);
35+
let d_ = (d1, d2, d3, d4);
36+
37+
assert_eq!(((&(C2 as u16), &C2, &C2, &C2), (C2 as u16, C2, C2, C2)), (d, d_));
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// run-pass
2+
// ignore-wasm
3+
#![allow(dead_code)]
4+
#![allow(improper_ctypes)]
5+
6+
#[link(name = "rust_test_helpers", kind = "static")]
7+
extern "C" {
8+
pub fn issue_97463_leak_uninit_data(a: u32, b: u32, c: u32) -> u16;
9+
}
10+
11+
fn main() {
12+
const C1: usize = 0x327b23c6;
13+
const C2: usize = C1 & 0xFFFF;
14+
15+
let r1: usize = 0x0;
16+
let r2: usize = C1;
17+
let r3: usize = 0x0;
18+
let value: u16 = unsafe { issue_97463_leak_uninit_data(r1 as u32, r2 as u32, r3 as u32) };
19+
20+
// NOTE: as an example of the sensitivity of this test to optimization choices,
21+
// uncommenting this block of code makes the bug go away on pnkfelix's machine.
22+
// (But observing via `dbg!` doesn't hide the bug. At least sometimes.)
23+
/*
24+
println!("{}", value);
25+
println!("{}", value as usize);
26+
println!("{}", usize::from(value));
27+
println!("{}", (value as usize) & 0xFFFF);
28+
*/
29+
30+
let d1 = value;
31+
let d2 = value as usize;
32+
let d3 = usize::from(value);
33+
let d4 = (value as usize) & 0xFFFF;
34+
35+
let d = (&d1, &d2, &d3, &d4);
36+
let d_ = (d1, d2, d3, d4);
37+
38+
assert_eq!(((&(C2 as u16), &C2, &C2, &C2), (C2 as u16, C2, C2, C2)), (d, d_));
39+
}

0 commit comments

Comments
 (0)
Please sign in to comment.