@@ -68,6 +68,7 @@ use iter::{Iterator, range};
68
68
use libc;
69
69
use kinds:: marker;
70
70
use ops:: Drop ;
71
+ use clone:: Clone ;
71
72
use option:: { Option , Some , None } ;
72
73
use ptr:: RawPtr ;
73
74
use ptr;
@@ -76,6 +77,7 @@ use str;
76
77
use vec:: { CloneableVector , ImmutableVector , MutableVector } ;
77
78
use vec;
78
79
use unstable:: intrinsics;
80
+ use rt:: global_heap:: malloc_raw;
79
81
80
82
/// Resolution options for the `null_byte` condition
81
83
pub enum NullByteResolution {
@@ -99,6 +101,21 @@ pub struct CString {
99
101
priv owns_buffer_ : bool ,
100
102
}
101
103
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
+
102
119
impl CString {
103
120
/// Create a C String from a pointer.
104
121
pub unsafe fn new ( buf : * libc:: c_char , owns_buffer : bool ) -> CString {
@@ -287,10 +304,7 @@ impl<'a> ToCStr for &'a [u8] {
287
304
288
305
unsafe fn to_c_str_unchecked ( & self ) -> CString {
289
306
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 ) ;
294
308
295
309
ptr:: copy_memory ( buf, self . as_ptr ( ) , self_len) ;
296
310
* ptr:: mut_offset ( buf, self_len as int ) = 0 ;
@@ -598,6 +612,36 @@ mod tests {
598
612
let c_str = unsafe { CString :: new ( ptr:: null ( ) , false ) } ;
599
613
c_str. iter ( ) ;
600
614
}
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
+ }
601
645
}
602
646
603
647
#[ cfg( test) ]
0 commit comments