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::error;
use std::ffi::CStr;
use std::ffi::CString;
use std::fmt;
use std::io;
use std::ptr;
@ -58,7 +59,7 @@ impl ErrorStack {
/// Used to report errors from the Rust crate
#[cold]
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.
@ -122,7 +123,14 @@ pub struct Error {
code: c_uint,
file: *const c_char,
line: c_uint,
data: Option<Cow<'static, str>>,
data: Data,
}
#[derive(Clone)]
enum Data {
None,
CString(CString),
String(String),
}
unsafe impl Sync for Error {}
@ -148,11 +156,9 @@ impl Error {
// 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
let data = if flags & ffi::ERR_FLAG_STRING != 0 {
Some(Cow::Owned(
CStr::from_ptr(data.cast()).to_string_lossy().into_owned(),
))
Data::CString(CStr::from_ptr(data.cast()).to_owned())
} else {
None
Data::None
};
Some(Error {
code,
@ -176,22 +182,8 @@ impl Error {
self.file,
self.line,
);
let ptr = match self.data {
Some(Cow::Borrowed(data)) => Some(data.as_ptr() as *mut c_char),
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);
if let Some(cstr) = self.data_cstr() {
ffi::ERR_set_error_data(cstr.as_ptr().cast_mut(), ffi::ERR_FLAG_STRING);
}
}
}
@ -297,15 +289,29 @@ impl Error {
/// Returns additional data describing the error.
#[must_use]
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 {
code: ffi::ERR_PACK(ffi::ERR_LIB_NONE.0 as _, 0, 0) as _,
file: BORING_INTERNAL.as_ptr(),
line: 0,
data: Some(msg.into()),
data: msg,
}
}