diff --git a/src/test/ui/issue-27282-mutate-before-diverging-arm-1.rs b/src/test/ui/issue-27282-mutate-before-diverging-arm-1.rs new file mode 100644 index 00000000000..b575f4ebce6 --- /dev/null +++ b/src/test/ui/issue-27282-mutate-before-diverging-arm-1.rs @@ -0,0 +1,43 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is testing an attempt to corrupt the discriminant of the match +// arm in a guard, followed by an attempt to continue matching on that +// corrupted discriminant in the remaining match arms. +// +// Basically this is testing that our new NLL feature of emitting a +// fake read on each match arm is catching cases like this. +// +// This case is interesting because it includes a guard that +// diverges, and therefore a single final fake-read at the very end +// after the final match arm would not suffice. + +#![feature(nll)] + +struct ForceFnOnce; + +fn main() { + let mut x = &mut Some(&2); + let force_fn_once = ForceFnOnce; + match x { + &mut None => panic!("unreachable"), + &mut Some(&_) if { + // ForceFnOnce needed to exploit #27282 + (|| { *x = None; drop(force_fn_once); })(); + //~^ ERROR closure requires unique access to `x` but it is already borrowed [E0500] + false + } => {} + &mut Some(&a) if { // this binds to garbage if we've corrupted discriminant + println!("{}", a); + panic!() + } => {} + _ => panic!("unreachable"), + } +} diff --git a/src/test/ui/issue-27282-mutate-before-diverging-arm-1.stderr b/src/test/ui/issue-27282-mutate-before-diverging-arm-1.stderr new file mode 100644 index 00000000000..8f7fe9d33fe --- /dev/null +++ b/src/test/ui/issue-27282-mutate-before-diverging-arm-1.stderr @@ -0,0 +1,25 @@ +error[E0500]: closure requires unique access to `x` but it is already borrowed + --> $DIR/issue-27282-mutate-before-diverging-arm-1.rs:33:14 + | +LL | match x { + | _____- + | |_____| + | || +LL | || &mut None => panic!("unreachable"), +LL | || &mut Some(&_) if { +LL | || // ForceFnOnce needed to exploit #27282 +LL | || (|| { *x = None; drop(force_fn_once); })(); + | || ^^ - borrow occurs due to use of `x` in closure + | || | + | || closure construction occurs here +... || +LL | || _ => panic!("unreachable"), +LL | || } + | || - + | ||_____| + | |______borrow occurs here + | borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0500`. diff --git a/src/test/ui/issue-27282-mutate-before-diverging-arm-2.rs b/src/test/ui/issue-27282-mutate-before-diverging-arm-2.rs new file mode 100644 index 00000000000..866fed13685 --- /dev/null +++ b/src/test/ui/issue-27282-mutate-before-diverging-arm-2.rs @@ -0,0 +1,52 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is testing an attempt to corrupt the discriminant of the match +// arm in a guard, followed by an attempt to continue matching on that +// corrupted discriminant in the remaining match arms. +// +// Basically this is testing that our new NLL feature of emitting a +// fake read on each match arm is catching cases like this. +// +// This case is interesting because it includes a guard that +// diverges, and therefore a single final fake-read at the very end +// after the final match arm would not suffice. +// +// It is also interesting because the access to the corrupted data +// occurs in the pattern-match itself, and not in the guard +// expression. + +#![feature(nll)] + +struct ForceFnOnce; + +fn main() { + let mut x = &mut Some(&2); + let force_fn_once = ForceFnOnce; + match x { + &mut None => panic!("unreachable"), + &mut Some(&_) + if { + // ForceFnOnce needed to exploit #27282 + (|| { *x = None; drop(force_fn_once); })(); + //~^ ERROR closure requires unique access to `x` but it is already borrowed [E0500] + false + } => {} + + // this segfaults if we corrupted the discriminant, because + // the compiler gets to *assume* that it cannot be the `None` + // case, even though that was the effect of the guard. + &mut Some(&2) + if { + panic!() + } => {} + _ => panic!("unreachable"), + } +} diff --git a/src/test/ui/issue-27282-mutate-before-diverging-arm-2.stderr b/src/test/ui/issue-27282-mutate-before-diverging-arm-2.stderr new file mode 100644 index 00000000000..df5e4300cec --- /dev/null +++ b/src/test/ui/issue-27282-mutate-before-diverging-arm-2.stderr @@ -0,0 +1,26 @@ +error[E0500]: closure requires unique access to `x` but it is already borrowed + --> $DIR/issue-27282-mutate-before-diverging-arm-2.rs:38:18 + | +LL | match x { + | _____- + | |_____| + | || +LL | || &mut None => panic!("unreachable"), +LL | || &mut Some(&_) +LL | || if { +LL | || // ForceFnOnce needed to exploit #27282 +LL | || (|| { *x = None; drop(force_fn_once); })(); + | || ^^ - borrow occurs due to use of `x` in closure + | || | + | || closure construction occurs here +... || +LL | || _ => panic!("unreachable"), +LL | || } + | || - + | ||_____| + | |______borrow occurs here + | borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0500`.