Skip to content

Commit a72ab2d

Browse files
committed
auto merge of #11840 : cmr/rust/cstr, r=kballard
2 parents 2bcd951 + a7f0ecf commit a72ab2d

File tree

1 file changed

+72
-4
lines changed

1 file changed

+72
-4
lines changed

src/libstd/c_str.rs

+72-4
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ use iter::{Iterator, range};
6868
use libc;
6969
use kinds::marker;
7070
use ops::Drop;
71+
use cmp::Eq;
72+
use clone::Clone;
7173
use option::{Option, Some, None};
7274
use ptr::RawPtr;
7375
use ptr;
@@ -76,6 +78,7 @@ use str;
7678
use vec::{CloneableVector, ImmutableVector, MutableVector};
7779
use vec;
7880
use unstable::intrinsics;
81+
use rt::global_heap::malloc_raw;
7982

8083
/// Resolution options for the `null_byte` condition
8184
pub enum NullByteResolution {
@@ -99,6 +102,36 @@ pub struct CString {
99102
priv owns_buffer_: bool,
100103
}
101104

105+
impl Clone for CString {
106+
/// Clone this CString into a new, uniquely owned CString. For safety
107+
/// reasons, this is always a deep clone, rather than the usual shallow
108+
/// clone.
109+
fn clone(&self) -> CString {
110+
if self.buf.is_null() {
111+
CString { buf: self.buf, owns_buffer_: self.owns_buffer_ }
112+
} else {
113+
let len = self.len() + 1;
114+
let buf = unsafe { malloc_raw(len) } as *mut libc::c_char;
115+
unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); }
116+
CString { buf: buf as *libc::c_char, owns_buffer_: true }
117+
}
118+
}
119+
}
120+
121+
impl Eq for CString {
122+
fn eq(&self, other: &CString) -> bool {
123+
if self.buf as uint == other.buf as uint {
124+
true
125+
} else if self.buf.is_null() || other.buf.is_null() {
126+
false
127+
} else {
128+
unsafe {
129+
libc::strcmp(self.buf, other.buf) == 0
130+
}
131+
}
132+
}
133+
}
134+
102135
impl CString {
103136
/// Create a C String from a pointer.
104137
pub unsafe fn new(buf: *libc::c_char, owns_buffer: bool) -> CString {
@@ -287,10 +320,7 @@ impl<'a> ToCStr for &'a [u8] {
287320

288321
unsafe fn to_c_str_unchecked(&self) -> CString {
289322
let self_len = self.len();
290-
let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
291-
if buf.is_null() {
292-
fail!("failed to allocate memory!");
293-
}
323+
let buf = malloc_raw(self_len + 1);
294324

295325
ptr::copy_memory(buf, self.as_ptr(), self_len);
296326
*ptr::mut_offset(buf, self_len as int) = 0;
@@ -598,6 +628,44 @@ mod tests {
598628
let c_str = unsafe { CString::new(ptr::null(), false) };
599629
c_str.iter();
600630
}
631+
632+
#[test]
633+
fn test_clone() {
634+
let a = "hello".to_c_str();
635+
let b = a.clone();
636+
assert!(a == b);
637+
}
638+
639+
#[test]
640+
fn test_clone_noleak() {
641+
fn foo(f: |c: &CString|) {
642+
let s = ~"test";
643+
let c = s.to_c_str();
644+
// give the closure a non-owned CString
645+
let mut c_ = c.with_ref(|c| unsafe { CString::new(c, false) } );
646+
f(&c_);
647+
// muck with the buffer for later printing
648+
c_.with_mut_ref(|c| unsafe { *c = 'X' as libc::c_char } );
649+
}
650+
651+
let mut c_: Option<CString> = None;
652+
foo(|c| {
653+
c_ = Some(c.clone());
654+
c.clone();
655+
// force a copy, reading the memory
656+
c.as_bytes().to_owned();
657+
});
658+
let c_ = c_.unwrap();
659+
// force a copy, reading the memory
660+
c_.as_bytes().to_owned();
661+
}
662+
663+
#[test]
664+
fn test_clone_eq_null() {
665+
let x = unsafe { CString::new(ptr::null(), false) };
666+
let y = x.clone();
667+
assert!(x == y);
668+
}
601669
}
602670

603671
#[cfg(test)]

0 commit comments

Comments
 (0)