Skip to content

Commit fc77fed

Browse files
committed
Remove the lifetime anchors from raw-pointer-to-reference functions
The emerging consensus in Rust [RFC PR #556][RFC] is to allow freely inferred lifetimes. [RFC]: rust-lang/rfcs#556
1 parent f97392a commit fc77fed

File tree

2 files changed

+67
-32
lines changed

2 files changed

+67
-32
lines changed

src/c_str.rs

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,45 @@ const NUL: u8 = 0;
9494

9595
/// Scans a C string as a byte slice.
9696
///
97-
/// The second parameter provides the lifetime for the returned slice;
98-
/// its value is ignored.
9997
/// The returned slice does not include the terminating NUL byte.
10098
///
10199
/// # Panics
102100
///
103101
/// Panics if the string pointer is null.
104-
pub unsafe fn parse_as_bytes<'a, T: ?Sized>(raw: *const libc::c_char,
105-
life_anchor: &'a T)
106-
-> &'a [u8]
102+
///
103+
/// # Caveat
104+
///
105+
/// The lifetime of the returned reference is inferred from its usage.
106+
/// This may be incorrect in many cases. Consider this example:
107+
///
108+
/// ```rust
109+
/// #[macro_use]
110+
/// extern crate c_string;
111+
///
112+
/// extern crate libc;
113+
/// extern "C" {
114+
/// fn strdup(source: *const libc::c_char) -> *mut libc::c_char;
115+
/// }
116+
///
117+
/// fn main() {
118+
/// let ptr = unsafe { strdup(c_str!("Hello!").as_ptr()) };
119+
/// let s = unsafe { c_string::parse_as_bytes(ptr) };
120+
///
121+
/// unsafe { libc::free(ptr as *mut libc::c_void) };
122+
///
123+
/// // The line below, if uncommented, will access freed memory:
124+
/// //let guess_what = s[0];
125+
/// }
126+
/// ```
127+
///
128+
/// To prevent accidental misuse, the lifetime should be assigned in some
129+
/// controllable way. This can be a helper function or method taking the
130+
/// lifetime from a `host` value, when available. In other cases, explicit
131+
/// annotation may be used.
132+
pub unsafe fn parse_as_bytes<'a>(raw: *const libc::c_char) -> &'a [u8]
107133
{
108134
assert!(!raw.is_null());
109-
from_raw_ptr(raw, life_anchor).parse_as_bytes()
135+
from_raw_ptr(raw).parse_as_bytes()
110136
}
111137

112138
/// Scans a C string as UTF-8 string slice.
@@ -122,12 +148,17 @@ pub unsafe fn parse_as_bytes<'a, T: ?Sized>(raw: *const libc::c_char,
122148
/// # Panics
123149
///
124150
/// Panics if the string pointer is null.
151+
///
152+
/// # Caveat
153+
///
154+
/// The lifetime of the returned reference is inferred from its usage.
155+
/// See the documentation on `parse_as_bytes` for possible pitfalls and
156+
/// suggested practices to avoid them.
125157
#[inline]
126-
pub unsafe fn parse_as_utf8<'a, T: ?Sized>(raw: *const libc::c_char,
127-
life_anchor: &'a T)
128-
-> Result<&'a str, str::Utf8Error>
158+
pub unsafe fn parse_as_utf8<'a>(raw: *const libc::c_char)
159+
-> Result<&'a str, str::Utf8Error>
129160
{
130-
str::from_utf8(parse_as_bytes(raw, life_anchor))
161+
str::from_utf8(parse_as_bytes(raw))
131162
}
132163

133164
/// Representation of an allocated C String.
@@ -151,7 +182,7 @@ impl Deref for OwnedCString {
151182
type Target = CStr;
152183

153184
fn deref(&self) -> &CStr {
154-
unsafe { from_ptr_internal(self.ptr, self) }
185+
unsafe { from_ptr_internal(self.ptr) }
155186
}
156187
}
157188

@@ -476,11 +507,10 @@ impl fmt::Debug for CStrBuf {
476507
}
477508
}
478509

479-
unsafe fn from_ptr_internal<'a, T: ?Sized>(ptr: *const libc::c_char,
480-
life_anchor: &'a T)
481-
-> &'a CStr
510+
#[inline]
511+
unsafe fn from_ptr_internal<'a>(ptr: *const libc::c_char) -> &'a CStr
482512
{
483-
mem::copy_lifetime(life_anchor, &*(ptr as *const CStr))
513+
mem::transmute(&*(ptr as *const CStr))
484514
}
485515

486516
/// Create a `CStr` reference out of a static byte array.
@@ -497,7 +527,7 @@ pub fn from_static_bytes(bytes: &'static [u8]) -> &'static CStr {
497527
"static byte string is not null-terminated: \"{}\"",
498528
escape_bytestring(bytes));
499529
let ptr = bytes.as_ptr() as *const libc::c_char;
500-
unsafe { from_ptr_internal(ptr, bytes) }
530+
unsafe { from_ptr_internal(ptr) }
501531
}
502532

503533
/// Create a `CStr` reference out of a static string.
@@ -513,7 +543,7 @@ pub fn from_static_str(s: &'static str) -> &'static CStr {
513543
assert!(s.ends_with("\0"),
514544
"static string is not null-terminated: \"{}\"", s);
515545
let ptr = s.as_ptr() as *const libc::c_char;
516-
unsafe { from_ptr_internal(ptr, s) }
546+
unsafe { from_ptr_internal(ptr) }
517547
}
518548

519549
/// Constructs a `CStr` reference from a raw pointer to a
@@ -525,12 +555,17 @@ pub fn from_static_str(s: &'static str) -> &'static CStr {
525555
/// # Panics
526556
///
527557
/// Panics if the pointer is null.
528-
pub unsafe fn from_raw_ptr<'a, T: ?Sized>(ptr: *const libc::c_char,
529-
life_anchor: &'a T)
530-
-> &'a CStr
558+
///
559+
/// # Caveat
560+
///
561+
/// The lifetime of the returned reference is inferred from its usage.
562+
/// See the documentation on `parse_as_bytes` for possible pitfalls and
563+
/// suggested practices to avoid them.
564+
#[inline]
565+
pub unsafe fn from_raw_ptr<'a>(ptr: *const libc::c_char) -> &'a CStr
531566
{
532567
assert!(!ptr.is_null());
533-
from_ptr_internal(ptr, life_anchor)
568+
from_ptr_internal(ptr)
534569
}
535570

536571
impl CStr {
@@ -593,7 +628,7 @@ impl Deref for CStrBuf {
593628
CStrData::Owned(ref v) => (*v).as_ptr(),
594629
CStrData::InPlace(ref a) => a.as_ptr()
595630
} as *const libc::c_char;
596-
unsafe { from_ptr_internal(p, self) }
631+
unsafe { from_ptr_internal(p) }
597632
}
598633
}
599634

@@ -648,7 +683,7 @@ pub unsafe fn parse_c_multistring<F>(buf: *const libc::c_char,
648683
None => (false, 0)
649684
};
650685
while (!limited_count || ctr < limit) && *curr_ptr != 0 {
651-
let bytes = parse_as_bytes(curr_ptr, &buf);
686+
let bytes = parse_as_bytes(curr_ptr);
652687
f(bytes);
653688
curr_ptr = curr_ptr.offset(bytes.len() as isize + 1);
654689
ctr += 1;

tests/tests.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,26 +109,26 @@ fn test_iterator() {
109109
#[test]
110110
fn test_parse_as_bytes() {
111111
let c_str = str_dup("hello");
112-
let bytes = unsafe { parse_as_bytes(c_str.as_ptr(), &c_str) };
112+
let bytes = unsafe { parse_as_bytes(c_str.as_ptr()) };
113113
assert_eq!(bytes, b"hello");
114114
let c_str = str_dup("");
115-
let bytes = unsafe { parse_as_bytes(c_str.as_ptr(), &c_str) };
115+
let bytes = unsafe { parse_as_bytes(c_str.as_ptr()) };
116116
assert_eq!(bytes, b"");
117117
let c_str = bytes_dup(b"foo\xFF");
118-
let bytes = unsafe { parse_as_bytes(c_str.as_ptr(), &c_str) };
118+
let bytes = unsafe { parse_as_bytes(c_str.as_ptr()) };
119119
assert_eq!(bytes, b"foo\xFF");
120120
}
121121

122122
#[test]
123123
fn test_parse_as_utf8() {
124124
let c_str = str_dup("hello");
125-
let res = unsafe { parse_as_utf8(c_str.as_ptr(), &c_str) };
125+
let res = unsafe { parse_as_utf8(c_str.as_ptr()) };
126126
assert_eq!(res, Ok("hello"));
127127
let c_str = str_dup("");
128-
let res = unsafe { parse_as_utf8(c_str.as_ptr(), &c_str) };
128+
let res = unsafe { parse_as_utf8(c_str.as_ptr()) };
129129
assert_eq!(res, Ok(""));
130130
let c_str = bytes_dup(b"foo\xFF");
131-
let res = unsafe { parse_as_utf8(c_str.as_ptr(), &c_str) };
131+
let res = unsafe { parse_as_utf8(c_str.as_ptr()) };
132132
assert!(res.is_err());
133133
}
134134

@@ -263,7 +263,7 @@ fn test_owned_c_string_debug() {
263263
fn test_parse_null_as_bytes_fail() {
264264
unsafe {
265265
let p: *const libc::c_char = ptr::null();
266-
let _ = parse_as_bytes(p, &p);
266+
let _ = parse_as_bytes(p);
267267
};
268268
}
269269

@@ -272,7 +272,7 @@ fn test_parse_null_as_bytes_fail() {
272272
fn test_parse_null_as_utf8_fail() {
273273
unsafe {
274274
let p: *const libc::c_char = ptr::null();
275-
let _ = parse_as_utf8(p, &p);
275+
let _ = parse_as_utf8(p);
276276
};
277277
}
278278

@@ -300,5 +300,5 @@ fn test_from_static_str_fail() {
300300
#[should_fail]
301301
fn test_from_raw_ptr_fail() {
302302
let p: *const libc::c_char = ptr::null();
303-
let _c_str = unsafe { from_raw_ptr(p, &p) };
303+
let _c_str = unsafe { from_raw_ptr(p) };
304304
}

0 commit comments

Comments
 (0)