Explicitly panic when out of memory.

- Change `rust_str_to_c_str` and `rust_bytes_to_c_str_lossy` to
    return a `Result`.

  - Return `Error::OutOfMemory` if `malloc` fails instead of undefined
    behavior.

  - Update the callers to propagate the error when convenient and to
    panic explicitly when not.

    - Note: Rust panics if a memory allocation fails so we don't go
      too far out of the way to propagate memory allocation errors.
pull/8/head
Neal H. Walfield 2 years ago
parent 4b05eb03aa
commit f69b85ff9c

@ -20,28 +20,40 @@ use crate::Result;
use crate::ffi::MM;
/// Copies a Rust string to a buffer, adding a terminating zero.
pub fn rust_str_to_c_str<S: AsRef<str>>(mm: MM, s: S) -> *mut c_char {
pub fn rust_str_to_c_str<S: AsRef<str>>(mm: MM, s: S)
-> Result<*mut c_char>
{
let malloc = mm.malloc;
let s = s.as_ref();
let bytes = s.as_bytes();
unsafe {
let buf = malloc(bytes.len() + 1);
if buf.is_null() {
return Err(Error::OutOfMemory("rust_bytes_to_c_str_lossy".into(),
bytes.len() + 1));
};
copy_nonoverlapping(bytes.as_ptr(), buf as *mut _, bytes.len());
*((buf as *mut u8).add(bytes.len())) = 0; // Terminate.
buf as *mut c_char
Ok(buf as *mut c_char)
}
}
/// Copies a C string to a buffer, adding a terminating zero.
///
/// Replaces embedded zeros with '_'.
pub fn rust_bytes_to_c_str_lossy<S: AsRef<[u8]>>(mm: MM, s: S) -> *mut c_char {
pub fn rust_bytes_to_c_str_lossy<S: AsRef<[u8]>>(mm: MM, s: S)
-> Result<*mut c_char>
{
let malloc = mm.malloc;
let bytes = s.as_ref();
unsafe {
let buf = malloc(bytes.len() + 1);
if buf.is_null() {
return Err(Error::OutOfMemory("rust_bytes_to_c_str_lossy".into(),
bytes.len() + 1));
};
copy_nonoverlapping(bytes.as_ptr(), buf as *mut _, bytes.len());
// Replace embedded zeros.
@ -50,7 +62,7 @@ pub fn rust_bytes_to_c_str_lossy<S: AsRef<[u8]>>(mm: MM, s: S) -> *mut c_char {
bytes_mut.iter_mut().for_each(|b| if *b == 0 { *b = b'_' });
*((buf as *mut u8).add(bytes.len())) = 0; // Terminate.
buf as *mut c_char
Ok(buf as *mut c_char)
}
}

@ -803,13 +803,13 @@ ffi!(fn pgp_decrypt_and_verify(session: *mut Session,
});
if ! filename_ptr.is_null() {
unsafe { filename_ptr.as_mut() }.map(|p| {
if let Some(p) = unsafe { filename_ptr.as_mut() } {
if let Some(filename) = h.filename.as_ref() {
*p = rust_bytes_to_c_str_lossy(mm, filename);
*p = rust_bytes_to_c_str_lossy(mm, filename)?;
} else {
*p = ptr::null_mut();
}
});
};
}
// **********************************

@ -104,10 +104,13 @@ impl PepIdentity {
panic!("Out of memory allocating a PepIdentity");
};
let ident = unsafe { &mut *(buffer as *mut Self) };
ident.address = rust_str_to_c_str(mm, &template.address);
ident.fpr = rust_str_to_c_str(mm, &template.fpr.to_hex());
ident.address = rust_str_to_c_str(mm, &template.address)
.expect("Out of memory allocating ident.address");
ident.fpr = rust_str_to_c_str(mm, &template.fpr.to_hex())
.expect("Out of memory allocating ident.fpr");
if let Some(username) = template.username.as_ref() {
ident.username = rust_str_to_c_str(mm, username);
ident.username = rust_str_to_c_str(mm, username)
.expect("Out of memory allocating ident.username");
}
ident
}
@ -140,7 +143,11 @@ impl PepIdentity {
/// Replaces the fingerprint.
pub fn set_fingerprint(&mut self, mm: MM, fpr: Fingerprint) {
unsafe { libc::free(self.fpr as *mut _) };
self.fpr = rust_str_to_c_str(mm, fpr.to_hex());
// Clear to avoid a dangling pointers if the following
// allocation fails.
self.fpr = ptr::null_mut();
self.fpr = rust_str_to_c_str(mm, fpr.to_hex())
.expect("Out of memory allocating fingerprint");
}
/// Returns the username (in RFC 2822 speak: the display name).

@ -52,7 +52,8 @@ impl StringListItem {
fn new<S: AsRef<str>>(mm: MM, value: S, next: *mut Self) -> &'static mut Self {
let item = Self::empty(mm);
item.value = rust_str_to_c_str(mm, value);
item.value = rust_str_to_c_str(mm, value)
.expect("Out of memory allocating StringListItem");
item.next = next;
item
@ -184,7 +185,8 @@ impl StringList {
if item.value.is_null() {
// 2. head is not NULL, but head.value is NULL.
item.value = rust_str_to_c_str(mm, value);
item.value = rust_str_to_c_str(mm, value)
.expect("Out of memory allocating StringList.value");
} else {
// 3. neither head nor head.value are NULL.
assert!(item.next.is_null());

Loading…
Cancel
Save