Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

format_args! returned from a closure causes corruption/crash #27592

Closed
thepowersgang opened this issue Aug 8, 2015 · 6 comments
Closed

format_args! returned from a closure causes corruption/crash #27592

thepowersgang opened this issue Aug 8, 2015 · 6 comments
Labels
A-type-system Area: Type system

Comments

@thepowersgang
Copy link
Contributor

The following code causes an abort in the generated executable, due to a bad jump in ::std::fmt::write (indirect call to 0x1)

This is present on stable, beta, and nightly, both with and without optimisation on. (from my tests in playpen)

fn write<'a, F: ::std::ops::FnOnce()->::std::fmt::Arguments<'a> + 'a>(fcn: F) {
    use std::fmt::Write;
    let _ = match fcn() { a => write!(&mut Stream, "{}", a), };
}

struct Stream;
impl ::std::fmt::Write for Stream {
    fn write_str(&mut self, _s: &str) -> ::std::fmt::Result {
        Ok( () )
    }
}

fn main() {
    write(|| format_args!("{}", "Hello world"));
}
   Compiling log_segv_repro v0.1.0 (file:///home/tpg/tmp/log_segv_repro)
GNU gdb (Ubuntu 7.9-1ubuntu1) 7.9
Copyright (C) 2015 Free Software Foundation, Inc.
<<SNIP gdb startup headers>>
(gdb) r
Starting program: /home/tpg/tmp/log_segv_repro/target/debug/log_segv_repro 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000001 in ?? ()
(gdb) bt
#0  0x0000000000000001 in ?? ()
#1  0x000055555558cc41 in fmt::write::h60410fae94938806bVM ()
#2  0x000055555558d0a2 in fmt::Arguments$LT$$u27$a$GT$.Debug::fmt::hf053ca5cd2a04b0dKSM ()
#3  0x000055555558cc41 in fmt::write::h60410fae94938806bVM ()
#4  0x00005555555595d4 in log_segv_repro::fmt::Write::write_fmt<log_segv_repro::Stream> (self=0x5555557a03a8 <ref_mut_slice2469>, args=...)
    at /home/rustbuild/src/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libcore/fmt/mod.rs:119
#5  0x000055555555942a in log_segv_repro::write<closure> (fcn={struct Arguments (())} 0x7fffffffdb88) at src/main.rs:5
#6  0x00005555555592fe in log_segv_repro::main () at src/main.rs:18
#7  0x00005555555649f9 in rust_try_inner ()
#8  0x00005555555649e6 in rust_try ()
#9  0x0000555555562154 in rt::lang_start::hfd55f157ee8450ebNDw ()
#10 0x000055555555a7f5 in main ()
(gdb) 
@thepowersgang
Copy link
Contributor Author

My theory is that this is a failing in borrowck, allowing Arguments to be returned when it contains a borrow of a local. (Which is subsequently clobbered and causes execution of a random address)

@TimNN
Copy link
Contributor

TimNN commented Aug 8, 2015

Running this through --pretty=expanded first fails to compile: https://play.rust-lang.org/?gist=7d46d0c33a5c6122b043&version=nightly

@nikomatsakis
Copy link
Contributor

My branch for RFC rust-lang/rfcs#1214 reports the following error:

/home/nmatsakis/tmp/issue-27592.rs:14:27: 14:31 error: borrowed value does not live long enough
/home/nmatsakis/tmp/issue-27592.rs:14     write(|| format_args!("{}", "Hello world"));
                                                                ^~~~
note: in expansion of format_args!
/home/nmatsakis/tmp/issue-27592.rs:14:14: 14:47 note: expansion site
note: in expansion of closure expansion
/home/nmatsakis/tmp/issue-27592.rs:14:11: 14:47 note: expansion site
/home/nmatsakis/tmp/issue-27592.rs:14:5: 14:48 note: reference must be valid for the call at 14:4...
/home/nmatsakis/tmp/issue-27592.rs:14     write(|| format_args!("{}", "Hello world"));
                                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/nmatsakis/tmp/issue-27592.rs:14:14: 14:47 note: ...but borrowed value is only valid for the block at 14:13
/home/nmatsakis/tmp/issue-27592.rs:14     write(|| format_args!("{}", "Hello world"));
                                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/nmatsakis/tmp/issue-27592.rs:14:33: 14:46 error: borrowed value does not live long enough
/home/nmatsakis/tmp/issue-27592.rs:14     write(|| format_args!("{}", "Hello world"));
                                                                      ^~~~~~~~~~~~~
note: in expansion of format_args!
/home/nmatsakis/tmp/issue-27592.rs:14:14: 14:47 note: expansion site
note: in expansion of closure expansion
/home/nmatsakis/tmp/issue-27592.rs:14:11: 14:47 note: expansion site
/home/nmatsakis/tmp/issue-27592.rs:14:5: 14:48 note: reference must be valid for the call at 14:4...
/home/nmatsakis/tmp/issue-27592.rs:14     write(|| format_args!("{}", "Hello world"));
                                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/nmatsakis/tmp/issue-27592.rs:14:14: 14:47 note: ...but borrowed value is only valid for the block at 14:13
/home/nmatsakis/tmp/issue-27592.rs:14     write(|| format_args!("{}", "Hello world"));
                                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors

@nikomatsakis
Copy link
Contributor

subissue of #27579

@alexcrichton
Copy link
Member

@TimNN note that the pretty expansion failing to compile is a bit of a red herring because it's not pretty printed correctly, if you wrap the &mut Stream part in parentheses then you get the same runtime error.

@arielb1
Copy link
Contributor

arielb1 commented Aug 10, 2015

Minimal example:

use std::ops::Deref;

fn write<'a, F>(f: F) where F: FnOnce() -> &'a u32 {
    println!("{}", f());
}

fn main() {
    let k = || (&mut 42).deref(); // no rvalue promotion here please
    write(k)
}

nikomatsakis added a commit to nikomatsakis/rust that referenced this issue Aug 13, 2015
causes errors, post rebase). Issue rust-lang#27592 is still alive and well,
whatever it is.
@steveklabnik steveklabnik added the A-type-system Area: Type system label Aug 13, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-type-system Area: Type system
Projects
None yet
Development

No branches or pull requests

6 participants