@@ -68,6 +68,8 @@ use iter::{Iterator, range};
68
68
use libc;
69
69
use kinds:: marker;
70
70
use ops:: Drop ;
71
+ use cmp:: Eq ;
72
+ use clone:: Clone ;
71
73
use option:: { Option , Some , None } ;
72
74
use ptr:: RawPtr ;
73
75
use ptr;
@@ -76,6 +78,7 @@ use str;
76
78
use vec:: { CloneableVector , ImmutableVector , MutableVector } ;
77
79
use vec;
78
80
use unstable:: intrinsics;
81
+ use rt:: global_heap:: malloc_raw;
79
82
80
83
/// Resolution options for the `null_byte` condition
81
84
pub enum NullByteResolution {
@@ -99,6 +102,36 @@ pub struct CString {
99
102
priv owns_buffer_ : bool ,
100
103
}
101
104
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
+
102
135
impl CString {
103
136
/// Create a C String from a pointer.
104
137
pub unsafe fn new ( buf : * libc:: c_char , owns_buffer : bool ) -> CString {
@@ -287,10 +320,7 @@ impl<'a> ToCStr for &'a [u8] {
287
320
288
321
unsafe fn to_c_str_unchecked ( & self ) -> CString {
289
322
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 ) ;
294
324
295
325
ptr:: copy_memory ( buf, self . as_ptr ( ) , self_len) ;
296
326
* ptr:: mut_offset ( buf, self_len as int ) = 0 ;
@@ -598,6 +628,44 @@ mod tests {
598
628
let c_str = unsafe { CString :: new ( ptr:: null ( ) , false ) } ;
599
629
c_str. iter ( ) ;
600
630
}
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
+ }
601
669
}
602
670
603
671
#[ cfg( test) ]
0 commit comments