@@ -68,6 +68,7 @@ use iter::{Iterator, range};
6868use libc;
6969use kinds:: marker;
7070use ops:: Drop ;
71+ use clone:: Clone ;
7172use option:: { Option , Some , None } ;
7273use ptr:: RawPtr ;
7374use ptr;
@@ -76,6 +77,7 @@ use str;
7677use vec:: { CloneableVector , ImmutableVector , MutableVector } ;
7778use vec;
7879use unstable:: intrinsics;
80+ use rt:: global_heap:: malloc_raw;
7981
8082/// Resolution options for the `null_byte` condition
8183pub 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+
102119impl 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