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



commit 5ac08d4f6eec4753656607ff94504110a2812e7b
Author: Federico Mena Quintero <federico gnome org>
Date:   Wed Feb 26 11:22:42 2020 -0600

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

 rsvg-structure.c | 33 ++++++++++++++++++++++++++-------
 1 file changed, 26 insertions(+), 7 deletions(-)
---
diff --git a/rsvg-structure.c b/rsvg-structure.c
index 823a91b4..d31e6d50 100644
--- a/rsvg-structure.c
+++ b/rsvg-structure.c
@@ -183,6 +183,7 @@ static void
 rsvg_node_use_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
 {
     RsvgNodeUse *use = (RsvgNodeUse *) self;
+    RsvgNode *self_acquired = NULL;
     RsvgNode *child;
     RsvgState *state;
     cairo_matrix_t affine;
@@ -194,14 +195,26 @@ rsvg_node_use_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
 
     rsvg_state_reinherit_top (ctx, self->state, dominate);
 
-    if (use->link == NULL)
-      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.
+     */
+    self_acquired = rsvg_drawing_ctx_acquire_node_ref (ctx, self);
+    if (!self_acquired) {
+        goto out;
+    }
+
+    if (use->link == NULL) {
+        goto out;
+    }
+
     child = rsvg_acquire_node (ctx, use->link);
-    if (!child)
-        return;
-    else if (rsvg_node_is_ancestor (child, self)) {     /* or, if we're <use>'ing ourself */
-        rsvg_release_node (ctx, child);
-        return;
+    if (!child) {
+        goto out;
     }
 
     state = rsvg_current_state (ctx);
@@ -254,6 +267,12 @@ rsvg_node_use_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
 
         rsvg_release_node (ctx, child);
     }
+
+out:
+
+    if (self_acquired) {
+        rsvg_release_node (ctx, self_acquired);
+    }
 }
 
 static void


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