Fix string data conversion in ErrorStack::put()

This commit is contained in:
Kornel 2025-10-01 11:50:08 +01:00 committed by Kornel
parent 353ea62c17
commit e3998212ed
1 changed files with 31 additions and 25 deletions

View File

@ -20,6 +20,7 @@ use openssl_macros::corresponds;
use std::borrow::Cow; use std::borrow::Cow;
use std::error; use std::error;
use std::ffi::CStr; use std::ffi::CStr;
use std::ffi::CString;
use std::fmt; use std::fmt;
use std::io; use std::io;
use std::ptr; use std::ptr;
@ -58,7 +59,7 @@ impl ErrorStack {
/// Used to report errors from the Rust crate /// Used to report errors from the Rust crate
#[cold] #[cold]
pub(crate) fn internal_error(err: impl error::Error) -> Self { pub(crate) fn internal_error(err: impl error::Error) -> Self {
Self(vec![Error::new_internal(err.to_string())]) Self(vec![Error::new_internal(Data::String(err.to_string()))])
} }
/// Empties the current thread's error queue. /// Empties the current thread's error queue.
@ -122,7 +123,14 @@ pub struct Error {
code: c_uint, code: c_uint,
file: *const c_char, file: *const c_char,
line: c_uint, line: c_uint,
data: Option<Cow<'static, str>>, data: Data,
}
#[derive(Clone)]
enum Data {
None,
CString(CString),
String(String),
} }
unsafe impl Sync for Error {} unsafe impl Sync for Error {}
@ -148,11 +156,9 @@ impl Error {
// The memory referenced by data is only valid until that slot is overwritten // The memory referenced by data is only valid until that slot is overwritten
// in the error stack, so we'll need to copy it off if it's dynamic // in the error stack, so we'll need to copy it off if it's dynamic
let data = if flags & ffi::ERR_FLAG_STRING != 0 { let data = if flags & ffi::ERR_FLAG_STRING != 0 {
Some(Cow::Owned( Data::CString(CStr::from_ptr(data.cast()).to_owned())
CStr::from_ptr(data.cast()).to_string_lossy().into_owned(),
))
} else { } else {
None Data::None
}; };
Some(Error { Some(Error {
code, code,
@ -176,22 +182,8 @@ impl Error {
self.file, self.file,
self.line, self.line,
); );
let ptr = match self.data { if let Some(cstr) = self.data_cstr() {
Some(Cow::Borrowed(data)) => Some(data.as_ptr() as *mut c_char), ffi::ERR_set_error_data(cstr.as_ptr().cast_mut(), ffi::ERR_FLAG_STRING);
Some(Cow::Owned(ref data)) => {
let ptr = ffi::OPENSSL_malloc((data.len() + 1) as _) as *mut c_char;
if ptr.is_null() {
None
} else {
ptr::copy_nonoverlapping(data.as_ptr(), ptr as *mut u8, data.len());
*ptr.add(data.len()) = 0;
Some(ptr)
}
}
None => None,
};
if let Some(ptr) = ptr {
ffi::ERR_add_error_data(1, ptr);
} }
} }
} }
@ -297,15 +289,29 @@ impl Error {
/// Returns additional data describing the error. /// Returns additional data describing the error.
#[must_use] #[must_use]
pub fn data(&self) -> Option<&str> { pub fn data(&self) -> Option<&str> {
self.data.as_deref() match &self.data {
Data::None => None,
Data::CString(cstring) => cstring.to_str().ok(),
Data::String(s) => Some(s),
}
} }
fn new_internal(msg: String) -> Self { #[must_use]
fn data_cstr(&self) -> Option<Cow<'_, CStr>> {
let s = match &self.data {
Data::None => return None,
Data::CString(cstr) => return Some(Cow::Borrowed(cstr)),
Data::String(s) => s.as_str(),
};
CString::new(s).ok().map(Cow::Owned)
}
fn new_internal(msg: Data) -> Self {
Self { Self {
code: ffi::ERR_PACK(ffi::ERR_LIB_NONE.0 as _, 0, 0) as _, code: ffi::ERR_PACK(ffi::ERR_LIB_NONE.0 as _, 0, 0) as _,
file: BORING_INTERNAL.as_ptr(), file: BORING_INTERNAL.as_ptr(),
line: 0, line: 0,
data: Some(msg.into()), data: msg,
} }
} }