From 2fbd53a6b33a90a08ef6eda9e5f88e8fb3b97c1e Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Fri, 23 Jul 2021 17:22:16 +0200 Subject: [PATCH 1/2] pdf: Properly pass on stdio write errors cairo-pdf was silently ignoring write errors in _cairo_pdf_surface_finish(). Any write errors that happened here ended up setting a "status" variable, but the value in this variable was then unused. This commit fixes this bug by passing this error on to the caller. Additionally, this also adds a test case for this behaviour based on writing to /dev/full. This file is non-standard and thus the test first checks that this file exists and is writable before trying to write to it. This bug was found based on a report from Knut Petersen [0]. [0]: https://lists.cairographics.org/archives/cairo/2021-July/029281.html Signed-off-by: Uli Schlachter --- src/cairo-pdf-interchange.c | 4 +--- src/cairo-pdf-surface-private.h | 2 +- src/cairo-pdf-surface.c | 4 +++- test/create-for-stream.c | 21 ++++++++++++++++++++- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/cairo-pdf-interchange.c b/src/cairo-pdf-interchange.c index 5cc10eb0b..ad4072e63 100644 --- a/src/cairo-pdf-interchange.c +++ b/src/cairo-pdf-interchange.c @@ -1515,7 +1515,7 @@ _cairo_pdf_interchange_free_outlines (cairo_pdf_surface_t *surface) _cairo_array_fini (&ic->outline); } -cairo_int_status_t +void _cairo_pdf_interchange_fini (cairo_pdf_surface_t *surface) { cairo_pdf_interchange_t *ic = &surface->interchange; @@ -1539,8 +1539,6 @@ _cairo_pdf_interchange_fini (cairo_pdf_surface_t *surface) free (ic->docinfo.creator); free (ic->docinfo.create_date); free (ic->docinfo.mod_date); - - return CAIRO_STATUS_SUCCESS; } cairo_int_status_t diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h index 3793332ce..49776b90f 100644 --- a/src/cairo-pdf-surface-private.h +++ b/src/cairo-pdf-surface-private.h @@ -355,7 +355,7 @@ _cairo_utf8_to_pdf_string (const char *utf8, char **str_out); cairo_private cairo_int_status_t _cairo_pdf_interchange_init (cairo_pdf_surface_t *surface); -cairo_private cairo_int_status_t +cairo_private void _cairo_pdf_interchange_fini (cairo_pdf_surface_t *surface); cairo_private cairo_int_status_t diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index b033fdf07..f2463a8c3 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -2329,7 +2329,9 @@ _cairo_pdf_surface_finish (void *abstract_surface) _cairo_surface_clipper_reset (&surface->clipper); - return _cairo_pdf_interchange_fini (surface); + _cairo_pdf_interchange_fini (surface); + + return status; } static cairo_int_status_t diff --git a/test/create-for-stream.c b/test/create-for-stream.c index af1632f14..3e7577a6a 100644 --- a/test/create-for-stream.c +++ b/test/create-for-stream.c @@ -28,6 +28,7 @@ #include #include #include +#include #if CAIRO_HAS_PS_SURFACE #include @@ -165,11 +166,29 @@ test_surface (const cairo_test_context_t *ctx, if (status != CAIRO_STATUS_WRITE_ERROR) { cairo_test_log (ctx, - "%s: Error: expected \"write error\", but received \"%s\".\n", + "%s: Error: expected \"write error\" from bad_write(), but received \"%s\".\n", backend, cairo_status_to_string (status)); return CAIRO_TEST_FAILURE; } + /* test propagation of file errors - for now this is unix-only */ + if (access("/dev/full", W_OK) == 0) { + surface = file_constructor ("/dev/full", WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + cairo_surface_destroy (surface); + + if (status != CAIRO_STATUS_WRITE_ERROR) { + cairo_test_log (ctx, + "%s: Error: expected \"write error\" from /dev/full, but received \"%s\".\n", + backend, cairo_status_to_string (status)); + return CAIRO_TEST_FAILURE; + } + } else { + cairo_test_log (ctx, + "/dev/full does not exist; skipping write test.\n"); + } + /* construct the real surface */ wc.ctx = ctx; wc.status = CAIRO_TEST_SUCCESS; From e689e670049b26be8c6bff69f3de372bddb8d856 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Fri, 23 Jul 2021 17:32:39 +0200 Subject: [PATCH 2/2] Fix build on windows Signed-off-by: Uli Schlachter --- test/create-for-stream.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/create-for-stream.c b/test/create-for-stream.c index 3e7577a6a..06f2db2b0 100644 --- a/test/create-for-stream.c +++ b/test/create-for-stream.c @@ -28,7 +28,10 @@ #include #include #include + +#ifndef _WIN32 #include +#endif #if CAIRO_HAS_PS_SURFACE #include @@ -172,6 +175,7 @@ test_surface (const cairo_test_context_t *ctx, } /* test propagation of file errors - for now this is unix-only */ +#ifndef _WIN32 if (access("/dev/full", W_OK) == 0) { surface = file_constructor ("/dev/full", WIDTH_IN_POINTS, HEIGHT_IN_POINTS); cairo_surface_finish (surface); @@ -188,6 +192,7 @@ test_surface (const cairo_test_context_t *ctx, cairo_test_log (ctx, "/dev/full does not exist; skipping write test.\n"); } +#endif /* construct the real surface */ wc.ctx = ctx;