Skip to content

Commit ed8e355

Browse files
cbarberdginev
authored andcommitted
fix: switch to manual memory management with transmute to avoid leaks
1 parent 03d02c9 commit ed8e355

3 files changed

Lines changed: 41 additions & 35 deletions

File tree

src/schemas/common.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,15 @@ use crate::bindings;
55

66
use crate::error::StructuredError;
77

8-
use std::cell::RefCell;
98
use std::ffi::c_void;
10-
use std::rc::Weak;
119

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

1716
let error = StructuredError::from_raw(error);
1817

19-
if let Some(errors) = errlog.upgrade() {
20-
errors.borrow_mut().push(error);
21-
} else {
22-
panic!("Underlying error log should not have outlived callback registration");
23-
}
24-
25-
Box::leak(errlog);
18+
errlog.push(error);
2619
}

src/schemas/parser.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@ use crate::bindings;
77
use crate::error::StructuredError;
88
use crate::tree::document::Document;
99

10-
use std::cell::RefCell;
1110
use std::ffi::CString;
1211
use std::os::raw::c_char;
13-
use std::rc::Rc;
1412

1513
/// Wrapper on xmlSchemaParserCtxt
1614
pub struct SchemaParserContext {
1715
inner: *mut bindings::_xmlSchemaParserCtxt,
18-
errlog: Rc<RefCell<Vec<StructuredError>>>,
16+
errlog: *mut Vec<StructuredError>,
1917
}
2018

2119
impl SchemaParserContext {
@@ -61,7 +59,9 @@ impl SchemaParserContext {
6159

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

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

7878
unsafe {
79+
let reference: *mut Vec<StructuredError> = std::mem::transmute(errors);
7980
bindings::xmlSchemaSetParserStructuredErrors(
8081
parser,
8182
Some(common::structured_error_handler),
82-
Box::into_raw(Box::new(Rc::downgrade(&errors))) as *mut _,
83+
reference as *mut _,
8384
);
84-
}
8585

86-
Self {
87-
inner: parser,
88-
errlog: errors,
86+
Self {
87+
inner: parser,
88+
errlog: reference,
89+
}
8990
}
9091
}
9192
}
9293

9394
impl Drop for SchemaParserContext {
9495
fn drop(&mut self) {
95-
unsafe { bindings::xmlSchemaFreeParserCtxt(self.inner) }
96+
unsafe {
97+
bindings::xmlSchemaFreeParserCtxt(self.inner);
98+
if !self.errlog.is_null() {
99+
let errors: Box<Vec<StructuredError>> = std::mem::transmute(self.errlog);
100+
drop(errors)
101+
}
102+
}
96103
}
97104
}

src/schemas/validation.rs

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,12 @@ use crate::tree::node::Node;
1313

1414
use crate::error::StructuredError;
1515

16-
use std::cell::RefCell;
1716
use std::ffi::CString;
18-
use std::rc::Rc;
1917

2018
/// Wrapper on xmlSchemaValidCtxt
2119
pub struct SchemaValidationContext {
2220
ctxt: *mut bindings::_xmlSchemaValidCtxt,
23-
errlog: Rc<RefCell<Vec<StructuredError>>>,
24-
21+
errlog: *mut Vec<StructuredError>,
2522
_schema: Schema,
2623
}
2724

@@ -83,7 +80,9 @@ impl SchemaValidationContext {
8380

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

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

10099
unsafe {
100+
let reference: *mut Vec<StructuredError> = std::mem::transmute(errors);
101101
bindings::xmlSchemaSetValidStructuredErrors(
102102
ctx,
103103
Some(common::structured_error_handler),
104-
Box::into_raw(Box::new(Rc::downgrade(&errors))) as *mut _,
104+
reference as *mut _,
105+
// Box::into_raw(Box::new(Rc::downgrade(&errors))) as *mut _,
105106
);
106-
}
107-
108-
Self {
109-
ctxt: ctx,
110-
errlog: errors,
111-
_schema: schema,
107+
Self {
108+
ctxt: ctx,
109+
errlog: reference,
110+
_schema: schema,
111+
}
112112
}
113113
}
114114
}
115115

116116
impl Drop for SchemaValidationContext {
117117
fn drop(&mut self) {
118-
unsafe { bindings::xmlSchemaFreeValidCtxt(self.ctxt) }
118+
unsafe {
119+
bindings::xmlSchemaFreeValidCtxt(self.ctxt);
120+
if !self.errlog.is_null() {
121+
let errors: Box<Vec<StructuredError>> = std::mem::transmute(self.errlog);
122+
drop(errors)
123+
}
124+
}
119125
}
120126
}

0 commit comments

Comments
 (0)