@@ -37,6 +37,8 @@ mod attributes;
37
37
mod xml2;
38
38
mod xml2_load;
39
39
40
+ use xml2:: xmlEntityPtr;
41
+
40
42
pub use attributes:: Attributes ;
41
43
42
44
#[ derive( Clone ) ]
@@ -71,14 +73,29 @@ struct XIncludeContext {
71
73
need_fallback : bool ,
72
74
}
73
75
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
-
78
76
extern "C" {
79
77
// The original function takes an xmlNodePtr, but that is compatible
80
78
// 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
+ }
82
99
}
83
100
84
101
// Creates an ExpandedName from the XInclude namespace and a local_name
@@ -117,7 +134,7 @@ struct XmlStateInner {
117
134
//
118
135
// (The structs cannot impl Drop because build_document()
119
136
// destructures and consumes them at the same time.)
120
- entities : HashMap < String , XmlEntityPtr > ,
137
+ entities : HashMap < String , XmlEntity > ,
121
138
}
122
139
123
140
pub struct XmlState {
@@ -337,20 +354,20 @@ impl XmlState {
337
354
. push ( Context :: FatalError ( e) ) ;
338
355
}
339
356
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 )
342
363
}
343
364
344
- pub fn entity_insert ( & self , entity_name : & str , entity : XmlEntityPtr ) {
365
+ pub fn entity_insert ( & self , entity_name : & str , entity : xmlEntityPtr ) {
345
366
let mut inner = self . inner . borrow_mut ( ) ;
346
367
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) ) ;
354
371
}
355
372
356
373
fn element_creation_start_element ( & self , name : & QualName , attrs : Attributes ) -> Context {
@@ -643,15 +660,7 @@ impl XmlState {
643
660
// consume self, then consume inner, then consume document_builder by calling .build()
644
661
645
662
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 ( ) ;
655
664
656
665
let XmlStateInner {
657
666
document_builder, ..
0 commit comments