Remove failure path from util::CowCString

This commit is contained in:
Simonas Kazlauskas
2015-11-08 13:04:25 +02:00
parent 099afbaa71
commit eca3fe927d
3 changed files with 17 additions and 29 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
/// UNIX implementation of dynamic library loading.
///
/// This module should eventually be expanded with more UNIX-specific functionality in the future.
use util::{CheckedCStr, CStringAsRef};
use util::{CowCString, CStringAsRef};
use std::ffi::{CStr, CString, OsStr};
use std::marker;
@@ -125,7 +125,7 @@ impl Library {
/// You may append a null byte at the end of the byte string to avoid string allocation in some
/// cases. E.g. for symbol `sin` you may write `b"sin\0"` instead of `b"sin"`.
pub unsafe fn get<T>(&self, symbol: &[u8]) -> ::Result<Symbol<T>> {
let symbol = try!(CheckedCStr::from_bytes(symbol));
let symbol = try!(CowCString::from_bytes(symbol));
// `dlsym` may return nullptr in two cases: when a symbol genuinely points to a null
// pointer or the symbol cannot be found. In order to detect this case a double dlerror
// pattern must be used, which is, sadly, a little bit racy.
+2 -2
View File
@@ -4,7 +4,7 @@
extern crate winapi;
extern crate kernel32;
use util::{CheckedCStr, CStringAsRef};
use util::{CowCString, CStringAsRef};
use std::ffi::{OsStr, OsString};
use std::marker;
@@ -67,7 +67,7 @@ impl Library {
/// You may append a null byte at the end of the byte string to avoid string allocation in some
/// cases. E.g. for symbol `sin` you may write `b"sin\0"` instead of `b"sin"`.
pub unsafe fn get<T>(&self, symbol: &[u8]) -> ::Result<Symbol<T>> {
let symbol = try!(CheckedCStr::from_bytes(symbol));
let symbol = try!(CowCString::from_bytes(symbol));
with_get_last_error(|| {
let symbol = kernel32::GetProcAddress(self.0, symbol.cstring_ref());
if symbol.is_null() {
+13 -25
View File
@@ -26,22 +26,19 @@ impl ::std::fmt::Display for NullError {
}
}
pub struct CheckedCStr<'a> {
s: Option<CString>,
p: Option<&'a raw::c_char>
pub enum CowCString<'a> {
Owned(CString),
Ref(&'a raw::c_char)
}
impl<'a> CheckedCStr<'a> {
impl<'a> CowCString<'a> {
/// Checks for last byte and avoids alocatting if its zero.
///
/// Non-last null bytes still result in an error.
pub fn from_bytes(slice: &'a [u8]) -> Result<CheckedCStr<'a>, NullError> {
pub fn from_bytes(slice: &'a [u8]) -> Result<CowCString<'a>, NullError> {
Ok(if slice.len() == 0 {
static ZERO: raw::c_char = 0;
CheckedCStr {
s: None,
p: Some(&ZERO)
}
CowCString::Ref(&ZERO)
} else if let Some(&0) = slice.last() {
// check for inner nulls
for (c, i) in slice.iter().zip(0..slice.len()-2) {
@@ -49,15 +46,9 @@ impl<'a> CheckedCStr<'a> {
return Err(NullError(i));
}
}
CheckedCStr {
s: None,
p: Some(unsafe { ::std::mem::transmute(slice.get_unchecked(0)) }),
}
CowCString::Ref(unsafe {::std::mem::transmute(slice.get_unchecked(0))})
} else {
CheckedCStr {
s: Some(try!(CString::new(slice))),
p: None
}
CowCString::Owned(try!(CString::new(slice)))
})
}
}
@@ -72,14 +63,11 @@ impl CStringAsRef for CString {
}
}
impl<'a> CStringAsRef for CheckedCStr<'a> {
fn cstring_ref(&self) -> &raw::c_char {
if let Some(ref p) = self.p {
*p
} else if let Some(ref s) = self.s {
s.cstring_ref()
} else {
unreachable!()
impl<'a> CStringAsRef for CowCString<'a> {
fn cstring_ref(&self) -> &raw::c_char {
match self {
&CowCString::Ref(r) => r,
&CowCString::Owned(ref o) => o.cstring_ref()
}
}
}