1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %        EEEEE  X   X   CCCC  EEEEE  PPPP  TTTTT  IIIII   OOO   N   N         %
7 %        E       X X   C      E      P   P   T      I    O   O  NN  N         %
8 %        EEE      X    C      EEE    PPPP    T      I    O   O  N N N         %
9 %        E       X X   C      E      P       T      I    O   O  N  NN         %
10 %        EEEEE   X  X   CCCC  EEEEE  P       T    IIIII   OOO   N   N         %
11 %                                                                             %
12 %                                                                             %
13 %                        MagickCore Exception Methods                         %
14 %                                                                             %
15 %                             Software Design                                 %
16 %                                  Cristy                                     %
17 %                                July 1993                                    %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    https://imagemagick.org/script/license.php                               %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/client.h"
45 #include "MagickCore/exception.h"
46 #include "MagickCore/exception-private.h"
47 #include "MagickCore/linked-list.h"
48 #include "MagickCore/locale_.h"
49 #include "MagickCore/log.h"
50 #include "MagickCore/magick.h"
51 #include "MagickCore/memory_.h"
52 #include "MagickCore/memory-private.h"
53 #include "MagickCore/semaphore.h"
54 #include "MagickCore/string_.h"
55 #include "MagickCore/utility.h"
56 #include "MagickCore/utility-private.h"
57 
58 /*
59   Define declarations.
60 */
61 #define MaxExceptionList  64
62 
63 /*
64   Forward declarations.
65 */
66 #if defined(__cplusplus) || defined(c_plusplus)
67 extern "C" {
68 #endif
69 
70 static void
71   DefaultErrorHandler(const ExceptionType,const char *,const char *),
72   DefaultFatalErrorHandler(const ExceptionType,const char *,const char *),
73   DefaultWarningHandler(const ExceptionType,const char *,const char *);
74 
75 #if defined(__cplusplus) || defined(c_plusplus)
76 }
77 #endif
78 
79 /*
80   Global declarations.
81 */
82 static ErrorHandler
83   error_handler = DefaultErrorHandler;
84 
85 static FatalErrorHandler
86   fatal_error_handler = DefaultFatalErrorHandler;
87 
88 static WarningHandler
89   warning_handler = DefaultWarningHandler;
90 
91 /*
92   Static declarations.
93 */
94 static SemaphoreInfo
95   *exception_semaphore = (SemaphoreInfo *) NULL;
96 
97 /*
98 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99 %                                                                             %
100 %                                                                             %
101 %                                                                             %
102 %   A c q u i r e E x c e p t i o n I n f o                                   %
103 %                                                                             %
104 %                                                                             %
105 %                                                                             %
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107 %
108 %  AcquireExceptionInfo() allocates the ExceptionInfo structure.
109 %
110 %  The format of the AcquireExceptionInfo method is:
111 %
112 %      ExceptionInfo *AcquireExceptionInfo(void)
113 %
114 */
AcquireExceptionInfo(void)115 MagickExport ExceptionInfo *AcquireExceptionInfo(void)
116 {
117   ExceptionInfo
118     *exception;
119 
120   exception=(ExceptionInfo *) AcquireCriticalMemory(sizeof(*exception));
121   InitializeExceptionInfo(exception);
122   exception->relinquish=MagickTrue;
123   return(exception);
124 }
125 
126 /*
127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
128 %                                                                             %
129 %                                                                             %
130 %                                                                             %
131 %   C l e a r M a g i c k E x c e p t i o n                                   %
132 %                                                                             %
133 %                                                                             %
134 %                                                                             %
135 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
136 %
137 %  ClearMagickException() clears any exception that may not have been caught
138 %  yet.
139 %
140 %  The format of the ClearMagickException method is:
141 %
142 %      ClearMagickException(ExceptionInfo *exception)
143 %
144 %  A description of each parameter follows:
145 %
146 %    o exception: the exception info.
147 %
148 */
149 
DestroyExceptionElement(void * exception)150 static void *DestroyExceptionElement(void *exception)
151 {
152   ExceptionInfo
153     *p;
154 
155   p=(ExceptionInfo *) exception;
156   if (p->reason != (char *) NULL)
157     p->reason=DestroyString(p->reason);
158   if (p->description != (char *) NULL)
159     p->description=DestroyString(p->description);
160   p=(ExceptionInfo *) RelinquishMagickMemory(p);
161   return((void *) NULL);
162 }
163 
ClearMagickException(ExceptionInfo * exception)164 MagickExport void ClearMagickException(ExceptionInfo *exception)
165 {
166   assert(exception != (ExceptionInfo *) NULL);
167   assert(exception->signature == MagickCoreSignature);
168   if (exception->exceptions == (void *) NULL)
169     return;
170   LockSemaphoreInfo(exception->semaphore);
171   ClearLinkedList((LinkedListInfo *) exception->exceptions,
172     DestroyExceptionElement);
173   exception->severity=UndefinedException;
174   exception->reason=(char *) NULL;
175   exception->description=(char *) NULL;
176   UnlockSemaphoreInfo(exception->semaphore);
177   errno=0;
178 }
179 
180 /*
181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
182 %                                                                             %
183 %                                                                             %
184 %                                                                             %
185 %   C a t c h E x c e p t i o n                                               %
186 %                                                                             %
187 %                                                                             %
188 %                                                                             %
189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
190 %
191 %  CatchException() returns if no exceptions is found otherwise it reports
192 %  the exception as a warning, error, or fatal depending on the severity.
193 %
194 %  The format of the CatchException method is:
195 %
196 %      CatchException(ExceptionInfo *exception)
197 %
198 %  A description of each parameter follows:
199 %
200 %    o exception: the exception info.
201 %
202 */
CatchException(ExceptionInfo * exception)203 MagickExport void CatchException(ExceptionInfo *exception)
204 {
205   LinkedListInfo
206     *exceptions;
207 
208   const ExceptionInfo
209     *p;
210 
211   ssize_t
212     i;
213 
214   assert(exception != (ExceptionInfo *) NULL);
215   assert(exception->signature == MagickCoreSignature);
216   if (exception->exceptions  == (void *) NULL)
217     return;
218   LockSemaphoreInfo(exception->semaphore);
219   exceptions=(LinkedListInfo *) exception->exceptions;
220   ResetLinkedListIterator(exceptions);
221   p=(const ExceptionInfo *) GetNextValueInLinkedList(exceptions);
222   for (i=0; p != (const ExceptionInfo *) NULL; i++)
223   {
224     if ((p->severity >= WarningException) && (p->severity < ErrorException))
225       MagickWarning(p->severity,p->reason,p->description);
226     if ((p->severity >= ErrorException) && (p->severity < FatalErrorException))
227       MagickError(p->severity,p->reason,p->description);
228     if (p->severity >= FatalErrorException)
229       MagickFatalError(p->severity,p->reason,p->description);
230     p=(const ExceptionInfo *) GetNextValueInLinkedList(exceptions);
231   }
232   UnlockSemaphoreInfo(exception->semaphore);
233   ClearMagickException(exception);
234 }
235 
236 /*
237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238 %                                                                             %
239 %                                                                             %
240 %                                                                             %
241 %   C l o n e E x c e p t i o n I n f o                                       %
242 %                                                                             %
243 %                                                                             %
244 %                                                                             %
245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
246 %
247 %  CloneExceptionInfo() clones the ExceptionInfo structure.
248 %
249 %  The format of the CloneExceptionInfo method is:
250 %
251 %      ExceptionInfo *CloneException(ExceptionInfo *exception)
252 %
253 %  A description of each parameter follows:
254 %
255 %    o exception: the exception info.
256 %
257 */
CloneExceptionInfo(ExceptionInfo * exception)258 MagickExport ExceptionInfo *CloneExceptionInfo(ExceptionInfo *exception)
259 {
260   ExceptionInfo
261     *clone_exception;
262 
263   clone_exception=(ExceptionInfo *) AcquireCriticalMemory(sizeof(*exception));
264   InitializeExceptionInfo(clone_exception);
265   InheritException(clone_exception,exception);
266   clone_exception->relinquish=MagickTrue;
267   return(clone_exception);
268 }
269 
270 /*
271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
272 %                                                                             %
273 %                                                                             %
274 %                                                                             %
275 +   D e f a u l t E r r o r H a n d l e r                                     %
276 %                                                                             %
277 %                                                                             %
278 %                                                                             %
279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280 %
281 %  DefaultErrorHandler() displays an error reason.
282 %
283 %  The format of the DefaultErrorHandler method is:
284 %
285 %      void MagickError(const ExceptionType severity,const char *reason,
286 %        const char *description)
287 %
288 %  A description of each parameter follows:
289 %
290 %    o severity: Specifies the numeric error category.
291 %
292 %    o reason: Specifies the reason to display before terminating the
293 %      program.
294 %
295 %    o description: Specifies any description to the reason.
296 %
297 */
DefaultErrorHandler(const ExceptionType magick_unused (severity),const char * reason,const char * description)298 static void DefaultErrorHandler(const ExceptionType magick_unused(severity),
299   const char *reason,const char *description)
300 {
301   magick_unreferenced(severity);
302 
303   if (reason == (char *) NULL)
304     return;
305   (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
306   if (description != (char *) NULL)
307     (void) FormatLocaleFile(stderr," (%s)",description);
308   (void) FormatLocaleFile(stderr,".\n");
309   (void) fflush(stderr);
310 }
311 
312 /*
313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314 %                                                                             %
315 %                                                                             %
316 %                                                                             %
317 +   D e f a u l t F a t a l E r r o r H a n d l e r                           %
318 %                                                                             %
319 %                                                                             %
320 %                                                                             %
321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322 %
323 %  DefaultFatalErrorHandler() displays an error reason and then terminates the
324 %  program.
325 %
326 %  The format of the DefaultFatalErrorHandler method is:
327 %
328 %      void MagickFatalError(const ExceptionType severity,const char *reason,
329 %        const char *description)
330 %
331 %  A description of each parameter follows:
332 %
333 %    o severity: Specifies the numeric error category.
334 %
335 %    o reason: Specifies the reason to display before terminating the program.
336 %
337 %    o description: Specifies any description to the reason.
338 %
339 */
DefaultFatalErrorHandler(const ExceptionType severity,const char * reason,const char * description)340 static void DefaultFatalErrorHandler(const ExceptionType severity,
341   const char *reason,const char *description)
342 {
343   if (reason == (char *) NULL)
344     return;
345   (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
346   if (description != (char *) NULL)
347     (void) FormatLocaleFile(stderr," (%s)",description);
348   (void) FormatLocaleFile(stderr,".\n");
349   (void) fflush(stderr);
350   MagickCoreTerminus();
351   exit((int) (severity-FatalErrorException)+1);
352 }
353 
354 /*
355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356 %                                                                             %
357 %                                                                             %
358 %                                                                             %
359 +   D e f a u l t W a r n i n g H a n d l e r                                 %
360 %                                                                             %
361 %                                                                             %
362 %                                                                             %
363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 %
365 %  DefaultWarningHandler() displays a warning reason.
366 %
367 %  The format of the DefaultWarningHandler method is:
368 %
369 %      void DefaultWarningHandler(const ExceptionType severity,
370 %        const char *reason,const char *description)
371 %
372 %  A description of each parameter follows:
373 %
374 %    o severity: Specifies the numeric warning category.
375 %
376 %    o reason: Specifies the reason to display before terminating the
377 %      program.
378 %
379 %    o description: Specifies any description to the reason.
380 %
381 */
DefaultWarningHandler(const ExceptionType magick_unused (severity),const char * reason,const char * description)382 static void DefaultWarningHandler(const ExceptionType magick_unused(severity),
383   const char *reason,const char *description)
384 {
385   magick_unreferenced(severity);
386 
387   if (reason == (char *) NULL)
388     return;
389   (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
390   if (description != (char *) NULL)
391     (void) FormatLocaleFile(stderr," (%s)",description);
392   (void) FormatLocaleFile(stderr,".\n");
393   (void) fflush(stderr);
394 }
395 
396 /*
397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398 %                                                                             %
399 %                                                                             %
400 %                                                                             %
401 %   D e s t r o y E x c e p t i o n I n f o                                   %
402 %                                                                             %
403 %                                                                             %
404 %                                                                             %
405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
406 %
407 %  DestroyExceptionInfo() deallocates memory associated with an exception.
408 %
409 %  The format of the DestroyExceptionInfo method is:
410 %
411 %      ExceptionInfo *DestroyExceptionInfo(ExceptionInfo *exception)
412 %
413 %  A description of each parameter follows:
414 %
415 %    o exception: the exception info.
416 %
417 */
DestroyExceptionInfo(ExceptionInfo * exception)418 MagickExport ExceptionInfo *DestroyExceptionInfo(ExceptionInfo *exception)
419 {
420   MagickBooleanType
421     relinquish;
422 
423   assert(exception != (ExceptionInfo *) NULL);
424   assert(exception->signature == MagickCoreSignature);
425   if (exception->semaphore == (SemaphoreInfo *) NULL)
426     ActivateSemaphoreInfo(&exception->semaphore);
427   LockSemaphoreInfo(exception->semaphore);
428   exception->severity=UndefinedException;
429   if (exception->relinquish != MagickFalse)
430     {
431       exception->signature=(~MagickCoreSignature);
432       if (exception->exceptions != (void *) NULL)
433         exception->exceptions=(void *) DestroyLinkedList((LinkedListInfo *)
434           exception->exceptions,DestroyExceptionElement);
435     }
436   else
437     if (exception->exceptions != (void *) NULL)
438       ClearLinkedList((LinkedListInfo *) exception->exceptions,
439         DestroyExceptionElement);
440   relinquish=exception->relinquish;
441   UnlockSemaphoreInfo(exception->semaphore);
442   if (relinquish != MagickFalse)
443     {
444       RelinquishSemaphoreInfo(&exception->semaphore);
445       exception=(ExceptionInfo *) RelinquishMagickMemory(exception);
446     }
447   return(exception);
448 }
449 
450 /*
451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
452 %                                                                             %
453 %                                                                             %
454 %                                                                             %
455 +   E x e c e p t i o n C o m p o n e n t G e n e s i s                       %
456 %                                                                             %
457 %                                                                             %
458 %                                                                             %
459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
460 %
461 %  ExceptionComponentGenesis() instantiates the exception component.
462 %
463 %  The format of the ExceptionComponentGenesis method is:
464 %
465 %      MagickBooleanType ExceptionComponentGenesis(void)
466 %
467 */
ExceptionComponentGenesis(void)468 MagickPrivate MagickBooleanType ExceptionComponentGenesis(void)
469 {
470   if (exception_semaphore == (SemaphoreInfo *) NULL)
471     exception_semaphore=AcquireSemaphoreInfo();
472   return(MagickTrue);
473 }
474 
475 /*
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477 %                                                                             %
478 %                                                                             %
479 %                                                                             %
480 +   E x c e p t i o n C o m p o n e n t T e r m i n u s                       %
481 %                                                                             %
482 %                                                                             %
483 %                                                                             %
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 %
486 %  ExceptionComponentTerminus() destroys the exception component.
487 %
488 %  The format of the ExceptionComponentTerminus method is:
489 %
490 %      void ExceptionComponentTerminus(void)
491 %
492 */
ExceptionComponentTerminus(void)493 MagickPrivate void ExceptionComponentTerminus(void)
494 {
495   if (exception_semaphore == (SemaphoreInfo *) NULL)
496     ActivateSemaphoreInfo(&exception_semaphore);
497   LockSemaphoreInfo(exception_semaphore);
498   UnlockSemaphoreInfo(exception_semaphore);
499   RelinquishSemaphoreInfo(&exception_semaphore);
500 }
501 
502 /*
503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
504 %                                                                             %
505 %                                                                             %
506 %                                                                             %
507 %   G e t E x c e p t i o n M e s s a g e                                     %
508 %                                                                             %
509 %                                                                             %
510 %                                                                             %
511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512 %
513 %  GetExceptionMessage() returns the error message defined by the specified
514 %  error code.
515 %
516 %  The format of the GetExceptionMessage method is:
517 %
518 %      char *GetExceptionMessage(const int error)
519 %
520 %  A description of each parameter follows:
521 %
522 %    o error: the error code.
523 %
524 */
GetExceptionMessage(const int error)525 MagickExport char *GetExceptionMessage(const int error)
526 {
527   char
528     exception[MagickPathExtent];
529 
530   *exception='\0';
531 #if defined(MAGICKCORE_HAVE_STRERROR_R)
532 #if !defined(MAGICKCORE_STRERROR_R_CHAR_P)
533   (void) strerror_r(error,exception,sizeof(exception));
534 #else
535   (void) CopyMagickString(exception,strerror_r(error,exception,
536     sizeof(exception)),sizeof(exception));
537 #endif
538 #else
539   (void) CopyMagickString(exception,strerror(error),sizeof(exception));
540 #endif
541   return(ConstantString(exception));
542 }
543 
544 /*
545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546 %                                                                             %
547 %                                                                             %
548 %                                                                             %
549 %   G e t L o c a l e E x c e p t i o n M e s s a g e                         %
550 %                                                                             %
551 %                                                                             %
552 %                                                                             %
553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
554 %
555 %  GetLocaleExceptionMessage() converts a enumerated exception severity and tag
556 %  to a message in the current locale.
557 %
558 %  The format of the GetLocaleExceptionMessage method is:
559 %
560 %      const char *GetLocaleExceptionMessage(const ExceptionType severity,
561 %        const char *tag)
562 %
563 %  A description of each parameter follows:
564 %
565 %    o severity: the severity of the exception.
566 %
567 %    o tag: the message tag.
568 %
569 */
570 
ExceptionSeverityToTag(const ExceptionType severity)571 static const char *ExceptionSeverityToTag(const ExceptionType severity)
572 {
573   switch (severity)
574   {
575     case ResourceLimitWarning: return("Resource/Limit/Warning/");
576     case TypeWarning: return("Type/Warning/");
577     case OptionWarning: return("Option/Warning/");
578     case DelegateWarning: return("Delegate/Warning/");
579     case MissingDelegateWarning: return("Missing/Delegate/Warning/");
580     case CorruptImageWarning: return("Corrupt/Image/Warning/");
581     case FileOpenWarning: return("File/Open/Warning/");
582     case BlobWarning: return("Blob/Warning/");
583     case StreamWarning: return("Stream/Warning/");
584     case CacheWarning: return("Cache/Warning/");
585     case CoderWarning: return("Coder/Warning/");
586     case FilterWarning: return("Filter/Warning/");
587     case ModuleWarning: return("Module/Warning/");
588     case DrawWarning: return("Draw/Warning/");
589     case ImageWarning: return("Image/Warning/");
590     case WandWarning: return("Wand/Warning/");
591     case XServerWarning: return("XServer/Warning/");
592     case MonitorWarning: return("Monitor/Warning/");
593     case RegistryWarning: return("Registry/Warning/");
594     case ConfigureWarning: return("Configure/Warning/");
595     case PolicyWarning: return("Policy/Warning/");
596     case ResourceLimitError: return("Resource/Limit/Error/");
597     case TypeError: return("Type/Error/");
598     case OptionError: return("Option/Error/");
599     case DelegateError: return("Delegate/Error/");
600     case MissingDelegateError: return("Missing/Delegate/Error/");
601     case CorruptImageError: return("Corrupt/Image/Error/");
602     case FileOpenError: return("File/Open/Error/");
603     case BlobError: return("Blob/Error/");
604     case StreamError: return("Stream/Error/");
605     case CacheError: return("Cache/Error/");
606     case CoderError: return("Coder/Error/");
607     case FilterError: return("Filter/Error/");
608     case ModuleError: return("Module/Error/");
609     case DrawError: return("Draw/Error/");
610     case ImageError: return("Image/Error/");
611     case WandError: return("Wand/Error/");
612     case XServerError: return("XServer/Error/");
613     case MonitorError: return("Monitor/Error/");
614     case RegistryError: return("Registry/Error/");
615     case ConfigureError: return("Configure/Error/");
616     case PolicyError: return("Policy/Error/");
617     case ResourceLimitFatalError: return("Resource/Limit/FatalError/");
618     case TypeFatalError: return("Type/FatalError/");
619     case OptionFatalError: return("Option/FatalError/");
620     case DelegateFatalError: return("Delegate/FatalError/");
621     case MissingDelegateFatalError: return("Missing/Delegate/FatalError/");
622     case CorruptImageFatalError: return("Corrupt/Image/FatalError/");
623     case FileOpenFatalError: return("File/Open/FatalError/");
624     case BlobFatalError: return("Blob/FatalError/");
625     case StreamFatalError: return("Stream/FatalError/");
626     case CacheFatalError: return("Cache/FatalError/");
627     case CoderFatalError: return("Coder/FatalError/");
628     case FilterFatalError: return("Filter/FatalError/");
629     case ModuleFatalError: return("Module/FatalError/");
630     case DrawFatalError: return("Draw/FatalError/");
631     case ImageFatalError: return("Image/FatalError/");
632     case WandFatalError: return("Wand/FatalError/");
633     case XServerFatalError: return("XServer/FatalError/");
634     case MonitorFatalError: return("Monitor/FatalError/");
635     case RegistryFatalError: return("Registry/FatalError/");
636     case ConfigureFatalError: return("Configure/FatalError/");
637     case PolicyFatalError: return("Policy/FatalError/");
638     default: break;
639   }
640   return("");
641 }
642 
GetLocaleExceptionMessage(const ExceptionType severity,const char * tag)643 MagickExport const char *GetLocaleExceptionMessage(const ExceptionType severity,
644   const char *tag)
645 {
646   char
647     message[MagickPathExtent];
648 
649   const char
650     *locale_message;
651 
652   assert(tag != (const char *) NULL);
653   (void) FormatLocaleString(message,MagickPathExtent,"Exception/%s%s",
654     ExceptionSeverityToTag(severity),tag);
655   locale_message=GetLocaleMessage(message);
656   if (locale_message == (const char *) NULL)
657     return(tag);
658   if (locale_message == message)
659     return(tag);
660   return(locale_message);
661 }
662 
663 /*
664 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
665 %                                                                             %
666 %                                                                             %
667 %                                                                             %
668 %   I n h e r i t E x c e p t i o n                                           %
669 %                                                                             %
670 %                                                                             %
671 %                                                                             %
672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
673 %
674 %  InheritException() inherits an exception from a related exception.
675 %
676 %  The format of the InheritException method is:
677 %
678 %      InheritException(ExceptionInfo *exception,const ExceptionInfo *relative)
679 %
680 %  A description of each parameter follows:
681 %
682 %    o exception: the exception info.
683 %
684 %    o relative: the related exception info.
685 %
686 */
InheritException(ExceptionInfo * exception,const ExceptionInfo * relative)687 MagickExport void InheritException(ExceptionInfo *exception,
688   const ExceptionInfo *relative)
689 {
690   const ExceptionInfo
691     *p;
692 
693   assert(exception != (ExceptionInfo *) NULL);
694   assert(exception->signature == MagickCoreSignature);
695   assert(relative != (ExceptionInfo *) NULL);
696   assert(relative->signature == MagickCoreSignature);
697   assert(exception != relative);
698   if (relative->exceptions == (void *) NULL)
699     return;
700   LockSemaphoreInfo(relative->semaphore);
701   ResetLinkedListIterator((LinkedListInfo *) relative->exceptions);
702   p=(const ExceptionInfo *) GetNextValueInLinkedList((LinkedListInfo *)
703     relative->exceptions);
704   while (p != (const ExceptionInfo *) NULL)
705   {
706     (void) ThrowException(exception,p->severity,p->reason,p->description);
707     p=(const ExceptionInfo *) GetNextValueInLinkedList((LinkedListInfo *)
708       relative->exceptions);
709   }
710   UnlockSemaphoreInfo(relative->semaphore);
711 }
712 
713 /*
714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
715 %                                                                             %
716 %                                                                             %
717 %                                                                             %
718 %   I n i t i a l i z e t E x c e p t i o n I n f o                           %
719 %                                                                             %
720 %                                                                             %
721 %                                                                             %
722 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723 %
724 %  InitializeExceptionInfo() initializes an exception to default values.
725 %
726 %  The format of the InitializeExceptionInfo method is:
727 %
728 %      InitializeExceptionInfo(ExceptionInfo *exception)
729 %
730 %  A description of each parameter follows:
731 %
732 %    o exception: the exception info.
733 %
734 */
InitializeExceptionInfo(ExceptionInfo * exception)735 MagickPrivate void InitializeExceptionInfo(ExceptionInfo *exception)
736 {
737   assert(exception != (ExceptionInfo *) NULL);
738   (void) memset(exception,0,sizeof(*exception));
739   exception->severity=UndefinedException;
740   exception->exceptions=(void *) NewLinkedList(0);
741   exception->semaphore=AcquireSemaphoreInfo();
742   exception->signature=MagickCoreSignature;
743 }
744 
745 /*
746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
747 %                                                                             %
748 %                                                                             %
749 %                                                                             %
750 %   M a g i c k E r r o r                                                     %
751 %                                                                             %
752 %                                                                             %
753 %                                                                             %
754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
755 %
756 %  MagickError() calls the exception handler methods with an error reason.
757 %
758 %  The format of the MagickError method is:
759 %
760 %      void MagickError(const ExceptionType error,const char *reason,
761 %        const char *description)
762 %
763 %  A description of each parameter follows:
764 %
765 %    o exception: Specifies the numeric error category.
766 %
767 %    o reason: Specifies the reason to display before terminating the
768 %      program.
769 %
770 %    o description: Specifies any description to the reason.
771 %
772 */
MagickError(const ExceptionType error,const char * reason,const char * description)773 MagickExport void MagickError(const ExceptionType error,const char *reason,
774   const char *description)
775 {
776   if (error_handler != (ErrorHandler) NULL)
777     (*error_handler)(error,reason,description);
778 }
779 
780 /*
781 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
782 %                                                                             %
783 %                                                                             %
784 %                                                                             %
785 %   M a g i c k F a t al E r r o r                                            %
786 %                                                                             %
787 %                                                                             %
788 %                                                                             %
789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790 %
791 %  MagickFatalError() calls the fatal exception handler methods with an error
792 %  reason.
793 %
794 %  The format of the MagickError method is:
795 %
796 %      void MagickFatalError(const ExceptionType error,const char *reason,
797 %        const char *description)
798 %
799 %  A description of each parameter follows:
800 %
801 %    o exception: Specifies the numeric error category.
802 %
803 %    o reason: Specifies the reason to display before terminating the
804 %      program.
805 %
806 %    o description: Specifies any description to the reason.
807 %
808 */
MagickFatalError(const ExceptionType error,const char * reason,const char * description)809 MagickExport void MagickFatalError(const ExceptionType error,const char *reason,
810   const char *description)
811 {
812   if (fatal_error_handler != (ErrorHandler) NULL)
813     (*fatal_error_handler)(error,reason,description);
814 }
815 
816 /*
817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
818 %                                                                             %
819 %                                                                             %
820 %                                                                             %
821 %   M a g i c k W a r n i n g                                                 %
822 %                                                                             %
823 %                                                                             %
824 %                                                                             %
825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
826 %
827 %  MagickWarning() calls the warning handler methods with a warning reason.
828 %
829 %  The format of the MagickWarning method is:
830 %
831 %      void MagickWarning(const ExceptionType warning,const char *reason,
832 %        const char *description)
833 %
834 %  A description of each parameter follows:
835 %
836 %    o warning: the warning severity.
837 %
838 %    o reason: Define the reason for the warning.
839 %
840 %    o description: Describe the warning.
841 %
842 */
MagickWarning(const ExceptionType warning,const char * reason,const char * description)843 MagickExport void MagickWarning(const ExceptionType warning,const char *reason,
844   const char *description)
845 {
846   if (warning_handler != (WarningHandler) NULL)
847     (*warning_handler)(warning,reason,description);
848 }
849 
850 /*
851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
852 %                                                                             %
853 %                                                                             %
854 %                                                                             %
855 %   S e t E r r o r H a n d l e r                                             %
856 %                                                                             %
857 %                                                                             %
858 %                                                                             %
859 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
860 %
861 %  SetErrorHandler() sets the exception handler to the specified method
862 %  and returns the previous exception handler.
863 %
864 %  The format of the SetErrorHandler method is:
865 %
866 %      ErrorHandler SetErrorHandler(ErrorHandler handler)
867 %
868 %  A description of each parameter follows:
869 %
870 %    o handler: the method to handle errors.
871 %
872 */
SetErrorHandler(ErrorHandler handler)873 MagickExport ErrorHandler SetErrorHandler(ErrorHandler handler)
874 {
875   ErrorHandler
876     previous_handler;
877 
878   if (exception_semaphore == (SemaphoreInfo *) NULL)
879     ActivateSemaphoreInfo(&exception_semaphore);
880   LockSemaphoreInfo(exception_semaphore);
881   previous_handler=error_handler;
882   error_handler=handler;
883   UnlockSemaphoreInfo(exception_semaphore);
884   return(previous_handler);
885 }
886 
887 /*
888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
889 %                                                                             %
890 %                                                                             %
891 %                                                                             %
892 %   S e t F a t a l E r r o r H a n d l e r                                   %
893 %                                                                             %
894 %                                                                             %
895 %                                                                             %
896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
897 %
898 %  SetFatalErrorHandler() sets the fatal exception handler to the specified
899 %  method and returns the previous fatal exception handler.
900 %
901 %  The format of the SetErrorHandler method is:
902 %
903 %      ErrorHandler SetErrorHandler(ErrorHandler handler)
904 %
905 %  A description of each parameter follows:
906 %
907 %    o handler: the method to handle errors.
908 %
909 */
SetFatalErrorHandler(FatalErrorHandler handler)910 MagickExport FatalErrorHandler SetFatalErrorHandler(FatalErrorHandler handler)
911 {
912   FatalErrorHandler
913     previous_handler;
914 
915   if (exception_semaphore == (SemaphoreInfo *) NULL)
916     ActivateSemaphoreInfo(&exception_semaphore);
917   LockSemaphoreInfo(exception_semaphore);
918   previous_handler=fatal_error_handler;
919   fatal_error_handler=handler;
920   UnlockSemaphoreInfo(exception_semaphore);
921   return(previous_handler);
922 }
923 
924 /*
925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
926 %                                                                             %
927 %                                                                             %
928 %                                                                             %
929 %   S e t W a r n i n g H a n d l e r                                         %
930 %                                                                             %
931 %                                                                             %
932 %                                                                             %
933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
934 %
935 %  SetWarningHandler() sets the warning handler to the specified method
936 %  and returns the previous warning handler.
937 %
938 %  The format of the SetWarningHandler method is:
939 %
940 %      ErrorHandler SetWarningHandler(ErrorHandler handler)
941 %
942 %  A description of each parameter follows:
943 %
944 %    o handler: the method to handle warnings.
945 %
946 */
SetWarningHandler(WarningHandler handler)947 MagickExport WarningHandler SetWarningHandler(WarningHandler handler)
948 {
949   WarningHandler
950     previous_handler;
951 
952   if (exception_semaphore == (SemaphoreInfo *) NULL)
953     ActivateSemaphoreInfo(&exception_semaphore);
954   LockSemaphoreInfo(exception_semaphore);
955   previous_handler=warning_handler;
956   warning_handler=handler;
957   UnlockSemaphoreInfo(exception_semaphore);
958   return(previous_handler);
959 }
960 
961 /*
962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
963 %                                                                             %
964 %                                                                             %
965 %                                                                             %
966 %   T h r o w E x c e p t i o n                                               %
967 %                                                                             %
968 %                                                                             %
969 %                                                                             %
970 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
971 %
972 %  ThrowException() throws an exception with the specified severity code,
973 %  reason, and optional description.
974 %
975 %  The format of the ThrowException method is:
976 %
977 %      MagickBooleanType ThrowException(ExceptionInfo *exception,
978 %        const ExceptionType severity,const char *reason,
979 %        const char *description)
980 %
981 %  A description of each parameter follows:
982 %
983 %    o exception: the exception info.
984 %
985 %    o severity: the severity of the exception.
986 %
987 %    o reason: the reason for the exception.
988 %
989 %    o description: the exception description.
990 %
991 */
ThrowException(ExceptionInfo * exception,const ExceptionType severity,const char * reason,const char * description)992 MagickExport MagickBooleanType ThrowException(ExceptionInfo *exception,
993   const ExceptionType severity,const char *reason,const char *description)
994 {
995   LinkedListInfo
996     *exceptions;
997 
998   ExceptionInfo
999     *p;
1000 
1001   assert(exception != (ExceptionInfo *) NULL);
1002   assert(exception->signature == MagickCoreSignature);
1003   LockSemaphoreInfo(exception->semaphore);
1004   exceptions=(LinkedListInfo *) exception->exceptions;
1005   if (GetNumberOfElementsInLinkedList(exceptions) > MaxExceptionList)
1006     {
1007       if (severity < ErrorException)
1008         {
1009           UnlockSemaphoreInfo(exception->semaphore);
1010           return(MagickTrue);
1011         }
1012       p=(ExceptionInfo *) GetLastValueInLinkedList(exceptions);
1013       if (p->severity >= ErrorException)
1014         {
1015           UnlockSemaphoreInfo(exception->semaphore);
1016           return(MagickTrue);
1017         }
1018     }
1019   p=(ExceptionInfo *) GetLastValueInLinkedList(exceptions);
1020   if ((p != (ExceptionInfo *) NULL) && (p->severity == severity) &&
1021       (LocaleCompare(exception->reason,reason) == 0) &&
1022       (LocaleCompare(exception->description,description) == 0))
1023     {
1024       UnlockSemaphoreInfo(exception->semaphore);
1025       return(MagickTrue);
1026     }
1027   p=(ExceptionInfo *) AcquireMagickMemory(sizeof(*p));
1028   if (p == (ExceptionInfo *) NULL)
1029     {
1030       UnlockSemaphoreInfo(exception->semaphore);
1031       ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1032     }
1033   (void) memset(p,0,sizeof(*p));
1034   p->severity=severity;
1035   if (reason != (const char *) NULL)
1036     p->reason=ConstantString(reason);
1037   if (description != (const char *) NULL)
1038     p->description=ConstantString(description);
1039   p->signature=MagickCoreSignature;
1040   (void) AppendValueToLinkedList(exceptions,p);
1041   if (p->severity > exception->severity)
1042     {
1043       exception->severity=p->severity;
1044       exception->reason=p->reason;
1045       exception->description=p->description;
1046     }
1047   UnlockSemaphoreInfo(exception->semaphore);
1048   if (GetNumberOfElementsInLinkedList(exceptions) == MaxExceptionList)
1049     (void) ThrowMagickException(exception,GetMagickModule(),
1050       ResourceLimitWarning,"TooManyExceptions",
1051       "(exception processing is suspended)");
1052   return(MagickTrue);
1053 }
1054 
1055 /*
1056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1057 %                                                                             %
1058 %                                                                             %
1059 %                                                                             %
1060 %   T h r o w M a g i c k E x c e p t i o n                                   %
1061 %                                                                             %
1062 %                                                                             %
1063 %                                                                             %
1064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1065 %
1066 %  ThrowMagickException logs an exception as determined by the log
1067 %  configuration file.  If an error occurs, MagickFalse is returned
1068 %  otherwise MagickTrue.
1069 %
1070 %  The format of the ThrowMagickException method is:
1071 %
1072 %      MagickBooleanType ThrowFileException(ExceptionInfo *exception,
1073 %        const char *module,const char *function,const size_t line,
1074 %        const ExceptionType severity,const char *tag,const char *format,...)
1075 %
1076 %  A description of each parameter follows:
1077 %
1078 %    o exception: the exception info.
1079 %
1080 %    o filename: the source module filename.
1081 %
1082 %    o function: the function name.
1083 %
1084 %    o line: the line number of the source module.
1085 %
1086 %    o severity: Specifies the numeric error category.
1087 %
1088 %    o tag: the locale tag.
1089 %
1090 %    o format: the output format.
1091 %
1092 */
1093 
ThrowMagickExceptionList(ExceptionInfo * exception,const char * module,const char * function,const size_t line,const ExceptionType severity,const char * tag,const char * format,va_list operands)1094 MagickExport MagickBooleanType ThrowMagickExceptionList(
1095   ExceptionInfo *exception,const char *module,const char *function,
1096   const size_t line,const ExceptionType severity,const char *tag,
1097   const char *format,va_list operands)
1098 {
1099   char
1100     message[MagickPathExtent],
1101     path[MagickPathExtent],
1102     reason[MagickPathExtent];
1103 
1104   const char
1105     *locale,
1106     *type;
1107 
1108   int
1109     n;
1110 
1111   MagickBooleanType
1112     status;
1113 
1114   size_t
1115     length;
1116 
1117   assert(exception != (ExceptionInfo *) NULL);
1118   assert(exception->signature == MagickCoreSignature);
1119   locale=GetLocaleExceptionMessage(severity,tag);
1120   (void) CopyMagickString(reason,locale,MagickPathExtent);
1121   (void) ConcatenateMagickString(reason," ",MagickPathExtent);
1122   length=strlen(reason);
1123 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
1124   n=vsnprintf(reason+length,MagickPathExtent-length,format,operands);
1125 #else
1126   n=vsprintf(reason+length,format,operands);
1127 #endif
1128   if (n < 0)
1129     reason[MagickPathExtent-1]='\0';
1130   status=LogMagickEvent(ExceptionEvent,module,function,line,"%s",reason);
1131   GetPathComponent(module,TailPath,path);
1132   type="undefined";
1133   if ((severity >= WarningException) && (severity < ErrorException))
1134     type="warning";
1135   if ((severity >= ErrorException) && (severity < FatalErrorException))
1136     type="error";
1137   if (severity >= FatalErrorException)
1138     type="fatal";
1139   (void) FormatLocaleString(message,MagickPathExtent,"%s @ %s/%s/%s/%.20g",
1140     reason,type,path,function,(double) line);
1141   (void) ThrowException(exception,severity,message,(char *) NULL);
1142   return(status);
1143 }
1144 
ThrowMagickException(ExceptionInfo * exception,const char * module,const char * function,const size_t line,const ExceptionType severity,const char * tag,const char * format,...)1145 MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception,
1146   const char *module,const char *function,const size_t line,
1147   const ExceptionType severity,const char *tag,const char *format,...)
1148 {
1149   MagickBooleanType
1150     status;
1151 
1152   va_list
1153     operands;
1154 
1155   va_start(operands,format);
1156   status=ThrowMagickExceptionList(exception,module,function,line,severity,tag,
1157     format,operands);
1158   va_end(operands);
1159   return(status);
1160 }
1161