@@ -86,13 +86,10 @@ impl CFString {
86
86
///
87
87
/// Warning: This is very difficult to ensure in generic contexts, e.g. it
88
88
/// cannot even be used inside `Debug::fmt`, since `Formatter` uses `dyn`
89
- /// internally, and can thus mutate the string inside there.
89
+ /// internally, and could thus mutate the string inside there.
90
90
#[ doc( alias = "CFStringGetCStringPtr" ) ]
91
- // NOTE: This is NOT public, since it's completely broken for differently
92
- // encoded strings, see the `as_str_broken` test below. See also:
93
- // <https://github.com/swiftlang/swift-corelibs-foundation/issues/5164>.
94
- #[ allow( dead_code) ]
95
- unsafe fn as_str_unchecked ( & self ) -> Option < & str > {
91
+ pub unsafe fn as_str_unchecked ( & self ) -> Option < & str > {
92
+ // NOTE: The encoding is an 8-bit encoding.
96
93
let bytes = CFStringGetCStringPtr ( self , CFStringBuiltInEncodings :: EncodingUTF8 . 0 ) ;
97
94
NonNull :: new ( bytes as * mut c_char ) . map ( |bytes| {
98
95
// SAFETY: The pointer is valid for as long as the CFString is not
@@ -102,8 +99,6 @@ impl CFString {
102
99
// We won't accidentally truncate the string here, since
103
100
// `CFStringGetCStringPtr` makes sure that there are no internal
104
101
// NUL bytes in the string.
105
- //
106
- // TODO: Verify this claim with a test.
107
102
let cstr = unsafe { CStr :: from_ptr ( bytes. as_ptr ( ) ) } ;
108
103
// SAFETY: `CFStringGetCStringPtr` is (very likely) implemented
109
104
// correctly, and won't return non-UTF8 strings.
@@ -255,6 +250,8 @@ mod tests {
255
250
let s = CFString :: from_str ( "a\0 b\0 c\0 d" ) ;
256
251
// Works with `CFStringGetBytes`.
257
252
assert_eq ! ( s. to_string( ) , "a\0 b\0 c\0 d" ) ;
253
+ // Expectedly does not work `CFStringGetCStringPtr`.
254
+ assert_eq ! ( unsafe { s. as_str_unchecked( ) } , None ) ;
258
255
259
256
// Test `CFStringGetCString`.
260
257
let mut buf = [ 0u8 ; 10 ] ;
@@ -287,9 +284,15 @@ mod tests {
287
284
}
288
285
289
286
#[ test]
290
- fn as_str_broken ( ) {
287
+ fn create_with_cstring_broken_on_non_8_bit ( ) {
291
288
// A CFString that is supposed to contain a "♥" (the UTF-8 encoding of
292
289
// that is the vastly different b"\xE2\x99\xA5").
290
+ //
291
+ // This line is wrong, because `CFStringCreateWithCString` expects an
292
+ // 8-bit encoding.
293
+ //
294
+ // See also:
295
+ // https://github.com/swiftlang/swift-corelibs-foundation/issues/5164
293
296
let s = unsafe {
294
297
CFStringCreateWithCString (
295
298
None ,
@@ -315,8 +318,7 @@ mod tests {
315
318
let cstr = CStr :: from_bytes_until_nul ( & buf) . unwrap ( ) ;
316
319
assert_eq ! ( cstr. to_bytes( ) , "♥" . as_bytes( ) ) ;
317
320
318
- // But `CFStringGetCStringPtr` completely ignores the UTF-8 conversion
319
- // we asked it to do, i.e. a huge correctness footgun!
321
+ // `CFStringGetCStringPtr` completely ignores the UTF-8 conversion.
320
322
assert_eq ! ( unsafe { s. as_str_unchecked( ) } , Some ( "e&" ) ) ;
321
323
}
322
324
0 commit comments