1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 /* pngerror.c - stub functions for i/o and memory allocation
  26  *
  27  * This file is available under and governed by the GNU General Public
  28  * License version 2 only, as published by the Free Software Foundation.
  29  * However, the following notice accompanied the original version of this
  30  * file and, per its terms, should not be removed:
  31  *
  32  * Last changed in libpng 1.6.31 [July 27, 2017]
  33  * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
  34  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  35  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  36  *
  37  * This code is released under the libpng license.
  38  * For conditions of distribution and use, see the disclaimer
  39  * and license in png.h
  40  *
  41  * This file provides a location for all error handling.  Users who
  42  * need special error handling are expected to write replacement functions
  43  * and use png_set_error_fn() to use those functions.  See the instructions
  44  * at each function.
  45  */
  46 
  47 #include "pngpriv.h"
  48 
  49 #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
  50 
  51 static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr,
  52     png_const_charp error_message)),PNG_NORETURN);
  53 
  54 #ifdef PNG_WARNINGS_SUPPORTED
  55 static void /* PRIVATE */
  56 png_default_warning PNGARG((png_const_structrp png_ptr,
  57     png_const_charp warning_message));
  58 #endif /* WARNINGS */
  59 
  60 /* This function is called whenever there is a fatal error.  This function
  61  * should not be changed.  If there is a need to handle errors differently,
  62  * you should supply a replacement error function and use png_set_error_fn()
  63  * to replace the error function at run-time.
  64  */
  65 #ifdef PNG_ERROR_TEXT_SUPPORTED
  66 PNG_FUNCTION(void,PNGAPI
  67 png_error,(png_const_structrp png_ptr, png_const_charp error_message),
  68     PNG_NORETURN)
  69 {
  70 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
  71    char msg[16];
  72    if (png_ptr != NULL)
  73    {
  74       if ((png_ptr->flags &
  75          (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
  76       {
  77          if (*error_message == PNG_LITERAL_SHARP)
  78          {
  79             /* Strip "#nnnn " from beginning of error message. */
  80             int offset;
  81             for (offset = 1; offset<15; offset++)
  82                if (error_message[offset] == ' ')
  83                   break;
  84 
  85             if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
  86             {
  87                int i;
  88                for (i = 0; i < offset - 1; i++)
  89                   msg[i] = error_message[i + 1];
  90                msg[i - 1] = '\0';
  91                error_message = msg;
  92             }
  93 
  94             else
  95                error_message += offset;
  96          }
  97 
  98          else
  99          {
 100             if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
 101             {
 102                msg[0] = '0';
 103                msg[1] = '\0';
 104                error_message = msg;
 105             }
 106          }
 107       }
 108    }
 109 #endif
 110    if (png_ptr != NULL && png_ptr->error_fn != NULL)
 111       (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr),
 112           error_message);
 113 
 114    /* If the custom handler doesn't exist, or if it returns,
 115       use the default handler, which will not return. */
 116    png_default_error(png_ptr, error_message);
 117 }
 118 #else
 119 PNG_FUNCTION(void,PNGAPI
 120 png_err,(png_const_structrp png_ptr),PNG_NORETURN)
 121 {
 122    /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed
 123     * erroneously as '\0', instead of the empty string "".  This was
 124     * apparently an error, introduced in libpng-1.2.20, and png_default_error
 125     * will crash in this case.
 126     */
 127    if (png_ptr != NULL && png_ptr->error_fn != NULL)
 128       (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), "");
 129 
 130    /* If the custom handler doesn't exist, or if it returns,
 131       use the default handler, which will not return. */
 132    png_default_error(png_ptr, "");
 133 }
 134 #endif /* ERROR_TEXT */
 135 
 136 /* Utility to safely appends strings to a buffer.  This never errors out so
 137  * error checking is not required in the caller.
 138  */
 139 size_t
 140 png_safecat(png_charp buffer, size_t bufsize, size_t pos,
 141     png_const_charp string)
 142 {
 143    if (buffer != NULL && pos < bufsize)
 144    {
 145       if (string != NULL)
 146          while (*string != '\0' && pos < bufsize-1)
 147            buffer[pos++] = *string++;
 148 
 149       buffer[pos] = '\0';
 150    }
 151 
 152    return pos;
 153 }
 154 
 155 #if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED)
 156 /* Utility to dump an unsigned value into a buffer, given a start pointer and
 157  * and end pointer (which should point just *beyond* the end of the buffer!)
 158  * Returns the pointer to the start of the formatted string.
 159  */
 160 png_charp
 161 png_format_number(png_const_charp start, png_charp end, int format,
 162     png_alloc_size_t number)
 163 {
 164    int count = 0;    /* number of digits output */
 165    int mincount = 1; /* minimum number required */
 166    int output = 0;   /* digit output (for the fixed point format) */
 167 
 168    *--end = '\0';
 169 
 170    /* This is written so that the loop always runs at least once, even with
 171     * number zero.
 172     */
 173    while (end > start && (number != 0 || count < mincount))
 174    {
 175 
 176       static const char digits[] = "0123456789ABCDEF";
 177 
 178       switch (format)
 179       {
 180          case PNG_NUMBER_FORMAT_fixed:
 181             /* Needs five digits (the fraction) */
 182             mincount = 5;
 183             if (output != 0 || number % 10 != 0)
 184             {
 185                *--end = digits[number % 10];
 186                output = 1;
 187             }
 188             number /= 10;
 189             break;
 190 
 191          case PNG_NUMBER_FORMAT_02u:
 192             /* Expects at least 2 digits. */
 193             mincount = 2;
 194             /* FALLTHROUGH */
 195 
 196          case PNG_NUMBER_FORMAT_u:
 197             *--end = digits[number % 10];
 198             number /= 10;
 199             break;
 200 
 201          case PNG_NUMBER_FORMAT_02x:
 202             /* This format expects at least two digits */
 203             mincount = 2;
 204             /* FALLTHROUGH */
 205 
 206          case PNG_NUMBER_FORMAT_x:
 207             *--end = digits[number & 0xf];
 208             number >>= 4;
 209             break;
 210 
 211          default: /* an error */
 212             number = 0;
 213             break;
 214       }
 215 
 216       /* Keep track of the number of digits added */
 217       ++count;
 218 
 219       /* Float a fixed number here: */
 220       if ((format == PNG_NUMBER_FORMAT_fixed) && (count == 5) && (end > start))
 221       {
 222          /* End of the fraction, but maybe nothing was output?  In that case
 223           * drop the decimal point.  If the number is a true zero handle that
 224           * here.
 225           */
 226          if (output != 0)
 227             *--end = '.';
 228          else if (number == 0) /* and !output */
 229             *--end = '0';
 230       }
 231    }
 232 
 233    return end;
 234 }
 235 #endif
 236 
 237 #ifdef PNG_WARNINGS_SUPPORTED
 238 /* This function is called whenever there is a non-fatal error.  This function
 239  * should not be changed.  If there is a need to handle warnings differently,
 240  * you should supply a replacement warning function and use
 241  * png_set_error_fn() to replace the warning function at run-time.
 242  */
 243 void PNGAPI
 244 png_warning(png_const_structrp png_ptr, png_const_charp warning_message)
 245 {
 246    int offset = 0;
 247    if (png_ptr != NULL)
 248    {
 249 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
 250    if ((png_ptr->flags &
 251        (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
 252 #endif
 253       {
 254          if (*warning_message == PNG_LITERAL_SHARP)
 255          {
 256             for (offset = 1; offset < 15; offset++)
 257                if (warning_message[offset] == ' ')
 258                   break;
 259          }
 260       }
 261    }
 262    if (png_ptr != NULL && png_ptr->warning_fn != NULL)
 263       (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr),
 264           warning_message + offset);
 265    else
 266       png_default_warning(png_ptr, warning_message + offset);
 267 }
 268 
 269 /* These functions support 'formatted' warning messages with up to
 270  * PNG_WARNING_PARAMETER_COUNT parameters.  In the format string the parameter
 271  * is introduced by @<number>, where 'number' starts at 1.  This follows the
 272  * standard established by X/Open for internationalizable error messages.
 273  */
 274 void
 275 png_warning_parameter(png_warning_parameters p, int number,
 276     png_const_charp string)
 277 {
 278    if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT)
 279       (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string);
 280 }
 281 
 282 void
 283 png_warning_parameter_unsigned(png_warning_parameters p, int number, int format,
 284     png_alloc_size_t value)
 285 {
 286    char buffer[PNG_NUMBER_BUFFER_SIZE];
 287    png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value));
 288 }
 289 
 290 void
 291 png_warning_parameter_signed(png_warning_parameters p, int number, int format,
 292     png_int_32 value)
 293 {
 294    png_alloc_size_t u;
 295    png_charp str;
 296    char buffer[PNG_NUMBER_BUFFER_SIZE];
 297 
 298    /* Avoid overflow by doing the negate in a png_alloc_size_t: */
 299    u = (png_alloc_size_t)value;
 300    if (value < 0)
 301       u = ~u + 1;
 302 
 303    str = PNG_FORMAT_NUMBER(buffer, format, u);
 304 
 305    if (value < 0 && str > buffer)
 306       *--str = '-';
 307 
 308    png_warning_parameter(p, number, str);
 309 }
 310 
 311 void
 312 png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p,
 313     png_const_charp message)
 314 {
 315    /* The internal buffer is just 192 bytes - enough for all our messages,
 316     * overflow doesn't happen because this code checks!  If someone figures
 317     * out how to send us a message longer than 192 bytes, all that will
 318     * happen is that the message will be truncated appropriately.
 319     */
 320    size_t i = 0; /* Index in the msg[] buffer: */
 321    char msg[192];
 322 
 323    /* Each iteration through the following loop writes at most one character
 324     * to msg[i++] then returns here to validate that there is still space for
 325     * the trailing '\0'.  It may (in the case of a parameter) read more than
 326     * one character from message[]; it must check for '\0' and continue to the
 327     * test if it finds the end of string.
 328     */
 329    while (i<(sizeof msg)-1 && *message != '\0')
 330    {
 331       /* '@' at end of string is now just printed (previously it was skipped);
 332        * it is an error in the calling code to terminate the string with @.
 333        */
 334       if (p != NULL && *message == '@' && message[1] != '\0')
 335       {
 336          int parameter_char = *++message; /* Consume the '@' */
 337          static const char valid_parameters[] = "123456789";
 338          int parameter = 0;
 339 
 340          /* Search for the parameter digit, the index in the string is the
 341           * parameter to use.
 342           */
 343          while (valid_parameters[parameter] != parameter_char &&
 344             valid_parameters[parameter] != '\0')
 345             ++parameter;
 346 
 347          /* If the parameter digit is out of range it will just get printed. */
 348          if (parameter < PNG_WARNING_PARAMETER_COUNT)
 349          {
 350             /* Append this parameter */
 351             png_const_charp parm = p[parameter];
 352             png_const_charp pend = p[parameter] + (sizeof p[parameter]);
 353 
 354             /* No need to copy the trailing '\0' here, but there is no guarantee
 355              * that parm[] has been initialized, so there is no guarantee of a
 356              * trailing '\0':
 357              */
 358             while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend)
 359                msg[i++] = *parm++;
 360 
 361             /* Consume the parameter digit too: */
 362             ++message;
 363             continue;
 364          }
 365 
 366          /* else not a parameter and there is a character after the @ sign; just
 367           * copy that.  This is known not to be '\0' because of the test above.
 368           */
 369       }
 370 
 371       /* At this point *message can't be '\0', even in the bad parameter case
 372        * above where there is a lone '@' at the end of the message string.
 373        */
 374       msg[i++] = *message++;
 375    }
 376 
 377    /* i is always less than (sizeof msg), so: */
 378    msg[i] = '\0';
 379 
 380    /* And this is the formatted message. It may be larger than
 381     * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these
 382     * are not (currently) formatted.
 383     */
 384    png_warning(png_ptr, msg);
 385 }
 386 #endif /* WARNINGS */
 387 
 388 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
 389 void PNGAPI
 390 png_benign_error(png_const_structrp png_ptr, png_const_charp error_message)
 391 {
 392    if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0)
 393    {
 394 #     ifdef PNG_READ_SUPPORTED
 395          if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
 396             png_ptr->chunk_name != 0)
 397             png_chunk_warning(png_ptr, error_message);
 398          else
 399 #     endif
 400       png_warning(png_ptr, error_message);
 401    }
 402 
 403    else
 404    {
 405 #     ifdef PNG_READ_SUPPORTED
 406          if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
 407             png_ptr->chunk_name != 0)
 408             png_chunk_error(png_ptr, error_message);
 409          else
 410 #     endif
 411       png_error(png_ptr, error_message);
 412    }
 413 
 414 #  ifndef PNG_ERROR_TEXT_SUPPORTED
 415       PNG_UNUSED(error_message)
 416 #  endif
 417 }
 418 
 419 void /* PRIVATE */
 420 png_app_warning(png_const_structrp png_ptr, png_const_charp error_message)
 421 {
 422    if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0)
 423       png_warning(png_ptr, error_message);
 424    else
 425       png_error(png_ptr, error_message);
 426 
 427 #  ifndef PNG_ERROR_TEXT_SUPPORTED
 428       PNG_UNUSED(error_message)
 429 #  endif
 430 }
 431 
 432 void /* PRIVATE */
 433 png_app_error(png_const_structrp png_ptr, png_const_charp error_message)
 434 {
 435    if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0)
 436       png_warning(png_ptr, error_message);
 437    else
 438       png_error(png_ptr, error_message);
 439 
 440 #  ifndef PNG_ERROR_TEXT_SUPPORTED
 441       PNG_UNUSED(error_message)
 442 #  endif
 443 }
 444 #endif /* BENIGN_ERRORS */
 445 
 446 #define PNG_MAX_ERROR_TEXT 196 /* Currently limited by profile_error in png.c */
 447 #if defined(PNG_WARNINGS_SUPPORTED) || \
 448    (defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED))
 449 /* These utilities are used internally to build an error message that relates
 450  * to the current chunk.  The chunk name comes from png_ptr->chunk_name,
 451  * which is used to prefix the message.  The message is limited in length
 452  * to 63 bytes. The name characters are output as hex digits wrapped in []
 453  * if the character is invalid.
 454  */
 455 #define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
 456 static PNG_CONST char png_digit[16] = {
 457    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 458    'A', 'B', 'C', 'D', 'E', 'F'
 459 };
 460 
 461 static void /* PRIVATE */
 462 png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp
 463     error_message)
 464 {
 465    png_uint_32 chunk_name = png_ptr->chunk_name;
 466    int iout = 0, ishift = 24;
 467 
 468    while (ishift >= 0)
 469    {
 470       int c = (int)(chunk_name >> ishift) & 0xff;
 471 
 472       ishift -= 8;
 473       if (isnonalpha(c) != 0)
 474       {
 475          buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET;
 476          buffer[iout++] = png_digit[(c & 0xf0) >> 4];
 477          buffer[iout++] = png_digit[c & 0x0f];
 478          buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET;
 479       }
 480 
 481       else
 482       {
 483          buffer[iout++] = (char)c;
 484       }
 485    }
 486 
 487    if (error_message == NULL)
 488       buffer[iout] = '\0';
 489 
 490    else
 491    {
 492       int iin = 0;
 493 
 494       buffer[iout++] = ':';
 495       buffer[iout++] = ' ';
 496 
 497       while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0')
 498          buffer[iout++] = error_message[iin++];
 499 
 500       /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */
 501       buffer[iout] = '\0';
 502    }
 503 }
 504 #endif /* WARNINGS || ERROR_TEXT */
 505 
 506 #if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)
 507 PNG_FUNCTION(void,PNGAPI
 508 png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message),
 509     PNG_NORETURN)
 510 {
 511    char msg[18+PNG_MAX_ERROR_TEXT];
 512    if (png_ptr == NULL)
 513       png_error(png_ptr, error_message);
 514 
 515    else
 516    {
 517       png_format_buffer(png_ptr, msg, error_message);
 518       png_error(png_ptr, msg);
 519    }
 520 }
 521 #endif /* READ && ERROR_TEXT */
 522 
 523 #ifdef PNG_WARNINGS_SUPPORTED
 524 void PNGAPI
 525 png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message)
 526 {
 527    char msg[18+PNG_MAX_ERROR_TEXT];
 528    if (png_ptr == NULL)
 529       png_warning(png_ptr, warning_message);
 530 
 531    else
 532    {
 533       png_format_buffer(png_ptr, msg, warning_message);
 534       png_warning(png_ptr, msg);
 535    }
 536 }
 537 #endif /* WARNINGS */
 538 
 539 #ifdef PNG_READ_SUPPORTED
 540 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
 541 void PNGAPI
 542 png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp
 543     error_message)
 544 {
 545    if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0)
 546       png_chunk_warning(png_ptr, error_message);
 547 
 548    else
 549       png_chunk_error(png_ptr, error_message);
 550 
 551 #  ifndef PNG_ERROR_TEXT_SUPPORTED
 552       PNG_UNUSED(error_message)
 553 #  endif
 554 }
 555 #endif
 556 #endif /* READ */
 557 
 558 void /* PRIVATE */
 559 png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error)
 560 {
 561 #  ifndef PNG_WARNINGS_SUPPORTED
 562       PNG_UNUSED(message)
 563 #  endif
 564 
 565    /* This is always supported, but for just read or just write it
 566     * unconditionally does the right thing.
 567     */
 568 #  if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED)
 569       if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
 570 #  endif
 571 
 572 #  ifdef PNG_READ_SUPPORTED
 573       {
 574          if (error < PNG_CHUNK_ERROR)
 575             png_chunk_warning(png_ptr, message);
 576 
 577          else
 578             png_chunk_benign_error(png_ptr, message);
 579       }
 580 #  endif
 581 
 582 #  if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED)
 583       else if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
 584 #  endif
 585 
 586 #  ifdef PNG_WRITE_SUPPORTED
 587       {
 588          if (error < PNG_CHUNK_WRITE_ERROR)
 589             png_app_warning(png_ptr, message);
 590 
 591          else
 592             png_app_error(png_ptr, message);
 593       }
 594 #  endif
 595 }
 596 
 597 #ifdef PNG_ERROR_TEXT_SUPPORTED
 598 #ifdef PNG_FLOATING_POINT_SUPPORTED
 599 PNG_FUNCTION(void,
 600 png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN)
 601 {
 602 #  define fixed_message "fixed point overflow in "
 603 #  define fixed_message_ln ((sizeof fixed_message)-1)
 604    unsigned int  iin;
 605    char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT];
 606    memcpy(msg, fixed_message, fixed_message_ln);
 607    iin = 0;
 608    if (name != NULL)
 609       while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0)
 610       {
 611          msg[fixed_message_ln + iin] = name[iin];
 612          ++iin;
 613       }
 614    msg[fixed_message_ln + iin] = 0;
 615    png_error(png_ptr, msg);
 616 }
 617 #endif
 618 #endif
 619 
 620 #ifdef PNG_SETJMP_SUPPORTED
 621 /* This API only exists if ANSI-C style error handling is used,
 622  * otherwise it is necessary for png_default_error to be overridden.
 623  */
 624 jmp_buf* PNGAPI
 625 png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn,
 626     size_t jmp_buf_size)
 627 {
 628    /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value
 629     * and it must not change after that.  Libpng doesn't care how big the
 630     * buffer is, just that it doesn't change.
 631     *
 632     * If the buffer size is no *larger* than the size of jmp_buf when libpng is
 633     * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0
 634     * semantics that this call will not fail.  If the size is larger, however,
 635     * the buffer is allocated and this may fail, causing the function to return
 636     * NULL.
 637     */
 638    if (png_ptr == NULL)
 639       return NULL;
 640 
 641    if (png_ptr->jmp_buf_ptr == NULL)
 642    {
 643       png_ptr->jmp_buf_size = 0; /* not allocated */
 644 
 645       if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local))
 646          png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local;
 647 
 648       else
 649       {
 650          png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *,
 651              png_malloc_warn(png_ptr, jmp_buf_size));
 652 
 653          if (png_ptr->jmp_buf_ptr == NULL)
 654             return NULL; /* new NULL return on OOM */
 655 
 656          png_ptr->jmp_buf_size = jmp_buf_size;
 657       }
 658    }
 659 
 660    else /* Already allocated: check the size */
 661    {
 662       size_t size = png_ptr->jmp_buf_size;
 663 
 664       if (size == 0)
 665       {
 666          size = (sizeof png_ptr->jmp_buf_local);
 667          if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local)
 668          {
 669             /* This is an internal error in libpng: somehow we have been left
 670              * with a stack allocated jmp_buf when the application regained
 671              * control.  It's always possible to fix this up, but for the moment
 672              * this is a png_error because that makes it easy to detect.
 673              */
 674             png_error(png_ptr, "Libpng jmp_buf still allocated");
 675             /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */
 676          }
 677       }
 678 
 679       if (size != jmp_buf_size)
 680       {
 681          png_warning(png_ptr, "Application jmp_buf size changed");
 682          return NULL; /* caller will probably crash: no choice here */
 683       }
 684    }
 685 
 686    /* Finally fill in the function, now we have a satisfactory buffer. It is
 687     * valid to change the function on every call.
 688     */
 689    png_ptr->longjmp_fn = longjmp_fn;
 690    return png_ptr->jmp_buf_ptr;
 691 }
 692 
 693 void /* PRIVATE */
 694 png_free_jmpbuf(png_structrp png_ptr)
 695 {
 696    if (png_ptr != NULL)
 697    {
 698       jmp_buf *jb = png_ptr->jmp_buf_ptr;
 699 
 700       /* A size of 0 is used to indicate a local, stack, allocation of the
 701        * pointer; used here and in png.c
 702        */
 703       if (jb != NULL && png_ptr->jmp_buf_size > 0)
 704       {
 705 
 706          /* This stuff is so that a failure to free the error control structure
 707           * does not leave libpng in a state with no valid error handling: the
 708           * free always succeeds, if there is an error it gets ignored.
 709           */
 710          if (jb != &png_ptr->jmp_buf_local)
 711          {
 712             /* Make an internal, libpng, jmp_buf to return here */
 713             jmp_buf free_jmp_buf;
 714 
 715             if (!setjmp(free_jmp_buf))
 716             {
 717                png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */
 718                png_ptr->jmp_buf_size = 0; /* stack allocation */
 719                png_ptr->longjmp_fn = longjmp;
 720                png_free(png_ptr, jb); /* Return to setjmp on error */
 721             }
 722          }
 723       }
 724 
 725       /* *Always* cancel everything out: */
 726       png_ptr->jmp_buf_size = 0;
 727       png_ptr->jmp_buf_ptr = NULL;
 728       png_ptr->longjmp_fn = 0;
 729    }
 730 }
 731 #endif
 732 
 733 /* This is the default error handling function.  Note that replacements for
 734  * this function MUST NOT RETURN, or the program will likely crash.  This
 735  * function is used by default, or if the program supplies NULL for the
 736  * error function pointer in png_set_error_fn().
 737  */
 738 static PNG_FUNCTION(void /* PRIVATE */,
 739 png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
 740     PNG_NORETURN)
 741 {
 742 #ifdef PNG_CONSOLE_IO_SUPPORTED
 743 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
 744    /* Check on NULL only added in 1.5.4 */
 745    if (error_message != NULL && *error_message == PNG_LITERAL_SHARP)
 746    {
 747       /* Strip "#nnnn " from beginning of error message. */
 748       int offset;
 749       char error_number[16];
 750       for (offset = 0; offset<15; offset++)
 751       {
 752          error_number[offset] = error_message[offset + 1];
 753          if (error_message[offset] == ' ')
 754             break;
 755       }
 756 
 757       if ((offset > 1) && (offset < 15))
 758       {
 759          error_number[offset - 1] = '\0';
 760          fprintf(stderr, "libpng error no. %s: %s",
 761              error_number, error_message + offset + 1);
 762          fprintf(stderr, PNG_STRING_NEWLINE);
 763       }
 764 
 765       else
 766       {
 767          fprintf(stderr, "libpng error: %s, offset=%d",
 768              error_message, offset);
 769          fprintf(stderr, PNG_STRING_NEWLINE);
 770       }
 771    }
 772    else
 773 #endif
 774    {
 775       fprintf(stderr, "libpng error: %s", error_message ? error_message :
 776          "undefined");
 777       fprintf(stderr, PNG_STRING_NEWLINE);
 778    }
 779 #else
 780    PNG_UNUSED(error_message) /* Make compiler happy */
 781 #endif
 782    png_longjmp(png_ptr, 1);
 783 }
 784 
 785 PNG_FUNCTION(void,PNGAPI
 786 png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN)
 787 {
 788 #ifdef PNG_SETJMP_SUPPORTED
 789    if (png_ptr != NULL && png_ptr->longjmp_fn != NULL &&
 790        png_ptr->jmp_buf_ptr != NULL)
 791       png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val);
 792 #else
 793    PNG_UNUSED(png_ptr)
 794    PNG_UNUSED(val)
 795 #endif
 796 
 797    /* If control reaches this point, png_longjmp() must not return. The only
 798     * choice is to terminate the whole process (or maybe the thread); to do
 799     * this the ANSI-C abort() function is used unless a different method is
 800     * implemented by overriding the default configuration setting for
 801     * PNG_ABORT().
 802     */
 803    PNG_ABORT();
 804 }
 805 
 806 #ifdef PNG_WARNINGS_SUPPORTED
 807 /* This function is called when there is a warning, but the library thinks
 808  * it can continue anyway.  Replacement functions don't have to do anything
 809  * here if you don't want them to.  In the default configuration, png_ptr is
 810  * not used, but it is passed in case it may be useful.
 811  */
 812 static void /* PRIVATE */
 813 png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)
 814 {
 815 #ifdef PNG_CONSOLE_IO_SUPPORTED
 816 #  ifdef PNG_ERROR_NUMBERS_SUPPORTED
 817    if (*warning_message == PNG_LITERAL_SHARP)
 818    {
 819       int offset;
 820       char warning_number[16];
 821       for (offset = 0; offset < 15; offset++)
 822       {
 823          warning_number[offset] = warning_message[offset + 1];
 824          if (warning_message[offset] == ' ')
 825             break;
 826       }
 827 
 828       if ((offset > 1) && (offset < 15))
 829       {
 830          warning_number[offset + 1] = '\0';
 831          fprintf(stderr, "libpng warning no. %s: %s",
 832              warning_number, warning_message + offset);
 833          fprintf(stderr, PNG_STRING_NEWLINE);
 834       }
 835 
 836       else
 837       {
 838          fprintf(stderr, "libpng warning: %s",
 839              warning_message);
 840          fprintf(stderr, PNG_STRING_NEWLINE);
 841       }
 842    }
 843    else
 844 #  endif
 845 
 846    {
 847       fprintf(stderr, "libpng warning: %s", warning_message);
 848       fprintf(stderr, PNG_STRING_NEWLINE);
 849    }
 850 #else
 851    PNG_UNUSED(warning_message) /* Make compiler happy */
 852 #endif
 853    PNG_UNUSED(png_ptr) /* Make compiler happy */
 854 }
 855 #endif /* WARNINGS */
 856 
 857 /* This function is called when the application wants to use another method
 858  * of handling errors and warnings.  Note that the error function MUST NOT
 859  * return to the calling routine or serious problems will occur.  The return
 860  * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1)
 861  */
 862 void PNGAPI
 863 png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr,
 864     png_error_ptr error_fn, png_error_ptr warning_fn)
 865 {
 866    if (png_ptr == NULL)
 867       return;
 868 
 869    png_ptr->error_ptr = error_ptr;
 870    png_ptr->error_fn = error_fn;
 871 #ifdef PNG_WARNINGS_SUPPORTED
 872    png_ptr->warning_fn = warning_fn;
 873 #else
 874    PNG_UNUSED(warning_fn)
 875 #endif
 876 }
 877 
 878 
 879 /* This function returns a pointer to the error_ptr associated with the user
 880  * functions.  The application should free any memory associated with this
 881  * pointer before png_write_destroy and png_read_destroy are called.
 882  */
 883 png_voidp PNGAPI
 884 png_get_error_ptr(png_const_structrp png_ptr)
 885 {
 886    if (png_ptr == NULL)
 887       return NULL;
 888 
 889    return ((png_voidp)png_ptr->error_ptr);
 890 }
 891 
 892 
 893 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
 894 void PNGAPI
 895 png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode)
 896 {
 897    if (png_ptr != NULL)
 898    {
 899       png_ptr->flags &=
 900          ((~(PNG_FLAG_STRIP_ERROR_NUMBERS |
 901          PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
 902    }
 903 }
 904 #endif
 905 
 906 #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
 907    defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
 908    /* Currently the above both depend on SETJMP_SUPPORTED, however it would be
 909     * possible to implement without setjmp support just so long as there is some
 910     * way to handle the error return here:
 911     */
 912 PNG_FUNCTION(void /* PRIVATE */, (PNGCBAPI
 913 png_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message),
 914     PNG_NORETURN)
 915 {
 916    const png_const_structrp png_ptr = png_nonconst_ptr;
 917    png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);
 918 
 919    /* An error is always logged here, overwriting anything (typically a warning)
 920     * that is already there:
 921     */
 922    if (image != NULL)
 923    {
 924       png_safecat(image->message, (sizeof image->message), 0, error_message);
 925       image->warning_or_error |= PNG_IMAGE_ERROR;
 926 
 927       /* Retrieve the jmp_buf from within the png_control, making this work for
 928        * C++ compilation too is pretty tricky: C++ wants a pointer to the first
 929        * element of a jmp_buf, but C doesn't tell us the type of that.
 930        */
 931       if (image->opaque != NULL && image->opaque->error_buf != NULL)
 932          longjmp(png_control_jmp_buf(image->opaque), 1);
 933 
 934       /* Missing longjmp buffer, the following is to help debugging: */
 935       {
 936          size_t pos = png_safecat(image->message, (sizeof image->message), 0,
 937              "bad longjmp: ");
 938          png_safecat(image->message, (sizeof image->message), pos,
 939              error_message);
 940       }
 941    }
 942 
 943    /* Here on an internal programming error. */
 944    abort();
 945 }
 946 
 947 #ifdef PNG_WARNINGS_SUPPORTED
 948 void /* PRIVATE */ PNGCBAPI
 949 png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message)
 950 {
 951    const png_const_structrp png_ptr = png_nonconst_ptr;
 952    png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);
 953 
 954    /* A warning is only logged if there is no prior warning or error. */
 955    if (image->warning_or_error == 0)
 956    {
 957       png_safecat(image->message, (sizeof image->message), 0, warning_message);
 958       image->warning_or_error |= PNG_IMAGE_WARNING;
 959    }
 960 }
 961 #endif
 962 
 963 int /* PRIVATE */
 964 png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg)
 965 {
 966    volatile png_imagep image = image_in;
 967    volatile int result;
 968    volatile png_voidp saved_error_buf;
 969    jmp_buf safe_jmpbuf;
 970 
 971    /* Safely execute function(arg) with png_error returning to this function. */
 972    saved_error_buf = image->opaque->error_buf;
 973    result = setjmp(safe_jmpbuf) == 0;
 974 
 975    if (result != 0)
 976    {
 977 
 978       image->opaque->error_buf = safe_jmpbuf;
 979       result = function(arg);
 980    }
 981 
 982    image->opaque->error_buf = saved_error_buf;
 983 
 984    /* And do the cleanup prior to any failure return. */
 985    if (result == 0)
 986       png_image_free(image);
 987 
 988    return result;
 989 }
 990 #endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */
 991 #endif /* READ || WRITE */