Skip to content

Commit f0c39a8

Browse files
committed
---
yaml --- r: 148815 b: refs/heads/try2 c: 73024e4 h: refs/heads/master i: 148813: 181eec1 148811: a28ccaa 148807: 3d71884 148799: 29234b9 v: v3
1 parent 80d95f9 commit f0c39a8

File tree

2 files changed

+49
-5
lines changed

2 files changed

+49
-5
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ refs/heads/snap-stage3: 78a7676898d9f80ab540c6df5d4c9ce35bb50463
55
refs/heads/try: 519addf6277dbafccbb4159db4b710c37eaa2ec5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
8-
refs/heads/try2: 2bcd951749b67402ccaa31f1bb0349656f880fe2
8+
refs/heads/try2: 73024e4b858e6c2083f40e8c987acedc22e9672b
99
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try2/src/libstd/c_str.rs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ use iter::{Iterator, range};
6868
use libc;
6969
use kinds::marker;
7070
use ops::Drop;
71+
use clone::Clone;
7172
use option::{Option, Some, None};
7273
use ptr::RawPtr;
7374
use ptr;
@@ -76,6 +77,7 @@ use str;
7677
use vec::{CloneableVector, ImmutableVector, MutableVector};
7778
use vec;
7879
use unstable::intrinsics;
80+
use rt::global_heap::malloc_raw;
7981

8082
/// Resolution options for the `null_byte` condition
8183
pub enum NullByteResolution {
@@ -99,6 +101,21 @@ pub struct CString {
99101
priv owns_buffer_: bool,
100102
}
101103

104+
impl Clone for CString {
105+
/// Clone this CString into a new, uniquely owned CString. For safety
106+
/// reasons, this is always a deep clone, rather than the usual shallow
107+
/// clone.
108+
fn clone(&self) -> CString {
109+
if self.buf.is_null() {
110+
CString { buf: self.buf, owns_buffer_: self.owns_buffer_ }
111+
} else {
112+
let buf = unsafe { malloc_raw(self.len()) } as *mut libc::c_char;
113+
unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, self.len()); }
114+
CString { buf: buf as *libc::c_char, owns_buffer_: true }
115+
}
116+
}
117+
}
118+
102119
impl CString {
103120
/// Create a C String from a pointer.
104121
pub unsafe fn new(buf: *libc::c_char, owns_buffer: bool) -> CString {
@@ -287,10 +304,7 @@ impl<'a> ToCStr for &'a [u8] {
287304

288305
unsafe fn to_c_str_unchecked(&self) -> CString {
289306
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-
}
307+
let buf = malloc_raw(self_len + 1);
294308

295309
ptr::copy_memory(buf, self.as_ptr(), self_len);
296310
*ptr::mut_offset(buf, self_len as int) = 0;
@@ -598,6 +612,36 @@ mod tests {
598612
let c_str = unsafe { CString::new(ptr::null(), false) };
599613
c_str.iter();
600614
}
615+
616+
#[test]
617+
fn test_clone() {
618+
let c_str = "hello".to_c_str();
619+
assert!(c_str == c_str.clone());
620+
}
621+
622+
#[test]
623+
fn test_clone_noleak() {
624+
fn foo(f: |c: &CString|) {
625+
let s = ~"test";
626+
let c = s.to_c_str();
627+
// give the closure a non-owned CString
628+
let mut c_ = c.with_ref(|c| unsafe { CString::new(c, false) } );
629+
f(&c_);
630+
// muck with the buffer for later printing
631+
c_.with_mut_ref(|c| unsafe { *c = 'X' as libc::c_char } );
632+
}
633+
634+
let mut c_: Option<CString> = None;
635+
foo(|c| {
636+
c_ = Some(c.clone());
637+
c.clone();
638+
// force a copy, reading the memory
639+
c.as_bytes().to_owned();
640+
});
641+
let c_ = c_.unwrap();
642+
// force a copy, reading the memory
643+
c_.as_bytes().to_owned();
644+
}
601645
}
602646

603647
#[cfg(test)]

0 commit comments

Comments
 (0)