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