[librsvg/librsvg-2.42: 5/8] NodeUse: fix infinite loops due to recursive references of "use" elements



commit 947dfc038cc93130af533ac305f8cfb7ff7320a1
Author: Federico Mena Quintero <federico gnome org>
Date:   Tue Feb 25 11:18:23 2020 -0600

    NodeUse: fix infinite loops due to recursive references of "use" elements

 rsvg_internals/src/drawing_ctx.rs                  |  23 ++--
 rsvg_internals/src/structure.rs                    |  21 ++--
 tests/errors.c                                     |  28 ++++-
 tests/fixtures/errors/308-doubly-recursive-use.svg |  13 +++
 tests/fixtures/errors/308-recursive-use.svg        |   9 ++
 tests/fixtures/errors/308-use-self-ref.svg         |   7 ++
 .../fixtures/errors/515-pattern-billion-laughs.svg | 130 +++++++++++++++++++++
 7 files changed, 213 insertions(+), 18 deletions(-)
---
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index d74547c6..631b073c 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -32,6 +32,11 @@ extern "C" {
 
     fn rsvg_drawing_ctx_pop_view_box(draw_ctx: *const RsvgDrawingCtx);
 
+    fn rsvg_drawing_ctx_acquire_node_ref(
+        draw_ctx: *const RsvgDrawingCtx,
+        node: *const RsvgNode,
+    ) -> *mut RsvgNode;
+
     fn rsvg_drawing_ctx_acquire_node(
         draw_ctx: *const RsvgDrawingCtx,
         url: *const libc::c_char,
@@ -45,8 +50,6 @@ extern "C" {
 
     fn rsvg_drawing_ctx_release_node(draw_ctx: *const RsvgDrawingCtx, node: *mut RsvgNode);
 
-    fn rsvg_drawing_ctx_increase_num_elements_acquired(draw_ctx: *const RsvgDrawingCtx);
-
     fn rsvg_drawing_ctx_get_current_state_affine(draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix;
 
     fn rsvg_drawing_ctx_set_current_state_affine(
@@ -149,6 +152,16 @@ pub fn pop_view_box(draw_ctx: *const RsvgDrawingCtx) {
     }
 }
 
+pub fn acquire_node_ref(draw_ctx: *const RsvgDrawingCtx, node: *const RsvgNode) -> Option<AcquiredNode> {
+    let raw_node = unsafe { rsvg_drawing_ctx_acquire_node_ref(draw_ctx, node) };
+
+    if raw_node.is_null() {
+        None
+    } else {
+        Some(AcquiredNode(draw_ctx, raw_node))
+    }
+}
+
 pub fn get_acquired_node(draw_ctx: *const RsvgDrawingCtx, url: &str) -> Option<AcquiredNode> {
     let raw_node = unsafe { rsvg_drawing_ctx_acquire_node(draw_ctx, str::to_glib_none(url).0) };
 
@@ -290,12 +303,6 @@ pub fn state_pop(draw_ctx: *const RsvgDrawingCtx) {
     }
 }
 
-pub fn increase_num_elements_acquired(draw_ctx: *const RsvgDrawingCtx) {
-    unsafe {
-        rsvg_drawing_ctx_increase_num_elements_acquired(draw_ctx);
-    }
-}
-
 pub struct AcquiredNode(*const RsvgDrawingCtx, *mut RsvgNode);
 
 impl Drop for AcquiredNode {
diff --git a/rsvg_internals/src/structure.rs b/rsvg_internals/src/structure.rs
index a993fc35..e4234aee 100644
--- a/rsvg_internals/src/structure.rs
+++ b/rsvg_internals/src/structure.rs
@@ -278,6 +278,20 @@ impl NodeTrait for NodeUse {
             return;
         }
 
+        // <use> is an element that is used directly, unlike
+        // <pattern>, which is used through a fill="url(#...)"
+        // reference.  However, <use> will always reference another
+        // element, potentially itself or an ancestor of itself (or
+        // another <use> which references the first one, etc.).  So,
+        // we acquire the <use> element itself so that circular
+        // references can be caught.
+        let self_box = box_node(node.clone());
+        let self_acquired = drawing_ctx::acquire_node_ref(draw_ctx, self_box);
+        rsvg_node_unref(self_box);
+        if self_acquired.is_none() {
+            return;
+        }
+
         let child = if let Some(acquired) =
             drawing_ctx::get_acquired_node(draw_ctx, link.as_ref().unwrap())
         {
@@ -286,13 +300,6 @@ impl NodeTrait for NodeUse {
             return;
         };
 
-        if Node::is_ancestor(node.clone(), child.clone()) {
-            // or, if we're <use>'ing ourselves
-            return;
-        }
-
-        drawing_ctx::increase_num_elements_acquired(draw_ctx);
-
         let nx = self.x.get().normalize(draw_ctx);
         let ny = self.y.get().normalize(draw_ctx);
 
diff --git a/tests/errors.c b/tests/errors.c
index f370d60e..fba3f5fc 100644
--- a/tests/errors.c
+++ b/tests/errors.c
@@ -23,9 +23,10 @@ get_test_filename (const char *basename) {
                              NULL);
 }
 static void
-test_instancing_limit (void)
+test_instancing_limit (gconstpointer data)
 {
-    char *filename = get_test_filename ("323-nested-use.svg");
+    const char *basename = data;
+    char *filename = get_test_filename (basename);
     RsvgHandle *handle;
     GError *error = NULL;
     cairo_surface_t *surf;
@@ -49,7 +50,28 @@ main (int argc, char **argv)
 {
     g_test_init (&argc, &argv, NULL);
 
-    g_test_add_func ("/errors/instancing_limit", test_instancing_limit);
+    g_test_add_data_func_full ("/errors/instancing_limit/323-nested-use.svg",
+                               "323-nested-use.svg",
+                               test_instancing_limit,
+                               NULL);
+
+    g_test_add_data_func_full ("/errors/instancing_limit/515-pattern-billion-laughs.svg",
+                               "515-pattern-billion-laughs.svg",
+                               test_instancing_limit,
+                               NULL);
+
+    g_test_add_data_func_full ("/errors/instancing_limit/308-use-self-ref.svg",
+                               "308-use-self-ref.svg",
+                               test_instancing_limit,
+                               NULL);
+    g_test_add_data_func_full ("/errors/instancing_limit/308-recursive-use.svg",
+                               "308-recursive-use.svg",
+                               test_instancing_limit,
+                               NULL);
+    g_test_add_data_func_full ("/errors/instancing_limit/308-doubly-recursive-use.svg",
+                               "308-doubly-recursive-use.svg",
+                               test_instancing_limit,
+                               NULL);
 
     return g_test_run ();
 }
diff --git a/tests/fixtures/errors/308-doubly-recursive-use.svg 
b/tests/fixtures/errors/308-doubly-recursive-use.svg
new file mode 100644
index 00000000..9b248a6f
--- /dev/null
+++ b/tests/fixtures/errors/308-doubly-recursive-use.svg
@@ -0,0 +1,13 @@
+<svg>
+  <defs>
+    <g id="one">
+      <use xlink:href="#two"/>
+    </g>
+
+    <g id="two">
+      <use xlink:href="#one"/>
+    </g>
+  </defs>
+
+  <use xlink:href="#one"/>
+</svg>
diff --git a/tests/fixtures/errors/308-recursive-use.svg b/tests/fixtures/errors/308-recursive-use.svg
new file mode 100644
index 00000000..f5d00bf2
--- /dev/null
+++ b/tests/fixtures/errors/308-recursive-use.svg
@@ -0,0 +1,9 @@
+<svg>
+  <defs>
+    <g id="one">
+      <use xlink:href="#one"/>
+    </g>
+  </defs>
+
+  <use xlink:href="#one"/>
+</svg>
diff --git a/tests/fixtures/errors/308-use-self-ref.svg b/tests/fixtures/errors/308-use-self-ref.svg
new file mode 100644
index 00000000..dbf14c54
--- /dev/null
+++ b/tests/fixtures/errors/308-use-self-ref.svg
@@ -0,0 +1,7 @@
+<svg>
+  <defs>
+    <use id="one" xlink:href="#one"/>
+  </defs>
+
+  <use xlink:href="#one"/>
+</svg>
diff --git a/tests/fixtures/errors/515-pattern-billion-laughs.svg 
b/tests/fixtures/errors/515-pattern-billion-laughs.svg
new file mode 100644
index 00000000..1cb6cbe8
--- /dev/null
+++ b/tests/fixtures/errors/515-pattern-billion-laughs.svg
@@ -0,0 +1,130 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
+  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd";>
+<svg width="40cm" height="20cm" viewBox="0 0 800 400" version="1.1"
+     xmlns="http://www.w3.org/2000/svg";>
+  <defs>
+    <pattern id="z" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" 
patternTransform="scale(10,10)">
+      <rect x="0" y="0" width="20" height="20" fill="url(#i)" stroke="yellow"/>
+    </pattern>
+       
+       <pattern id="i" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" 
patternTransform="scale(0.5,0.5)">
+      <rect x="0" y="0" width="20" height="20" fill="url(#h)" stroke="green" />
+         <rect x="1" y="1" width="20" height="20" fill="url(#h)" stroke="brown" />
+         <rect x="2" y="2" width="20" height="20" fill="url(#h)" stroke="pink" />
+         <rect x="3" y="3" width="20" height="20" fill="url(#h)" stroke="grey" />
+         <rect x="4" y="3" width="20" height="20" fill="url(#h)" stroke="cyan" />
+         <rect x="5" y="3" width="20" height="20" fill="url(#h)" stroke="green" />
+         <rect x="6" y="3" width="20" height="20" fill="url(#h)" stroke="brown" />
+         <rect x="7" y="3" width="20" height="20" fill="url(#h)" stroke="pink" />
+         <rect x="8" y="3" width="20" height="20" fill="url(#h)" stroke="grey" />
+         <rect x="9" y="3" width="20" height="20" fill="url(#h)" stroke="cyan" />
+    </pattern>
+       
+       <pattern id="h" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" 
patternTransform="scale(0.5,0.5)">
+      <rect x="0" y="0" width="20" height="20" fill="url(#g)" stroke="green" />
+         <rect x="1" y="1" width="20" height="20" fill="url(#g)" stroke="brown" />
+         <rect x="2" y="2" width="20" height="20" fill="url(#g)" stroke="pink" />
+         <rect x="3" y="3" width="20" height="20" fill="url(#g)" stroke="grey" />
+         <rect x="4" y="3" width="20" height="20" fill="url(#g)" stroke="cyan" />
+         <rect x="5" y="3" width="20" height="20" fill="url(#g)" stroke="green" />
+         <rect x="6" y="3" width="20" height="20" fill="url(#g)" stroke="brown" />
+         <rect x="7" y="3" width="20" height="20" fill="url(#g)" stroke="pink" />
+         <rect x="8" y="3" width="20" height="20" fill="url(#g)" stroke="grey" />
+         <rect x="9" y="3" width="20" height="20" fill="url(#g)" stroke="cyan" />
+    </pattern>
+       
+       <pattern id="g" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" 
patternTransform="scale(0.5,0.5)">
+      <rect x="0" y="0" width="20" height="20" fill="url(#f)" stroke="green" />
+         <rect x="1" y="1" width="20" height="20" fill="url(#f)" stroke="brown" />
+         <rect x="2" y="2" width="20" height="20" fill="url(#f)" stroke="pink" />
+         <rect x="3" y="3" width="20" height="20" fill="url(#f)" stroke="grey" />
+         <rect x="4" y="3" width="20" height="20" fill="url(#f)" stroke="cyan" />
+         <rect x="5" y="3" width="20" height="20" fill="url(#f)" stroke="green" />
+         <rect x="6" y="3" width="20" height="20" fill="url(#f)" stroke="brown" />
+         <rect x="7" y="3" width="20" height="20" fill="url(#f)" stroke="pink" />
+         <rect x="8" y="3" width="20" height="20" fill="url(#f)" stroke="grey" />
+         <rect x="9" y="3" width="20" height="20" fill="url(#f)" stroke="cyan" />
+    </pattern>
+       
+       <pattern id="f" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" 
patternTransform="scale(0.5,0.5)">
+      <rect x="0" y="0" width="20" height="20" fill="url(#e)" stroke="green" />
+         <rect x="1" y="1" width="20" height="20" fill="url(#e)" stroke="brown" />
+         <rect x="2" y="2" width="20" height="20" fill="url(#e)" stroke="pink" />
+         <rect x="3" y="3" width="20" height="20" fill="url(#e)" stroke="grey" />
+         <rect x="4" y="3" width="20" height="20" fill="url(#e)" stroke="cyan" />
+         <rect x="5" y="3" width="20" height="20" fill="url(#e)" stroke="green" />
+         <rect x="6" y="3" width="20" height="20" fill="url(#e)" stroke="brown" />
+         <rect x="7" y="3" width="20" height="20" fill="url(#e)" stroke="pink" />
+         <rect x="8" y="3" width="20" height="20" fill="url(#e)" stroke="grey" />
+         <rect x="9" y="3" width="20" height="20" fill="url(#e)" stroke="cyan" />
+    </pattern>
+       
+       <pattern id="e" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" 
patternTransform="scale(0.5,0.5)">
+      <rect x="0" y="0" width="20" height="20" fill="url(#d)" stroke="green" />
+         <rect x="1" y="1" width="20" height="20" fill="url(#d)" stroke="brown" />
+         <rect x="2" y="2" width="20" height="20" fill="url(#d)" stroke="pink" />
+         <rect x="3" y="3" width="20" height="20" fill="url(#d)" stroke="grey" />
+         <rect x="4" y="3" width="20" height="20" fill="url(#d)" stroke="cyan" />
+         <rect x="5" y="3" width="20" height="20" fill="url(#d)" stroke="green" />
+         <rect x="6" y="3" width="20" height="20" fill="url(#d)" stroke="brown" />
+         <rect x="7" y="3" width="20" height="20" fill="url(#d)" stroke="pink" />
+         <rect x="8" y="3" width="20" height="20" fill="url(#d)" stroke="grey" />
+         <rect x="9" y="3" width="20" height="20" fill="url(#d)" stroke="cyan" />
+    </pattern>
+       
+    <pattern id="d" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" 
patternTransform="scale(0.5,0.5)">
+      <rect x="0" y="0" width="20" height="20" fill="url(#c)" stroke="green" />
+         <rect x="1" y="1" width="20" height="20" fill="url(#c)" stroke="brown" />
+         <rect x="2" y="2" width="20" height="20" fill="url(#c)" stroke="pink" />
+         <rect x="3" y="3" width="20" height="20" fill="url(#c)" stroke="grey" />
+         <rect x="4" y="3" width="20" height="20" fill="url(#c)" stroke="cyan" />
+         <rect x="5" y="3" width="20" height="20" fill="url(#c)" stroke="green" />
+         <rect x="6" y="3" width="20" height="20" fill="url(#c)" stroke="brown" />
+         <rect x="7" y="3" width="20" height="20" fill="url(#c)" stroke="pink" />
+         <rect x="8" y="3" width="20" height="20" fill="url(#c)" stroke="grey" />
+         <rect x="9" y="3" width="20" height="20" fill="url(#c)" stroke="cyan" />
+    </pattern>
+    <pattern id="c" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" 
patternTransform="scale(0.5,0.5)">
+      <rect x="0" y="0" width="20" height="20" fill="url(#b)" stroke="green" />
+         <rect x="1" y="1" width="20" height="20" fill="url(#b)" stroke="brown" />
+         <rect x="2" y="2" width="20" height="20" fill="url(#b)" stroke="pink" />
+         <rect x="3" y="3" width="20" height="20" fill="url(#b)" stroke="grey" />
+         <rect x="4" y="3" width="20" height="20" fill="url(#b)" stroke="cyan" />
+         <rect x="5" y="3" width="20" height="20" fill="url(#b)" stroke="green" />
+         <rect x="6" y="3" width="20" height="20" fill="url(#b)" stroke="brown" />
+         <rect x="7" y="3" width="20" height="20" fill="url(#b)" stroke="pink" />
+         <rect x="8" y="3" width="20" height="20" fill="url(#b)" stroke="grey" />
+         <rect x="9" y="3" width="20" height="20" fill="url(#b)" stroke="cyan" />
+    </pattern>
+    <pattern id="b" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" 
patternTransform="scale(0.5,0.5)">
+         <rect x="0" y="0" width="20" height="20" fill="url(#a)" stroke="green" />
+         <rect x="1" y="1" width="20" height="20" fill="url(#a)" stroke="brown" />
+         <rect x="2" y="2" width="20" height="20" fill="url(#a)" stroke="pink" />
+         <rect x="3" y="3" width="20" height="20" fill="url(#a)" stroke="grey" />
+         <rect x="4" y="3" width="20" height="20" fill="url(#a)" stroke="cyan" />
+         <rect x="5" y="3" width="20" height="20" fill="url(#a)" stroke="green" />
+         <rect x="6" y="3" width="20" height="20" fill="url(#a)" stroke="brown" />
+         <rect x="7" y="3" width="20" height="20" fill="url(#a)" stroke="pink" />
+         <rect x="8" y="3" width="20" height="20" fill="url(#a)" stroke="grey" />
+         <rect x="9" y="3" width="20" height="20" fill="url(#a)" stroke="cyan" />
+         
+    </pattern>
+    <pattern id="a" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" 
patternTransform="scale(0.5,0.5)">
+      <rect x="0" y="0" width="20" height="20" fill="none" stroke="green" />
+         <rect x="1" y="1" width="20" height="20" fill="none" stroke="brown" />
+         <rect x="2" y="2" width="20" height="20" fill="none" stroke="pink" />
+         <rect x="3" y="3" width="20" height="20" fill="none" stroke="grey" />
+         <rect x="4" y="3" width="20" height="20" fill="none" stroke="cyan" />
+         <rect x="5" y="3" width="20" height="20" fill="none" stroke="green" />
+         <rect x="6" y="3" width="20" height="20" fill="none" stroke="brown" />
+         <rect x="7" y="3" width="20" height="20" fill="none" stroke="pink" />
+         <rect x="8" y="3" width="20" height="20" fill="none" stroke="grey" />
+         <rect x="9" y="3" width="20" height="20" fill="none" stroke="cyan" />
+    </pattern>
+  </defs>
+
+  <ellipse fill="url(#z)" stroke="black" stroke-width="5"  
+           cx="400" cy="200" rx="350" ry="150" />
+                  
+</svg>
\ No newline at end of file


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]