diff --git a/ANNOUNCE b/ANNOUNCE index 46b5786aa..289608f21 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -49,6 +49,12 @@ Version 1.5.7beta02 [November 5, 2011] be non-NULL. The cast of the profile length potentially truncated the value unnecessarily on a 16-bit int system, so the cast of the (byte) compression type to (int) is specified by ANSI-C anyway. + Fixed FP division by zero in pngvalid.c; the 'test_pixel' code left + the sBIT fields in the test pixel as 0, which resulted in a floating + point division by zero which was irrelevant but causes systems where + FP exceptions cause a crash. Added code to pngvalid to turn on FP + exceptions if the appropriate glibc support is there to ensure this is + tested in the future. Send comments/corrections/commendations to png-mng-implement at lists.sf.net: (subscription required; visit diff --git a/CHANGES b/CHANGES index 9ee895027..c85a42653 100644 --- a/CHANGES +++ b/CHANGES @@ -3692,6 +3692,12 @@ Version 1.5.7beta02 [November 5, 2011] be non-NULL. The cast of the profile length potentially truncated the value unnecessarily on a 16-bit int system, so the cast of the (byte) compression type to (int) is specified by ANSI-C anyway. + Fixed FP division by zero in pngvalid.c; the 'test_pixel' code left + the sBIT fields in the test pixel as 0, which resulted in a floating + point division by zero which was irrelevant but causes systems where + FP exceptions cause a crash. Added code to pngvalid to turn on FP + exceptions if the appropriate glibc support is there to ensure this is + tested in the future. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/png.h b/png.h index 1d06ac272..9852f7224 100644 --- a/png.h +++ b/png.h @@ -1,7 +1,7 @@ /* png.h - header file for PNG reference library * - * libpng version 1.5.7beta02 - November 4, 2011 + * libpng version 1.5.7beta02 - November 5, 2011 * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -11,7 +11,7 @@ * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.5.7beta02 - November 4, 2011: Glenn + * libpng versions 0.97, January 1998, through 1.5.7beta02 - November 5, 2011: Glenn * See also "Contributing Authors", below. * * Note about libpng version numbers: @@ -195,7 +195,7 @@ * * This code is released under the libpng license. * - * libpng versions 1.2.6, August 15, 2004, through 1.5.7beta02, November 4, 2011, are + * libpng versions 1.2.6, August 15, 2004, through 1.5.7beta02, November 5, 2011, are * Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are * distributed according to the same disclaimer and license as libpng-1.2.5 * with the following individual added to the list of Contributing Authors: @@ -307,7 +307,7 @@ * Y2K compliance in libpng: * ========================= * - * November 4, 2011 + * November 5, 2011 * * Since the PNG Development group is an ad-hoc body, we can't make * an official declaration. @@ -370,7 +370,7 @@ /* Version information for png.h - this should match the version in png.c */ #define PNG_LIBPNG_VER_STRING "1.5.7beta02" #define PNG_HEADER_VERSION_STRING \ - " libpng version 1.5.7beta02 - November 4, 2011\n" + " libpng version 1.5.7beta02 - November 5, 2011\n" #define PNG_LIBPNG_VER_SONUM 15 #define PNG_LIBPNG_VER_DLLNUM 15 diff --git a/pngvalid.c b/pngvalid.c index 14d198ac9..beb6cb5c0 100644 --- a/pngvalid.c +++ b/pngvalid.c @@ -20,8 +20,21 @@ */ #define _POSIX_SOURCE 1 +#define _ISOC99_SOURCE 1 /* For floating point */ +#define _GNU_SOURCE 1 /* For the floating point exception extension */ + +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_FEENABLEEXCEPT +# include +#endif #include "png.h" + #if PNG_LIBPNG_VER < 10500 /* This delibarately lacks the PNG_CONST. */ typedef png_byte *png_const_bytep; @@ -831,6 +844,19 @@ store_log(png_store* ps, png_structp pp, png_const_charp message, int is_error) store_verbose(ps, pp, is_error ? "error: " : "warning: ", message); } +/* Internal error function, called with a png_store but no libpng stuff. */ +static void +internal_error(png_store *ps, png_const_charp message) +{ + store_log(ps, NULL, message, 1 /* error */); + + /* And finally throw an exception. */ + { + struct exception_context *the_exception_context = &ps->exception_context; + Throw ps; + } +} + /* Functions to use as PNG callbacks. */ static void store_error(png_structp pp, png_const_charp message) /* PNG_NORETURN */ @@ -3679,9 +3705,11 @@ static PNG_CONST struct }; static void -make_error(png_store* volatile ps, png_byte PNG_CONST colour_type, +make_error(png_store* volatile psIn, png_byte PNG_CONST colour_type, png_byte bit_depth, int interlace_type, int test, png_const_charp name) { + png_store * volatile ps = psIn; + context(ps, fault); Try @@ -3965,6 +3993,8 @@ standard_display_init(standard_display *dp, png_store* ps, png_uint_32 id, dp->ps = ps; dp->colour_type = COL_FROM_ID(id); dp->bit_depth = DEPTH_FROM_ID(id); + if (dp->bit_depth < 1 || dp->bit_depth > 16) + internal_error(ps, "internal: bad bit depth"); if (dp->colour_type == 3) dp->red_sBIT = dp->blue_sBIT = dp->green_sBIT = dp->alpha_sBIT = 8; else @@ -5333,8 +5363,12 @@ transform_info_imp(transform_display *dp, png_structp pp, png_infop pi) test_pixel.sample_depth = 8; else test_pixel.sample_depth = test_pixel.bit_depth; - /* Don't need sBIT here */ + /* Don't need sBIT here, but it must be set to non-zero to avoid + * arithmetic overflows. + */ test_pixel.have_tRNS = dp->this.is_transparent; + test_pixel.red_sBIT = test_pixel.green_sBIT = test_pixel.blue_sBIT = + test_pixel.alpha_sBIT = test_pixel.sample_depth; dp->transform_list->mod(dp->transform_list, &test_pixel, pp, dp); @@ -9267,6 +9301,72 @@ static PNG_CONST color_encoding test_encodings[] = /*blue: */ { 0.146774385252705, 0.016589442011321, 0.773892783545073} }, }; +/* signal handler + * + * This attempts to trap signals and escape without crashing. It needs a + * context pointer so that it can throw an exception (call longjmp) to recover + * from the condition; this is handled by making the png_modifier used by 'main' + * into a global variable. + */ +static png_modifier pm; + +static void signal_handler(int signum) +{ + + size_t pos = 0; + char msg[64]; + + pos = safecat(msg, sizeof msg, pos, "caught signal: "); + + switch (signum) + { + case SIGABRT: + pos = safecat(msg, sizeof msg, pos, "abort"); + break; + + case SIGFPE: + pos = safecat(msg, sizeof msg, pos, "floating point exception"); + break; + + case SIGILL: + pos = safecat(msg, sizeof msg, pos, "illegal instruction"); + break; + + case SIGINT: + pos = safecat(msg, sizeof msg, pos, "interrupt"); + break; + + case SIGSEGV: + pos = safecat(msg, sizeof msg, pos, "invalid memory access"); + break; + + case SIGTERM: + pos = safecat(msg, sizeof msg, pos, "termination request"); + break; + + default: + pos = safecat(msg, sizeof msg, pos, "unknown "); + pos = safecatn(msg, sizeof msg, pos, signum); + break; + } + + store_log(&pm.this, NULL/*png_structp*/, msg, 1/*error*/); + + /* And finally throw an exception so we can keep going, unless this is + * SIGTERM in which case stop now. + */ + if (signum != SIGTERM) + { + struct exception_context *the_exception_context = + &pm.this.exception_context; + + Throw &pm.this; + } + + else + exit(1); +} + /* main program */ int main(int argc, PNG_CONST char **argv) { @@ -9288,9 +9388,24 @@ int main(int argc, PNG_CONST char **argv) size_t cp = 0; char command[1024]; - png_modifier pm; context(&pm.this, fault); + /* Add appropriate signal handlers, just the ANSI specified ones: */ + signal(SIGABRT, signal_handler); + signal(SIGFPE, signal_handler); + signal(SIGILL, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGSEGV, signal_handler); + signal(SIGTERM, signal_handler); + +#ifdef HAVE_FEENABLEEXCEPT + /* Only required to enable FP exceptions on platforms where they start off + * disabled; this is not necessary but if it is not done pngvalid will likely + * end up ignoring FP conditions that other platforms fault. + */ + feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); +#endif + modifier_init(&pm); /* Preallocate the image buffer, because we know how big it needs to be,