Skip to content

Commit e32687a

Browse files
Merge branch 'entities-leak-1087' into 'main'
(#1087): Don't leak XML entities when the XML document fails to parse Closes #1087 See merge request GNOME/librsvg!985
2 parents 1b6e319 + ae7c6ae commit e32687a

File tree

2 files changed

+35
-25
lines changed

2 files changed

+35
-25
lines changed

rsvg/src/css.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ pub struct RuleParser {
186186
}
187187

188188
/// Errors from the CSS parsing process
189+
#[allow(dead_code)] // looks like we are not actually using this yet?
189190
#[derive(Debug)]
190191
pub enum ParseErrorKind<'i> {
191192
Selector(selectors::parser::SelectorParseErrorKind<'i>),

rsvg/src/xml/mod.rs

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ mod attributes;
3737
mod xml2;
3838
mod xml2_load;
3939

40+
use xml2::xmlEntityPtr;
41+
4042
pub use attributes::Attributes;
4143

4244
#[derive(Clone)]
@@ -71,14 +73,29 @@ struct XIncludeContext {
7173
need_fallback: bool,
7274
}
7375

74-
// This is to hold an xmlEntityPtr from libxml2; we just hold an opaque pointer
75-
// that is freed in impl Drop for XmlState
76-
type XmlEntityPtr = *mut libc::c_void;
77-
7876
extern "C" {
7977
// The original function takes an xmlNodePtr, but that is compatible
8078
// with xmlEntityPtr for the purposes of this function.
81-
fn xmlFreeNode(node: XmlEntityPtr);
79+
fn xmlFreeNode(node: xmlEntityPtr);
80+
}
81+
82+
/// This is to hold an xmlEntityPtr from libxml2; we just hold an opaque pointer
83+
/// that is freed in impl Drop.
84+
struct XmlEntity(xmlEntityPtr);
85+
86+
impl Drop for XmlEntity {
87+
fn drop(&mut self) {
88+
unsafe {
89+
// Even though we are freeing an xmlEntityPtr, historically the code has always
90+
// used xmlFreeNode() because that function actually does allow freeing entities.
91+
//
92+
// See https://gitlab.gnome.org/GNOME/libxml2/-/issues/731
93+
// for a possible memory leak on older versions of libxml2 when using
94+
// xmlFreeNode() instead of xmlFreeEntity() - the latter just became public
95+
// in librsvg-2.12.0.
96+
xmlFreeNode(self.0);
97+
}
98+
}
8299
}
83100

84101
// Creates an ExpandedName from the XInclude namespace and a local_name
@@ -117,7 +134,7 @@ struct XmlStateInner {
117134
//
118135
// (The structs cannot impl Drop because build_document()
119136
// destructures and consumes them at the same time.)
120-
entities: HashMap<String, XmlEntityPtr>,
137+
entities: HashMap<String, XmlEntity>,
121138
}
122139

123140
pub struct XmlState {
@@ -337,20 +354,20 @@ impl XmlState {
337354
.push(Context::FatalError(e));
338355
}
339356

340-
pub fn entity_lookup(&self, entity_name: &str) -> Option<XmlEntityPtr> {
341-
self.inner.borrow().entities.get(entity_name).copied()
357+
pub fn entity_lookup(&self, entity_name: &str) -> Option<xmlEntityPtr> {
358+
self.inner
359+
.borrow()
360+
.entities
361+
.get(entity_name)
362+
.map(|entity| entity.0)
342363
}
343364

344-
pub fn entity_insert(&self, entity_name: &str, entity: XmlEntityPtr) {
365+
pub fn entity_insert(&self, entity_name: &str, entity: xmlEntityPtr) {
345366
let mut inner = self.inner.borrow_mut();
346367

347-
let old_value = inner.entities.insert(entity_name.to_string(), entity);
348-
349-
if let Some(v) = old_value {
350-
unsafe {
351-
xmlFreeNode(v);
352-
}
353-
}
368+
inner
369+
.entities
370+
.insert(entity_name.to_string(), XmlEntity(entity));
354371
}
355372

356373
fn element_creation_start_element(&self, name: &QualName, attrs: Attributes) -> Context {
@@ -643,15 +660,7 @@ impl XmlState {
643660
// consume self, then consume inner, then consume document_builder by calling .build()
644661

645662
let XmlState { inner, .. } = self;
646-
let mut inner = inner.into_inner();
647-
648-
// Free the hash of XmlEntityPtr. We cannot do this in Drop because we will
649-
// consume inner by destructuring it after the for() loop.
650-
for (_key, entity) in inner.entities.drain() {
651-
unsafe {
652-
xmlFreeNode(entity);
653-
}
654-
}
663+
let inner = inner.into_inner();
655664

656665
let XmlStateInner {
657666
document_builder, ..

0 commit comments

Comments
 (0)