auto merge of #11840 : cmr/rust/cstr, r=kballard

This commit is contained in:
bors 2014-02-01 15:46:25 -08:00
commit a72ab2d31c

View File

@ -68,6 +68,8 @@
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 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 @@ fn to_c_str(&self) -> CString {
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 @@ fn test_iter_fail() {
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)]