From 300e13808e679e6224f51705794b234dfd8bf73a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 26 Sep 2016 15:22:22 +0300 Subject: [PATCH] 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. --- src/libstd/ffi/c_str.rs | 4 ++- src/test/run-pass/cstring-drop.rs | 49 ------------------------------- 2 files changed, 3 insertions(+), 50 deletions(-) delete mode 100644 src/test/run-pass/cstring-drop.rs diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index d6a5efbd279..6f5ce350e6c 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -314,9 +314,11 @@ fn into_inner(self) -> Box<[u8]> { } // 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; } } diff --git a/src/test/run-pass/cstring-drop.rs b/src/test/run-pass/cstring-drop.rs deleted file mode 100644 index 960391bb8de..00000000000 --- a/src/test/run-pass/cstring-drop.rs +++ /dev/null @@ -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 or the MIT license -// , 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 = 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::>(); - 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() -}