Don't leak exceptions

This commit is contained in:
Eelco Dolstra 2019-12-13 19:05:09 +01:00
parent e6bd88878e
commit b4edc3ca61
3 changed files with 48 additions and 9 deletions

View file

@ -76,7 +76,7 @@ impl From<Error> for CppException {
fn from(err: Error) -> Self { fn from(err: Error) -> Self {
match err { match err {
Error::Foreign(ex) => ex, Error::Foreign(ex) => ex,
_ => unsafe { make_error(&err.to_string()) }, _ => CppException::new(&err.to_string()),
} }
} }
} }
@ -85,7 +85,23 @@ impl From<Error> for CppException {
#[derive(Debug)] #[derive(Debug)]
pub struct CppException(*const libc::c_void); // == std::exception_ptr* pub struct CppException(*const libc::c_void); // == std::exception_ptr*
impl CppException {
fn new(s: &str) -> Self {
Self(unsafe { make_error(s) })
}
}
impl Drop for CppException {
fn drop(&mut self) {
unsafe {
destroy_error(self.0);
}
}
}
extern "C" { extern "C" {
#[allow(improper_ctypes)] // YOLO #[allow(improper_ctypes)] // YOLO
fn make_error(s: &str) -> CppException; fn make_error(s: &str) -> *const libc::c_void;
fn destroy_error(exc: *const libc::c_void);
} }

View file

@ -3,10 +3,14 @@
extern "C" std::exception_ptr * make_error(rust::StringSlice s) extern "C" std::exception_ptr * make_error(rust::StringSlice s)
{ {
// FIXME: leak
return new std::exception_ptr(std::make_exception_ptr(nix::Error(std::string(s.ptr, s.size)))); return new std::exception_ptr(std::make_exception_ptr(nix::Error(std::string(s.ptr, s.size))));
} }
extern "C" void destroy_error(std::exception_ptr * ex)
{
free(ex);
}
namespace rust { namespace rust {
std::ostream & operator << (std::ostream & str, const String & s) std::ostream & operator << (std::ostream & str, const String & s)

View file

@ -152,28 +152,47 @@ struct Source
template<typename T> template<typename T>
struct Result struct Result
{ {
unsigned int tag; enum { Ok = 0, Err = 1, Uninit = 2 } tag;
union { union {
T data; T data;
std::exception_ptr * exc; std::exception_ptr * exc;
}; };
Result() : tag(Uninit) { }; // FIXME: remove
Result(const Result &) = delete;
Result(Result && other)
: tag(other.tag)
{
other.tag = Uninit;
if (tag == Ok)
data = std::move(other.data);
else if (tag == Err)
exc = other.exc;
}
~Result() ~Result()
{ {
if (tag == 0) if (tag == Ok)
data.~T(); data.~T();
else if (tag == 1) else if (tag == Err)
// FIXME: don't leak exc free(exc);
else if (tag == Uninit)
; ;
else
abort();
} }
/* Rethrow the wrapped exception or return the wrapped value. */ /* Rethrow the wrapped exception or return the wrapped value. */
T unwrap() T unwrap()
{ {
if (tag == 0) if (tag == Ok) {
tag = Uninit;
return std::move(data); return std::move(data);
else if (tag == 1) }
else if (tag == Err)
std::rethrow_exception(*exc); std::rethrow_exception(*exc);
else else
abort(); abort();