about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-02-01 15:46:25 -0800
committerbors <bors@rust-lang.org>2014-02-01 15:46:25 -0800
commita72ab2d31c9f2c0d7f19ef70aa8ef3fcfef68175 (patch)
tree58f43bb92ab8b4d3a313b1b37772c6d03ebc5d76 /src
parent2bcd951749b67402ccaa31f1bb0349656f880fe2 (diff)
parenta7f0ecf5626aefc3a269f32d70316654f5b4773f (diff)
downloadrust-a72ab2d31c9f2c0d7f19ef70aa8ef3fcfef68175.tar.gz
rust-a72ab2d31c9f2c0d7f19ef70aa8ef3fcfef68175.zip
auto merge of #11840 : cmr/rust/cstr, r=kballard
Diffstat (limited to 'src')
-rw-r--r--src/libstd/c_str.rs76
1 files changed, 72 insertions, 4 deletions
diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs
index b7374b6f15d..7e79ad97df0 100644
--- a/src/libstd/c_str.rs
+++ b/src/libstd/c_str.rs
@@ -68,6 +68,8 @@ use iter::{Iterator, range};
 use libc;
 use kinds::marker;
 use ops::Drop;
+use cmp::Eq;
+use clone::Clone;
 use option::{Option, Some, None};
 use ptr::RawPtr;
 use ptr;
@@ -76,6 +78,7 @@ use str;
 use vec::{CloneableVector, ImmutableVector, MutableVector};
 use vec;
 use unstable::intrinsics;
+use rt::global_heap::malloc_raw;
 
 /// Resolution options for the `null_byte` condition
 pub enum NullByteResolution {
@@ -99,6 +102,36 @@ pub struct CString {
     priv owns_buffer_: bool,
 }
 
+impl Clone for CString {
+    /// Clone this CString into a new, uniquely owned CString. For safety
+    /// reasons, this is always a deep clone, rather than the usual shallow
+    /// clone.
+    fn clone(&self) -> CString {
+        if self.buf.is_null() {
+            CString { buf: self.buf, owns_buffer_: self.owns_buffer_ }
+        } else {
+            let len = self.len() + 1;
+            let buf = unsafe { malloc_raw(len) } as *mut libc::c_char;
+            unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); }
+            CString { buf: buf as *libc::c_char, owns_buffer_: true }
+        }
+    }
+}
+
+impl Eq for CString {
+    fn eq(&self, other: &CString) -> bool {
+        if self.buf as uint == other.buf as uint {
+            true
+        } else if self.buf.is_null() || other.buf.is_null() {
+            false
+        } else {
+            unsafe {
+                libc::strcmp(self.buf, other.buf) == 0
+            }
+        }
+    }
+}
+
 impl CString {
     /// Create a C String from a pointer.
     pub unsafe fn new(buf: *libc::c_char, owns_buffer: bool) -> CString {
@@ -287,10 +320,7 @@ impl<'a> ToCStr for &'a [u8] {
 
     unsafe fn to_c_str_unchecked(&self) -> CString {
         let self_len = self.len();
-        let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
-        if buf.is_null() {
-            fail!("failed to allocate memory!");
-        }
+        let buf = malloc_raw(self_len + 1);
 
         ptr::copy_memory(buf, self.as_ptr(), self_len);
         *ptr::mut_offset(buf, self_len as int) = 0;
@@ -598,6 +628,44 @@ mod tests {
         let c_str = unsafe { CString::new(ptr::null(), false) };
         c_str.iter();
     }
+
+    #[test]
+    fn test_clone() {
+        let a = "hello".to_c_str();
+        let b = a.clone();
+        assert!(a == b);
+    }
+
+    #[test]
+    fn test_clone_noleak() {
+        fn foo(f: |c: &CString|) {
+            let s = ~"test";
+            let c = s.to_c_str();
+            // give the closure a non-owned CString
+            let mut c_ = c.with_ref(|c| unsafe { CString::new(c, false) } );
+            f(&c_);
+            // muck with the buffer for later printing
+            c_.with_mut_ref(|c| unsafe { *c = 'X' as libc::c_char } );
+        }
+
+        let mut c_: Option<CString> = None;
+        foo(|c| {
+            c_ = Some(c.clone());
+            c.clone();
+            // force a copy, reading the memory
+            c.as_bytes().to_owned();
+        });
+        let c_ = c_.unwrap();
+        // force a copy, reading the memory
+        c_.as_bytes().to_owned();
+    }
+
+    #[test]
+    fn test_clone_eq_null() {
+        let x = unsafe { CString::new(ptr::null(), false) };
+        let y = x.clone();
+        assert!(x == y);
+    }
 }
 
 #[cfg(test)]