about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAleksey Kladov <aleksey.kladov@gmail.com>2016-09-07 10:13:49 +0300
committerAleksey Kladov <aleksey.kladov@gmail.com>2016-09-07 22:33:10 +0300
commitf9a340804c998f25691be182fc8bc40b8fc9a496 (patch)
tree03674650e28b0248ecaa764ca3115c8280e4fc2a /src
parent04b776e5eca7aa49618a1425f08c8825e51b19dc (diff)
downloadrust-f9a340804c998f25691be182fc8bc40b8fc9a496.tar.gz
rust-f9a340804c998f25691be182fc8bc40b8fc9a496.zip
Add a test for CString drop
Diffstat (limited to 'src')
-rw-r--r--src/test/run-pass/cstring-drop.rs49
1 files changed, 49 insertions, 0 deletions
diff --git a/src/test/run-pass/cstring-drop.rs b/src/test/run-pass/cstring-drop.rs
new file mode 100644
index 00000000000..960391bb8de
--- /dev/null
+++ b/src/test/run-pass/cstring-drop.rs
@@ -0,0 +1,49 @@
+// 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()
+}