-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbuild.rs
More file actions
181 lines (155 loc) · 5.29 KB
/
build.rs
File metadata and controls
181 lines (155 loc) · 5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#![allow(unknown_lints, clippy::undocumented_unsafe_blocks)]
#[::rustversion::since(1.80)]
fn rustc_cfg() {
println!("cargo:rustc-check-cfg=cfg(nightly)");
}
#[::rustversion::before(1.80)]
fn rustc_cfg() {
// noop
}
#[::rustversion::nightly]
#[allow(dead_code)]
const fn is_nightly() -> bool {
true
}
#[::rustversion::not(nightly)]
#[allow(dead_code)]
const fn is_nightly() -> bool {
false
}
fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=src/ffi/c/calloca.c");
let failures = run_checks();
if failures.is_empty() {
// all success, now enable "nightly" if on the nightly toolchain
rustc_cfg();
#[cfg(not(feature = "no_nightly"))]
if is_nightly() {
println!("cargo:rustc-cfg=nightly");
}
#[cfg(feature = "stack_alloc")]
{
if let Err(e) = cc::Build::new().file("src/ffi/c/calloca.c").try_compile("calloca") {
panic!("failed to compile calloca.c: {}", e);
}
}
return;
}
for Failure { source, code, msg } in &failures {
eprintln!("UB test {}:{} failed: {}", source, code, msg);
}
let example_toolchain = "nightly-x86_64-unknown-linux-gnu 1.91.0 (840b83a10 2025-07-30)";
let req_info = "please open an issue with your rust toolchain info";
let get_tc_info = "(`rustup default`, `cargo --version`).";
panic!(
"UB checks failed (codes: {:?}).\n{} {}\nexample: {}",
failures.iter().map(|f| f.code).collect::<Vec<_>>(),
req_info,
get_tc_info,
example_toolchain
);
}
pub struct Failure {
source: usize,
code: usize,
msg: &'static str
}
fn run_checks() -> Vec<Failure> {
let mut failures = Vec::new();
failures.extend(checks::sp_frp::check());
failures
}
mod checks {
pub mod sp_frp {
use {crate::Failure, ::core::ptr::NonNull};
#[cfg_attr(miri, track_caller)]
pub fn check() -> Vec<Failure> {
let mut failures = Vec::<Failure>::new();
let i = 4;
let mut data: Vec<usize> = (0..i).map(|j| 64 << j).collect();
let slice: &mut [usize] = &mut data;
let ptr = slice.as_mut_ptr();
let len = slice.len();
let slice_ptr = slice_ptr_from_parts(ptr, len);
// check that they dereference to the same thing
if unsafe { &*slice_ptr } != slice {
failures.push(Failure {
source: 0,
code: 0,
msg: "result doesn't dereference properly"
});
}
// check that they have the same pointer and length
if slice.as_ptr() != slice_ptr.cast::<usize>() {
failures.push(Failure {
source: 0,
code: 1,
msg: "result doesn't have the same pointer"
});
}
if unsafe { slice_ptr.as_ref() }.unwrap().len() != len {
failures.push(Failure {
source: 0,
code: 2,
msg: "result doesn't have the same length"
});
}
unsafe {
if len
!= nonnull_slice_len(nonnull_slice_from_parts(NonNull::new_unchecked(ptr), len))
{
failures.push(Failure {
source: 0,
code: 3,
msg: "result doesn't have the correct metadata"
});
}
}
for (i, &elem) in slice.iter().enumerate() {
let via_raw = unsafe { (&*slice_ptr)[i] };
// check that the values are all the same
if elem != via_raw {
failures.push(Failure {
source: 0,
code: 4,
msg: "values differ between original slice and raw-slice"
});
}
// manually check that the values are the same
if via_raw != 64_usize << i {
failures.push(Failure {
source: 0,
code: 5,
msg: "raw-slice value mismatch against expected"
});
}
}
failures
}
// from the crate
#[cfg_attr(miri, track_caller)]
#[must_use]
fn nonnull_slice_len<T>(ptr: NonNull<[T]>) -> usize {
unsafe { (&*ptr.as_ptr()).len() }
}
#[cfg_attr(miri, track_caller)]
#[must_use]
fn nonnull_slice_from_parts<T>(p: NonNull<T>, len: usize) -> NonNull<[T]> {
unsafe { NonNull::new_unchecked(slice_ptr_from_parts(p.as_ptr(), len)) }
}
#[cfg_attr(miri, track_caller)]
#[must_use]
fn slice_ptr_from_parts<T>(p: *mut T, len: usize) -> *mut [T] {
unsafe { union_transmute((p, len)) }
}
#[cfg_attr(miri, track_caller)]
unsafe fn union_transmute<Src: Copy, Dst: Copy>(src: Src) -> Dst {
union Either<Src: Copy, Dst: Copy> {
src: Src,
dst: Dst
}
Either { src }.dst
}
}
}