Skip to content

Commit

Permalink
fix: switch to manual memory management with transmute to avoid leaks
Browse files Browse the repository at this point in the history
  • Loading branch information
cbarber authored and dginev committed Jan 16, 2020
1 parent 03d02c9 commit ed8e355
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 35 deletions.
13 changes: 3 additions & 10 deletions src/schemas/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,15 @@ use crate::bindings;

use crate::error::StructuredError;

use std::cell::RefCell;
use std::ffi::c_void;
use std::rc::Weak;

/// Provides a callback to the C side of things to accumulate xmlErrors to be
/// handled back on the Rust side.
pub fn structured_error_handler(ctx: *mut c_void, error: bindings::xmlErrorPtr) {
let errlog = unsafe { Box::from_raw(ctx as *mut Weak<RefCell<Vec<StructuredError>>>) };
assert!(!ctx.is_null());
let errlog = unsafe { &mut *{ ctx as *mut Vec<StructuredError> } };

let error = StructuredError::from_raw(error);

if let Some(errors) = errlog.upgrade() {
errors.borrow_mut().push(error);
} else {
panic!("Underlying error log should not have outlived callback registration");
}

Box::leak(errlog);
errlog.push(error);
}
29 changes: 18 additions & 11 deletions src/schemas/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@ use crate::bindings;
use crate::error::StructuredError;
use crate::tree::document::Document;

use std::cell::RefCell;
use std::ffi::CString;
use std::os::raw::c_char;
use std::rc::Rc;

/// Wrapper on xmlSchemaParserCtxt
pub struct SchemaParserContext {
inner: *mut bindings::_xmlSchemaParserCtxt,
errlog: Rc<RefCell<Vec<StructuredError>>>,
errlog: *mut Vec<StructuredError>,
}

impl SchemaParserContext {
Expand Down Expand Up @@ -61,7 +59,9 @@ impl SchemaParserContext {

/// Drains error log from errors that might have accumulated while parsing schema
pub fn drain_errors(&mut self) -> Vec<StructuredError> {
self.errlog.borrow_mut().drain(0..).collect()
assert!(!self.errlog.is_null());
let errors = unsafe { &mut *self.errlog };
errors.drain(0..).collect()
}

/// Return a raw pointer to the underlying xmlSchemaParserCtxt structure
Expand All @@ -73,25 +73,32 @@ impl SchemaParserContext {
/// Private Interface
impl SchemaParserContext {
fn from_raw(parser: *mut bindings::_xmlSchemaParserCtxt) -> Self {
let errors = Rc::new(RefCell::new(Vec::new()));
let errors: Box<Vec<StructuredError>> = Box::new(Vec::new());

unsafe {
let reference: *mut Vec<StructuredError> = std::mem::transmute(errors);
bindings::xmlSchemaSetParserStructuredErrors(
parser,
Some(common::structured_error_handler),
Box::into_raw(Box::new(Rc::downgrade(&errors))) as *mut _,
reference as *mut _,
);
}

Self {
inner: parser,
errlog: errors,
Self {
inner: parser,
errlog: reference,
}
}
}
}

impl Drop for SchemaParserContext {
fn drop(&mut self) {
unsafe { bindings::xmlSchemaFreeParserCtxt(self.inner) }
unsafe {
bindings::xmlSchemaFreeParserCtxt(self.inner);
if !self.errlog.is_null() {
let errors: Box<Vec<StructuredError>> = std::mem::transmute(self.errlog);
drop(errors)
}
}
}
}
34 changes: 20 additions & 14 deletions src/schemas/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,12 @@ use crate::tree::node::Node;

use crate::error::StructuredError;

use std::cell::RefCell;
use std::ffi::CString;
use std::rc::Rc;

/// Wrapper on xmlSchemaValidCtxt
pub struct SchemaValidationContext {
ctxt: *mut bindings::_xmlSchemaValidCtxt,
errlog: Rc<RefCell<Vec<StructuredError>>>,

errlog: *mut Vec<StructuredError>,
_schema: Schema,
}

Expand Down Expand Up @@ -83,7 +80,9 @@ impl SchemaValidationContext {

/// Drains error log from errors that might have accumulated while validating something
pub fn drain_errors(&mut self) -> Vec<StructuredError> {
self.errlog.borrow_mut().drain(0..).collect()
assert!(!self.errlog.is_null());
let errors = unsafe { &mut *self.errlog };
errors.drain(0..).collect()
}

/// Return a raw pointer to the underlying xmlSchemaValidCtxt structure
Expand All @@ -95,26 +94,33 @@ impl SchemaValidationContext {
/// Private Interface
impl SchemaValidationContext {
fn from_raw(ctx: *mut bindings::_xmlSchemaValidCtxt, schema: Schema) -> Self {
let errors = Rc::new(RefCell::new(Vec::new()));
let errors: Box<Vec<StructuredError>> = Box::new(Vec::new());

unsafe {
let reference: *mut Vec<StructuredError> = std::mem::transmute(errors);
bindings::xmlSchemaSetValidStructuredErrors(
ctx,
Some(common::structured_error_handler),
Box::into_raw(Box::new(Rc::downgrade(&errors))) as *mut _,
reference as *mut _,
// Box::into_raw(Box::new(Rc::downgrade(&errors))) as *mut _,
);
}

Self {
ctxt: ctx,
errlog: errors,
_schema: schema,
Self {
ctxt: ctx,
errlog: reference,
_schema: schema,
}
}
}
}

impl Drop for SchemaValidationContext {
fn drop(&mut self) {
unsafe { bindings::xmlSchemaFreeValidCtxt(self.ctxt) }
unsafe {
bindings::xmlSchemaFreeValidCtxt(self.ctxt);
if !self.errlog.is_null() {
let errors: Box<Vec<StructuredError>> = std::mem::transmute(self.errlog);
drop(errors)
}
}
}
}

0 comments on commit ed8e355

Please sign in to comment.