Rollup merge of #36741 - matklad:no-flacky-test, r=alexcrichton

Remove CString drop test.

The test relies on the undefined behavior, and so may fail in some
circumstances. This can be worked around by stubbing a memory allocator
in the test, but it is a bit of work, and LLVM could still theoretically
eliminate the write of the zero byte in release mode (which is
intended).

So let's just remove the test and mark the function as inline. It
shouldn't be optimized away when inlined into the debug build of user's
code.

Supersedes #36607

r? @alexcrichton
This commit is contained in:
Jonathan Turner 2016-09-28 20:21:51 -07:00 committed by GitHub
commit 8f2c000506
2 changed files with 3 additions and 50 deletions

View File

@ -314,9 +314,11 @@ impl CString {
}
// Turns this `CString` into an empty string to prevent
// memory unsafe code from working by accident.
// memory unsafe code from working by accident. Inline
// to prevent LLVM from optimizing it away in debug builds.
#[stable(feature = "cstring_drop", since = "1.13.0")]
impl Drop for CString {
#[inline]
fn drop(&mut self) {
unsafe { *self.inner.get_unchecked_mut(0) = 0; }
}

View File

@ -1,49 +0,0 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-emscripten
// Test that `CString::new("hello").unwrap().as_ptr()` pattern
// leads to failure.
use std::env;
use std::ffi::{CString, CStr};
use std::os::raw::c_char;
use std::process::{Command, Stdio};
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() > 1 && args[1] == "child" {
// Repeat several times to be more confident that
// it is `Drop` for `CString` that does the cleanup,
// and not just some lucky UB.
let xs = vec![CString::new("Hello").unwrap(); 10];
let ys = xs.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
drop(xs);
assert!(ys.into_iter().any(is_hello));
return;
}
let output = Command::new(&args[0]).arg("child").output().unwrap();
assert!(!output.status.success());
}
fn is_hello(s: *const c_char) -> bool {
// `s` is a dangling pointer and reading it is technically
// undefined behavior. But we want to prevent the most diabolical
// kind of UB (apart from nasal demons): reading a value that was
// previously written.
//
// Segfaulting or reading an empty string is Ok,
// reading "Hello" is bad.
let s = unsafe { CStr::from_ptr(s) };
let hello = CString::new("Hello").unwrap();
s == hello.as_ref()
}