[librsvg] (#385): Don't crash if there is no rsvg_handle_write() before close()



commit 936430cc5ebe69a815fd5de072b3fbd46976ff97
Author: Federico Mena Quintero <federico gnome org>
Date:   Tue Nov 27 16:25:33 2018 -0600

    (#385): Don't crash if there is no rsvg_handle_write() before close()
    
    rsvg_handle_close() was not checking for all the handle's states in which
    it can be called.
    
    Fixes https://gitlab.gnome.org/GNOME/librsvg/issues/385

 librsvg/rsvg-handle.c | 29 +++++++++++++++++++++++------
 tests/api.c           | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+), 6 deletions(-)
---
diff --git a/librsvg/rsvg-handle.c b/librsvg/rsvg-handle.c
index b85ef14f..a0d582c9 100644
--- a/librsvg/rsvg-handle.c
+++ b/librsvg/rsvg-handle.c
@@ -728,21 +728,38 @@ rsvg_handle_close (RsvgHandle *handle, GError **error)
 {
     RsvgHandlePrivate *priv;
     gboolean read_successfully;
-    gboolean result;
+    gboolean result = FALSE;
 
     g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
     rsvg_return_val_if_fail (handle, FALSE, error);
 
     priv = handle->priv;
 
-    if (priv->hstate == RSVG_HANDLE_STATE_CLOSED_OK
-        || priv->hstate == RSVG_HANDLE_STATE_CLOSED_ERROR) {
+    switch (priv->hstate) {
+    case RSVG_HANDLE_STATE_START:
+        g_set_error (error, RSVG_ERROR, RSVG_ERROR_FAILED, _("no data passed to parser"));
+        priv->hstate = RSVG_HANDLE_STATE_CLOSED_ERROR;
+        result = FALSE;
+        break;
+
+    case RSVG_HANDLE_STATE_LOADING:
+        g_assert (priv->load != NULL);
+        read_successfully = rsvg_load_close (priv->load, error);
+        result = finish_load (handle, read_successfully, error);
+        break;
+
+    case RSVG_HANDLE_STATE_CLOSED_OK:
+    case RSVG_HANDLE_STATE_CLOSED_ERROR:
         /* closing is idempotent */
-        return TRUE;
+        result = TRUE;
+        break;
+
+    default:
+        g_assert_not_reached ();
     }
 
-    read_successfully = rsvg_load_close (priv->load, error);
-    result = finish_load (handle, read_successfully, error);
+    g_assert (priv->hstate == RSVG_HANDLE_STATE_CLOSED_OK
+              || priv->hstate == RSVG_HANDLE_STATE_CLOSED_ERROR);
 
     return result;
 }
diff --git a/tests/api.c b/tests/api.c
index 75d3883c..587f06d5 100644
--- a/tests/api.c
+++ b/tests/api.c
@@ -616,6 +616,38 @@ render_cairo_sub (void)
     cairo_destroy (cr);
 }
 
+/* https://gitlab.gnome.org/GNOME/librsvg/issues/385 */
+static void
+no_write_before_close (void)
+{
+    RsvgHandle *handle = rsvg_handle_new();
+    GError *error = NULL;
+
+    g_assert (rsvg_handle_close (handle, &error) == FALSE);
+    g_assert_error (error, RSVG_ERROR, RSVG_ERROR_FAILED);
+    g_error_free (error);
+
+    g_object_unref (handle);
+}
+
+static void
+empty_write_close (void)
+{
+    RsvgHandle *handle = rsvg_handle_new();
+    GError *error = NULL;
+    guchar buf = 0;
+
+    g_assert (rsvg_handle_write (handle, &buf, 0, &error) == TRUE);
+    g_assert_no_error (error);
+
+    g_assert (rsvg_handle_close (handle, &error) == FALSE);
+    g_assert_error (error, RSVG_ERROR, RSVG_ERROR_FAILED);
+
+    g_error_free (error);
+
+    g_object_unref (handle);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -647,6 +679,8 @@ main (int argc, char **argv)
     g_test_add_func ("/api/detects_cairo_context_in_error", detects_cairo_context_in_error);
     g_test_add_func ("/api/can_draw_to_non_image_surface", can_draw_to_non_image_surface);
     g_test_add_func ("/api/render_cairo_sub", render_cairo_sub);
+    g_test_add_func ("/api/no_write_before_close", no_write_before_close);
+    g_test_add_func ("/api/empty_write_close", empty_write_close);
 
     return g_test_run ();
 }


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