Rust: Borrowck regression: allows segfault in 1.27.1

Created on 10 Jul 2018  路  10Comments  路  Source: rust-lang/rust

The following sample correctly fails to build on stable channel, but erroneously passes on beta and nightly.

It's worth noting that with NLL turned on it also correctly fails to build.
```
enum Inner {
Stack {
data: [u8;23]
},
Heap {
capacity: usize,
data: *mut u8
}
}

struct SmallString {
len: usize,
inner: Inner
}

impl SmallString {
fn push_str(&mut self, item: &str) {
match (&mut self.inner, self.len + item.len()) {
(Inner::Heap { capacity, ref data }, x) => {
if x > *capacity {
self.grow();
// data is now null pointer
}
unsafe {
::std::ptr::copy_nonoverlapping(item.as_ptr(), data.add(self.len), item.len())
}
},
_ => ()
}
}
fn grow(&mut self){
// Invalidate borrowed Heap.data
self.inner = Inner::Stack { data: [0;23] };
}
}

C-bug I-unsound 馃挜 T-compiler regression-from-stable-to-stable

Most helpful comment

I have a fix up, will push it soon.

All 10 comments

Here is an example of being able to segfault in safe rust on beta

enum Inner {
    Stack {
        data: [u8;23]
    },
    Heap {
        data: Box<[u8]>
    }
}

struct SmallString {
    len: usize,
    inner: Inner
}

impl SmallString {
    fn push_str(&mut self, item: &str) {
        match (&mut self.inner, self.len + item.len()) {
            (Inner::Heap { data }, x) => {
                println!("{}", data.len());
                if x > data.len() {
                    self.grow();
                    // data is now garbage pointer
                }
                println!("{:?}", data);
            },
            _ => ()
        }
    }
    fn grow(&mut self){
        // Invalidate borrowed Heap.data
        self.inner = Inner::Stack { data: [1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1] };
    }
}

fn main (){
    let slice = "this is gonna go bad".to_owned().into_bytes().into_boxed_slice();
    let mut ss = SmallString { len: slice.len(), inner: Inner::Heap { data: slice } };
    ss.push_str(" right now");
}

http://play.rust-lang.org/?gist=e9ebe1460df7a817467ee017de9655dc&version=beta&mode=debug&edition=2015

Turns out this regression is now also in the new patch release on stable!

If this can be reproduced on 1.27.1 but can't be reproduced on 1.27.0 (@NilSet said that on IRC), I guess that this regression is caused by #51686 .

cc @nikomatsakis #51686.

@rust-lang/compiler the obligatory ping to all of you.

Minified:



fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
    match (&t, ()) {
        ((t,), ()) => t,
    }
}

fn main() {
    let x = {
        let y = Box::new((42,));
        transmute_lifetime(&y)
    };

    println!("{}", x);
}

Did anyone verify that this reproduces on 1.27.1? I am not sure

And now I'm in the state of "how does this ever work", given that cat_pattern is returning Err "correctly".

@arielb1: Your minified example compiles with 1.27.1, and so does the second example in this thread.

I have a fix up, will push it soon.

Was this page helpful?
0 / 5 - 0 ratings