Description
The following code in the playground reports a Miri error:
use futures::executor::block_on;
use futures::AsyncReadExt;
async fn hello_world() {
let data = [0u8; 1];
let mut reader = &data[..];
let mut marker = [0u8; 1];
reader.read_exact(&mut marker).await.unwrap();
}
fn main() {
let future = hello_world();
block_on(future);
}
error: Undefined Behavior: accessing memory with alignment 1, but alignment 2 is required
--> src/main.rs:8:22
|
8 | let mut marker = [0u8; 1];
| ^^^^^^^^ accessing memory with alignment 1, but alignment 2 is required
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
error notes
= note: inside closure at src/main.rs:8:22
= note: inside `<std::future::from_generator::GenFuture<[static generator@src/main.rs:4:24: 10:2]> as futures::Future>::poll` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/mod.rs:80:19
= note: inside closure at /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-executor-0.3.17/src/local_pool.rs:315:23
= note: inside closure at /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-executor-0.3.17/src/local_pool.rs:90:37
= note: inside `std::thread::LocalKey::<std::sync::Arc<futures::futures_executor::local_pool::ThreadNotify>>::try_with::<[closure@futures::futures_executor::local_pool::run_executor<(), [closure@futures::futures_executor::block_on<std::future::from_generator::GenFuture<[static generator@src/main.rs:4:24: 10:2]>>::{closure#0}]>::{closure#0}], ()>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:399:16
= note: inside `std::thread::LocalKey::<std::sync::Arc<futures::futures_executor::local_pool::ThreadNotify>>::with::<[closure@futures::futures_executor::local_pool::run_executor<(), [closure@futures::futures_executor::block_on<std::future::from_generator::GenFuture<[static generator@src/main.rs:4:24: 10:2]>>::{closure#0}]>::{closure#0}], ()>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:375:9
= note: inside `futures::futures_executor::local_pool::run_executor::<(), [closure@futures::futures_executor::block_on<std::future::from_generator::GenFuture<[static generator@src/main.rs:4:24: 10:2]>>::{closure#0}]>` at /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-executor-0.3.17/src/local_pool.rs:86:5
= note: inside `futures::futures_executor::block_on::<std::future::from_generator::GenFuture<[static generator@src/main.rs:4:24: 10:2]>>` at /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-executor-0.3.17/src/local_pool.rs:315:5
note: inside `main` at src/main.rs:14:5
--> src/main.rs:14:5
|
14 | block_on(future);
| ^^^^^^^^^^^^^^^^
= note: inside `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
= note: inside `std::sys_common::backtrace::__rust_begin_short_backtrace::<fn(), ()>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/backtrace.rs:123:18
= note: inside closure at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:145:18
= note: inside `std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:259:13
= note: inside `std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:406:40
= note: inside `std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:370:19
= note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:133:14
= note: inside closure at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:128:48
= note: inside `std::panicking::r#try::do_call::<[closure@std::rt::lang_start_internal::{closure#2}], isize>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:406:40
= note: inside `std::panicking::r#try::<isize, [closure@std::rt::lang_start_internal::{closure#2}]>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:370:19
= note: inside `std::panic::catch_unwind::<[closure@std::rt::lang_start_internal::{closure#2}], isize>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:133:14
= note: inside `std::rt::lang_start_internal` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:128:20
= note: inside `std::rt::lang_start::<()>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:144:17
I believe Miri is wrong here, but I don't really know how it represents async code.
When I look at the LLVM IR, I see a memset(i8* align 2 ...)
for this marker
within the generator Suspend0
state. That alignment comes from PlaceRef::project_field
's effective_field_align
, because the struct has alignment 8 and the field is at offset 42, so the field will always be at alignment 2.
You can also bump this around in the example by changing the data
length. At 2, marker
moves to offset 43 and alignment 1, and miri is happy. At 3 we get offset 44 and alignment 4, and at 7 we get offset 48 and alignment 8, both miri errors.
So it seems Miri is seeing the projection alignment, but from the error span it looks like it may be applying that requirement to the initialization value?