Don't leak exceptions
This commit is contained in:
parent
e6bd88878e
commit
b4edc3ca61
3 changed files with 48 additions and 9 deletions
|
@ -76,7 +76,7 @@ impl From<Error> for CppException {
|
|||
fn from(err: Error) -> Self {
|
||||
match err {
|
||||
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)]
|
||||
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" {
|
||||
#[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);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,14 @@
|
|||
|
||||
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))));
|
||||
}
|
||||
|
||||
extern "C" void destroy_error(std::exception_ptr * ex)
|
||||
{
|
||||
free(ex);
|
||||
}
|
||||
|
||||
namespace rust {
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const String & s)
|
||||
|
|
|
@ -152,28 +152,47 @@ struct Source
|
|||
template<typename T>
|
||||
struct Result
|
||||
{
|
||||
unsigned int tag;
|
||||
enum { Ok = 0, Err = 1, Uninit = 2 } tag;
|
||||
|
||||
union {
|
||||
T data;
|
||||
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()
|
||||
{
|
||||
if (tag == 0)
|
||||
if (tag == Ok)
|
||||
data.~T();
|
||||
else if (tag == 1)
|
||||
// FIXME: don't leak exc
|
||||
else if (tag == Err)
|
||||
free(exc);
|
||||
else if (tag == Uninit)
|
||||
;
|
||||
else
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Rethrow the wrapped exception or return the wrapped value. */
|
||||
T unwrap()
|
||||
{
|
||||
if (tag == 0)
|
||||
if (tag == Ok) {
|
||||
tag = Uninit;
|
||||
return std::move(data);
|
||||
else if (tag == 1)
|
||||
}
|
||||
else if (tag == Err)
|
||||
std::rethrow_exception(*exc);
|
||||
else
|
||||
abort();
|
||||
|
|
Loading…
Reference in a new issue