Skip to content

Commit 5864e9f

Browse files
committed
Make size_of or align_of fail for generators (because they are currently buggy, see model-checking#1395)
1 parent daecbbf commit 5864e9f

10 files changed

+281
-11
lines changed

kani-compiler/src/codegen_cprover_gotoc/codegen/intrinsic.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,9 +313,19 @@ impl<'tcx> GotocCtx<'tcx> {
313313
macro_rules! codegen_size_align {
314314
($which: ident) => {{
315315
let tp_ty = instance.substs.type_at(0);
316-
let arg = fargs.remove(0);
317-
let size_align = self.size_and_align_of_dst(tp_ty, arg);
318-
self.codegen_expr_to_place(p, size_align.$which)
316+
if tp_ty.is_generator() {
317+
let e = self.codegen_unimplemented(
318+
"size or alignment of a generator type",
319+
cbmc_ret_ty,
320+
loc,
321+
"https://github.com/model-checking/kani/issues/1395",
322+
);
323+
self.codegen_expr_to_place(p, e)
324+
} else {
325+
let arg = fargs.remove(0);
326+
let size_align = self.size_and_align_of_dst(tp_ty, arg);
327+
self.codegen_expr_to_place(p, size_align.$which)
328+
}
319329
}};
320330
}
321331

tests/kani/Generator/rustc-generator-tests/discriminant.rs renamed to tests/kani/Generator/rustc-generator-tests/discriminant_fixme.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ fn main() {
136136
}
137137
};
138138

139+
// FIXME: size of generators does not work reliably (https://github.com/model-checking/kani/issues/1395)
139140
assert_eq!(size_of_val(&gen_u8_tiny_niche()), 1);
140141
assert_eq!(size_of_val(&Some(gen_u8_tiny_niche())), 1); // uses niche
141142
assert_eq!(size_of_val(&Some(Some(gen_u8_tiny_niche()))), 2); // cannot use niche anymore
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// SPDX-License-Identifier: Apache-2.0 OR MIT
2+
//
3+
// Modifications Copyright Kani Contributors
4+
// See GitHub history for details.
5+
6+
// Copyright rustc Contributors
7+
// Adapted from rustc: https://github.com/rust-lang/rust/tree/5f98537eb7b5f42c246a52c550813c3cff336069/src/test/ui/generator/niche-in-generator.rs
8+
9+
// Test that niche finding works with captured generator upvars.
10+
11+
// run-pass
12+
13+
#![feature(generators, generator_trait)]
14+
15+
use std::ops::{Generator, GeneratorState};
16+
use std::pin::Pin;
17+
18+
use std::mem::size_of_val;
19+
20+
fn take<T>(_: T) {}
21+
22+
#[kani::proof]
23+
fn main() {
24+
let x = false;
25+
let mut gen1 = || {
26+
yield;
27+
take(x);
28+
};
29+
30+
// FIXME: for some reason, these asserts are very hard for CBMC to figure out
31+
// Kani didn't terminate within 5 minutes.
32+
// assert_eq!(Pin::new(&mut gen1).resume(()), GeneratorState::Yielded(()));
33+
// assert_eq!(Pin::new(&mut gen1).resume(()), GeneratorState::Complete(()));
34+
assert!(false); // to make the test fail without taking forever
35+
}

tests/kani/Generator/rustc-generator-tests/niche-in-generator.rs renamed to tests/kani/Generator/rustc-generator-tests/niche-in-generator_fixme.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ fn main() {
2424
take(x);
2525
};
2626

27+
// FIXME: size of generators does not work reliably (https://github.com/model-checking/kani/issues/1395)
2728
assert_eq!(size_of_val(&gen1), size_of_val(&Some(gen1)));
2829
}

tests/kani/Generator/rustc-generator-tests/overlap-locals.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,35 @@
88

99
// run-pass
1010

11-
#![feature(generators)]
11+
#![feature(generators, generator_trait)]
12+
13+
use std::ops::{Generator, GeneratorState};
14+
use std::pin::Pin;
1215

1316
#[kani::proof]
1417
fn main() {
15-
let a = || {
18+
let mut a = || {
1619
{
1720
let w: i32 = 4;
1821
yield;
19-
println!("{:?}", w);
2022
}
2123
{
2224
let x: i32 = 5;
2325
yield;
24-
println!("{:?}", x);
2526
}
2627
{
2728
let y: i32 = 6;
2829
yield;
29-
println!("{:?}", y);
3030
}
3131
{
3232
let z: i32 = 7;
3333
yield;
34-
println!("{:?}", z);
3534
}
3635
};
37-
assert_eq!(8, std::mem::size_of_val(&a));
36+
37+
assert_eq!(Pin::new(&mut a).resume(()), GeneratorState::Yielded(()));
38+
assert_eq!(Pin::new(&mut a).resume(()), GeneratorState::Yielded(()));
39+
assert_eq!(Pin::new(&mut a).resume(()), GeneratorState::Yielded(()));
40+
assert_eq!(Pin::new(&mut a).resume(()), GeneratorState::Yielded(()));
41+
assert_eq!(Pin::new(&mut a).resume(()), GeneratorState::Complete(()));
3842
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// SPDX-License-Identifier: Apache-2.0 OR MIT
2+
//
3+
// Modifications Copyright Kani Contributors
4+
// See GitHub history for details.
5+
6+
// Copyright rustc Contributors
7+
// Adapted from rustc: https://github.com/rust-lang/rust/tree/5f98537eb7b5f42c246a52c550813c3cff336069/src/test/ui/generator/overlap-locals.rs
8+
9+
// run-pass
10+
11+
#![feature(generators)]
12+
13+
#[kani::proof]
14+
fn main() {
15+
let a = || {
16+
{
17+
let w: i32 = 4;
18+
yield;
19+
println!("{:?}", w);
20+
}
21+
{
22+
let x: i32 = 5;
23+
yield;
24+
println!("{:?}", x);
25+
}
26+
{
27+
let y: i32 = 6;
28+
yield;
29+
println!("{:?}", y);
30+
}
31+
{
32+
let z: i32 = 7;
33+
yield;
34+
println!("{:?}", z);
35+
}
36+
};
37+
38+
// FIXME: size of generators does not work reliably (https://github.com/model-checking/kani/issues/1395)
39+
assert_eq!(8, std::mem::size_of_val(&a));
40+
}

tests/kani/Generator/rustc-generator-tests/resume-arg-size.rs renamed to tests/kani/Generator/rustc-generator-tests/resume-arg-size_fixme.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ fn main() {
3232

3333
// Neither of these generators have the resume arg live across the `yield`, so they should be
3434
// 1 Byte in size (only storing the discriminant)
35+
// FIXME: size of generators does not work reliably (https://github.com/model-checking/kani/issues/1395)
3536
assert_eq!(size_of_val(&gen_copy), 1);
3637
assert_eq!(size_of_val(&gen_move), 1);
3738
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// SPDX-License-Identifier: Apache-2.0 OR MIT
2+
//
3+
// Modifications Copyright Kani Contributors
4+
// See GitHub history for details.
5+
6+
// Copyright rustc Contributors
7+
// Adapted from rustc: https://github.com/rust-lang/rust/tree/5f98537eb7b5f42c246a52c550813c3cff336069/src/test/ui/generator/resume-arg-size.rs
8+
9+
#![feature(generators, generator_trait)]
10+
11+
use std::ops::{Generator, GeneratorState};
12+
use std::pin::Pin;
13+
14+
// run-pass
15+
16+
use std::mem::size_of_val;
17+
18+
#[kani::proof]
19+
fn main() {
20+
// Generator taking a `Copy`able resume arg.
21+
let mut gen_copy = |mut x: usize| {
22+
loop {
23+
drop(x);
24+
x = yield;
25+
}
26+
};
27+
28+
// Generator taking a non-`Copy` resume arg.
29+
let mut gen_move = |mut x: Box<usize>| {
30+
loop {
31+
drop(x);
32+
x = yield;
33+
}
34+
};
35+
36+
assert_eq!(Pin::new(&mut gen_copy).resume(0), GeneratorState::Yielded(()));
37+
assert_eq!(Pin::new(&mut gen_copy).resume(1), GeneratorState::Yielded(()));
38+
39+
assert_eq!(Pin::new(&mut gen_move).resume(Box::new(0)), GeneratorState::Yielded(()));
40+
assert_eq!(Pin::new(&mut gen_move).resume(Box::new(1)), GeneratorState::Yielded(()));
41+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// SPDX-License-Identifier: Apache-2.0 OR MIT
2+
//
3+
// Modifications Copyright Kani Contributors
4+
// See GitHub history for details.
5+
6+
// Copyright rustc Contributors
7+
// Adapted from rustc: https://github.com/rust-lang/rust/tree/5f98537eb7b5f42c246a52c550813c3cff336069/src/test/ui/generator/size-moved-locals.rs
8+
9+
// run-pass
10+
// Test that we don't duplicate storage for a variable that is moved to another
11+
// binding. This used to happen in the presence of unwind and drop edges (see
12+
// `complex` below.)
13+
//
14+
// The exact sizes here can change (we'd like to know when they do). What we
15+
// don't want to see is the `complex` generator size being upwards of 2048 bytes
16+
// (which would indicate it is reserving space for two copies of Foo.)
17+
//
18+
// See issue #59123 for a full explanation.
19+
20+
// edition:2018
21+
// ignore-wasm32 issue #62807
22+
// ignore-asmjs issue #62807
23+
24+
#![feature(generators, generator_trait)]
25+
26+
use std::ops::{Generator, GeneratorState};
27+
use std::pin::Pin;
28+
29+
const FOO_SIZE: usize = 1024;
30+
struct Foo([u8; FOO_SIZE]);
31+
32+
impl Drop for Foo {
33+
fn drop(&mut self) {}
34+
}
35+
36+
fn move_before_yield() -> impl Generator<Yield = (), Return = ()> {
37+
static || {
38+
let first = Foo([0; FOO_SIZE]);
39+
let _second = first;
40+
yield;
41+
// _second dropped here
42+
}
43+
}
44+
45+
fn noop() {}
46+
47+
fn move_before_yield_with_noop() -> impl Generator<Yield = (), Return = ()> {
48+
static || {
49+
let first = Foo([0; FOO_SIZE]);
50+
noop();
51+
let _second = first;
52+
yield;
53+
// _second dropped here
54+
}
55+
}
56+
57+
// Today we don't have NRVO (we allocate space for both `first` and `second`,)
58+
// but we can overlap `first` with `_third`.
59+
fn overlap_move_points() -> impl Generator<Yield = (), Return = ()> {
60+
static || {
61+
let first = Foo([0; FOO_SIZE]);
62+
yield;
63+
let second = first;
64+
yield;
65+
let _third = second;
66+
yield;
67+
}
68+
}
69+
70+
fn overlap_x_and_y() -> impl Generator<Yield = (), Return = ()> {
71+
static || {
72+
let x = Foo([0; FOO_SIZE]);
73+
yield;
74+
drop(x);
75+
let y = Foo([0; FOO_SIZE]);
76+
yield;
77+
drop(y);
78+
}
79+
}
80+
81+
#[kani::proof]
82+
fn main() {
83+
// FIXME: the following tests are very slow (did not terminate in a couple of minutes)
84+
/* let mut generator = move_before_yield();
85+
assert_eq!(
86+
unsafe { Pin::new_unchecked(&mut generator) }.resume(()),
87+
GeneratorState::Yielded(())
88+
);
89+
assert_eq!(
90+
unsafe { Pin::new_unchecked(&mut generator) }.resume(()),
91+
GeneratorState::Complete(())
92+
);
93+
94+
let mut generator = move_before_yield_with_noop();
95+
assert_eq!(
96+
unsafe { Pin::new_unchecked(&mut generator) }.resume(()),
97+
GeneratorState::Yielded(())
98+
);
99+
assert_eq!(
100+
unsafe { Pin::new_unchecked(&mut generator) }.resume(()),
101+
GeneratorState::Complete(())
102+
);
103+
104+
let mut generator = overlap_move_points();
105+
assert_eq!(
106+
unsafe { Pin::new_unchecked(&mut generator) }.resume(()),
107+
GeneratorState::Yielded(())
108+
);
109+
assert_eq!(
110+
unsafe { Pin::new_unchecked(&mut generator) }.resume(()),
111+
GeneratorState::Yielded(())
112+
);
113+
assert_eq!(
114+
unsafe { Pin::new_unchecked(&mut generator) }.resume(()),
115+
GeneratorState::Yielded(())
116+
);
117+
assert_eq!(
118+
unsafe { Pin::new_unchecked(&mut generator) }.resume(()),
119+
GeneratorState::Complete(())
120+
);
121+
122+
let mut generator = overlap_x_and_y();
123+
assert_eq!(
124+
unsafe { Pin::new_unchecked(&mut generator) }.resume(()),
125+
GeneratorState::Yielded(())
126+
);
127+
assert_eq!(
128+
unsafe { Pin::new_unchecked(&mut generator) }.resume(()),
129+
GeneratorState::Yielded(())
130+
);
131+
assert_eq!(
132+
unsafe { Pin::new_unchecked(&mut generator) }.resume(()),
133+
GeneratorState::Complete(())
134+
); */
135+
assert!(false); // to make the test fail without taking forever
136+
}

tests/kani/Generator/rustc-generator-tests/size-moved-locals.rs renamed to tests/kani/Generator/rustc-generator-tests/size-moved-locals_fixme.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,12 @@ fn overlap_x_and_y() -> impl Generator<Yield = (), Return = ()> {
7979

8080
#[kani::proof]
8181
fn main() {
82+
// FIXME: size of generators does not work reliably (https://github.com/model-checking/kani/issues/1395)
8283
assert_eq!(1025, std::mem::size_of_val(&move_before_yield()));
8384
// The following assertion fails for some reason (tracking issue: https://github.com/model-checking/kani/issues/1395).
8485
// But it also fails for WASM (https://github.com/rust-lang/rust/issues/62807),
8586
// so it is probably not a big problem:
86-
// assert_eq!(1026, std::mem::size_of_val(&move_before_yield_with_noop()));
87+
assert_eq!(1026, std::mem::size_of_val(&move_before_yield_with_noop()));
8788
assert_eq!(2051, std::mem::size_of_val(&overlap_move_points()));
8889
assert_eq!(1026, std::mem::size_of_val(&overlap_x_and_y()));
8990
}

0 commit comments

Comments
 (0)