Re: Crash in cairo_surface_get_mime_data()

Uli Schlachter <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <[email protected]>
On 04.10.2011 11:56, Chris Wilson wrote:
> On Mon, 03 Oct 2011 23:09:42 +0200, Uli Schlachter <[email protected]> wrote:
> Non-text part: multipart/mixed
>> Hi,
>>
>> attached is a test case which crashes on every cairo version since 1.10. First
>> it sets some mime data, then it removes that mime data again. The next
>> cairo_surface_get_mime_data() then dereferences a NULL pointer.
>>
>> Also attached is a patch which fixes the issue for me.
>>
>> I wonder if this really is a cairo bug or if I'm just using the API in a wrong
>> way. Could someone enlighten me?
> 
> It's a bug. Should have realised when the docs said remove, it meant hide.
>  ;-)
> 
> Yours is a nice simple fix, though I wonder if we should fix
> _cairo_user_data_array_set_data(key, NULL) to actually remove the slot.

I think that could avoid a memory allocation later on. On the other hand. The
mime-data array is reinitialized all the time and removing and re-adding mime
data to a surface doesn't really make sense....

>> Then I also wonder how this should be added to the test suite. The only thing
>> that currently calls cairo_surface_get_mime_data() is api-special-cases, but
>> this problem doesn't really fit into that test. Should this get its own test
>> case, looking something like the code below?
> 
> Sure, start a suite of tests for mime-surface-api.c As we also want to make
> sure that we do get the exact same data returned from get as for set.
> (The drawing test should cover that, but doesn't actually imply no copy
> was made etc.)

Attached are two patches. First one adds a new test case and the other is the
one-line fix I posted earlier.

If no one complains, I'll eventually push this.

Cheers,
Uli
-- 
"Do you know that books smell like nutmeg or some spice from a foreign land?"
                                                  -- Faber in Fahrenheit 451

--
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
0001-test-Add-mime-surface-api.patch (text/x-diff, 5.1 KB)
From f05d59b16f7c5ce93a1cdb6dcb46f35d5ec9f865 Mon Sep 17 00:00:00 2001
From: Uli Schlachter <[email protected]>
Date: Tue, 4 Oct 2011 14:58:41 +0200
Subject: [PATCH 1/2] test: Add mime-surface-api

This test checks if setting and unsetting mime data works correctly. E.g. this
verifies that we get the same pointer back which we passed in (=no copy made).

This test currently crashes in its last call to cairo_surface_get_mime_data().

Signed-off-by: Uli Schlachter <[email protected]>
---
 test/Makefile.sources   |    1 +
 test/mime-surface-api.c |  133 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 134 insertions(+), 0 deletions(-)
 create mode 100644 test/mime-surface-api.c

diff --git a/test/Makefile.sources b/test/Makefile.sources
index afb5c97..14d416c 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -202,6 +202,7 @@ test_sources = \
 	mesh-pattern-transformed.c		        \
 	mime-data.c					\
 	mime-surface.c					\
+	mime-surface-api.c				\
 	miter-precision.c				\
 	move-to-show-surface.c				\
 	new-sub-path.c					\
diff --git a/test/mime-surface-api.c b/test/mime-surface-api.c
new file mode 100644
index 0000000..b5cd219
--- /dev/null
+++ b/test/mime-surface-api.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright © 2011 Uli Schlachter
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Uli Schlachter <[email protected]>
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_status_t
+check_mime_data (cairo_test_context_t *ctx, cairo_surface_t *surface,
+		 const char *mimetype, const unsigned char *data,
+		 unsigned long length)
+{
+    const unsigned char *data_ret;
+    unsigned long length_ret;
+
+    cairo_surface_get_mime_data (surface, mimetype, &data_ret, &length_ret);
+    if (data_ret != data || length_ret != length) {
+	cairo_test_log (ctx,
+			"Surface has mime data %p with length %lu, "
+			"but expected %p with length %lu\n",
+			data_ret, length_ret, data, length);
+       return CAIRO_TEST_ERROR;
+    }
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+static void
+mime_data_destroy_func (void *data)
+{
+    cairo_bool_t *called = data;
+    *called = TRUE;
+}
+
+static cairo_test_status_t
+preamble (cairo_test_context_t *ctx)
+{
+    const char *mimetype = "text/x-uri";
+    const char *data = "http://www.cairographics.org";
+    cairo_bool_t destroy_called = FALSE;
+    cairo_surface_t *surface;
+    cairo_status_t status;
+    cairo_test_status_t test_status = CAIRO_TEST_SUCCESS;
+
+    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
+    if (cairo_surface_status (surface)) {
+	cairo_test_log (ctx, "Could not create image surface\n");
+	test_status = CAIRO_TEST_ERROR;
+	goto out;
+    }
+
+    test_status = check_mime_data (ctx, surface, mimetype, NULL, 0);
+    if (test_status)
+	goto out;
+
+    status = cairo_surface_set_mime_data (surface,
+					  mimetype,
+					  (const unsigned char *) data,
+					  strlen (data),
+					  mime_data_destroy_func,
+					  &destroy_called);
+    if (status) {
+	cairo_test_log (ctx, "Could not set mime data: %s\n",
+			cairo_status_to_string(status));
+	test_status = CAIRO_TEST_ERROR;
+	goto out;
+    }
+
+    test_status = check_mime_data (ctx, surface, mimetype,
+	    (unsigned char *) data, strlen (data));
+    if (test_status)
+	goto out;
+
+    if (destroy_called) {
+	cairo_test_log (ctx, "MIME data destroyed too early\n");
+	test_status = CAIRO_TEST_ERROR;
+	goto out;
+    }
+
+    status = cairo_surface_set_mime_data (surface,
+					  mimetype,
+					  NULL, 0,
+					  NULL, NULL);
+    if (status) {
+	cairo_test_log (ctx, "Could not unset mime data: %s\n",
+			cairo_status_to_string(status));
+	test_status = CAIRO_TEST_ERROR;
+	goto out;
+    }
+
+    if (!destroy_called) {
+	cairo_test_log (ctx, "MIME data destroy callback not called\n");
+	test_status = CAIRO_TEST_ERROR;
+	goto out;
+    }
+
+    test_status = check_mime_data (ctx, surface, mimetype, NULL, 0);
+    if (test_status)
+	goto out;
+
+out:
+    cairo_surface_destroy (surface);
+
+    return test_status;
+}
+
+CAIRO_TEST (mime_surface_api,
+	    "Check the mime data API",
+	    "api", /* keywords */
+	    NULL, /* requirements */
+	    0, 0,
+	    preamble, NULL)
-- 
1.7.6.3
0002-Make-the-new-mime-surface-api-succeed.patch (text/x-diff, 1.3 KB)
From 373d3f397a5a6ce1d47c35a0606cd3e49c00758d Mon Sep 17 00:00:00 2001
From: Uli Schlachter <[email protected]>
Date: Tue, 4 Oct 2011 15:03:27 +0200
Subject: [PATCH 2/2] Make the new mime-surface-api succeed

When removing mime data, _cairo_user_data_array_set_data () is called with a
NULL argument. This leaves behind an entry with key == NULL in the user data
array. Skip those entries instead of dereferencing NULL.

(The NULL entry in the array let's us avoid moving data around and/or doing a
memory allocation later, so I guess it might be a good idea to keep that)

Signed-off-by: Uli Schlachter <[email protected]>
---
 src/cairo-surface.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 8488380..3be6d42 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1035,7 +1035,7 @@ cairo_surface_get_mime_data (cairo_surface_t		*surface,
     num_slots = surface->mime_data.num_elements;
     slots = _cairo_array_index (&surface->mime_data, 0);
     for (i = 0; i < num_slots; i++) {
-	if (strcmp ((char *) slots[i].key, mime_type) == 0) {
+	if (slots[i].key != NULL && strcmp ((char *) slots[i].key, mime_type) == 0) {
 	    cairo_mime_data_t *mime_data = slots[i].user_data;
 
 	    *data = mime_data->data;
-- 
1.7.6.3
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.