diff --git a/contrib/libtests/pngimage.c b/contrib/libtests/pngimage.c index d22f7bcd0..2e2dd0894 100644 --- a/contrib/libtests/pngimage.c +++ b/contrib/libtests/pngimage.c @@ -542,6 +542,7 @@ typedef enum struct display { jmp_buf error_return; /* Where to go to on error */ + error_level error_code; /* Set before longjmp */ const char *filename; /* The name of the original file */ const char *operation; /* Operation being performed */ @@ -762,7 +763,10 @@ display_log(struct display *dp, error_level level, const char *fmt, ...) /* Errors cause this routine to exit to the fail code */ if (level > APP_FAIL || (level > ERRORS && !(dp->options & CONTINUE))) + { + dp->error_code = level; longjmp(dp->error_return, level); + } } /* error handler callbacks for libpng */ @@ -1570,18 +1574,19 @@ static int do_test(struct display *dp, const char *file) /* Exists solely to isolate the setjmp clobbers */ { - int ret = setjmp(dp->error_return); + dp->error_code = VERBOSE; /* The "lowest" level */ - if (ret == 0) + if (setjmp(dp->error_return) == 0) { test_one_file(dp, file); return 0; } - else if (ret < ERRORS) /* shouldn't longjmp on warnings */ - display_log(dp, INTERNAL_ERROR, "unexpected return code %d", ret); + else if (dp->error_code < ERRORS) /* shouldn't longjmp on warnings */ + display_log(dp, INTERNAL_ERROR, "unexpected return code %d", + dp->error_code); - return ret; + return dp->error_code; } int @@ -1681,7 +1686,11 @@ main(int argc, char **argv) int ret = do_test(&d, argv[i]); if (ret > QUIET) /* abort on user or internal error */ + { + display_clean(&d); + display_destroy(&d); return 99; + } } /* Here on any return, including failures, except user/internal issues diff --git a/pngerror.c b/pngerror.c index aa0ae58e1..275b188d0 100644 --- a/pngerror.c +++ b/pngerror.c @@ -935,23 +935,37 @@ png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message) int /* PRIVATE */ png_safe_execute(png_imagep image, int (*function)(png_voidp), png_voidp arg) { - png_voidp saved_error_buf = image->opaque->error_buf; + const png_voidp saved_error_buf = image->opaque->error_buf; jmp_buf safe_jmpbuf; - int result; /* Safely execute function(arg), with png_error returning back here. */ if (setjmp(safe_jmpbuf) == 0) { + int result; + image->opaque->error_buf = safe_jmpbuf; result = function(arg); image->opaque->error_buf = saved_error_buf; - return result; + + if (result) + return 1; /* success */ } - /* On png_error, return via longjmp, pop the jmpbuf, and free the image. */ + /* The function failed either because of a caught png_error and a regular + * return of false above or because of an uncaught png_error from the + * function itself. Ensure that the error_buf is always set back to the + * value saved above: + */ image->opaque->error_buf = saved_error_buf; - png_image_free(image); - return 0; + + /* On the final false return, when about to return control to the caller, the + * image is freed (png_image_free does this check but it is duplicated here + * for clarity: + */ + if (saved_error_buf == NULL) + png_image_free(image); + + return 0; /* failure */ } #endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */ #endif /* READ || WRITE */