1 /** Interface for NSException for GNUStep
2    Copyright (C) 1995, 1996 Free Software Foundation, Inc.
3 
4    Written by:  Adam Fedor <fedor@boulder.colorado.edu>
5    Date: 1995
6 
7    This file is part of the GNUstep Base Library.
8 
9    This library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU Lesser General Public
11    License as published by the Free Software Foundation; either
12    version 2 of the License, or (at your option) any later version.
13 
14    This library is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    Lesser General Public License for more details.
18 
19    You should have received a copy of the GNU Lesser General Public
20    License along with this library; if not, write to the Free
21    Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22    Boston, MA 02110 USA.
23 
24     <title>NSException and NSAssertionHandler class reference</title>
25 
26     AutogsdocSource: NSAssertionHandler.m
27     AutogsdocSource: NSException.m
28 
29    */
30 
31 #ifndef __NSException_h_GNUSTEP_BASE_INCLUDE
32 #define __NSException_h_GNUSTEP_BASE_INCLUDE
33 #import	<GNUstepBase/GSVersionMacros.h>
34 #import	<GNUstepBase/GSConfig.h>
35 
36 #if     defined(_NATIVE_OBJC_EXCEPTIONS)
37 #  define USER_NATIVE_OBJC_EXCEPTIONS       1
38 #elif defined(BASE_NATIVE_OBJC_EXCEPTIONS) && defined(OBJC_ZEROCOST_EXCEPTIONS)
39 #  define USER_NATIVE_OBJC_EXCEPTIONS       1
40 #  define _NATIVE_OBJC_EXCEPTIONS           1
41 #endif
42 
43 #if     !BASE_NATIVE_OBJC_EXCEPTIONS && USER_NATIVE_OBJC_EXCEPTIONS
44 #error "There are two separate exception handling mechanisms available ... one based on the standard setjmp() function (which does not require special compiler support), and one 'native' version where the compiler manages the exception handling.  If you try to use both in the same executable, exception handlers will not work... which can be pretty disastrous.  This error is telling you that the gnustep-base library was built using one form of exception handling, but that the gnustep-make package you are using is building code to use the other form of exception handling ... with the consequence that exception handling would be broken in the program you are building.  So, somehow your gnustep-base and gnustep-make package are incompatible, and you need to replace one of them with a version configured to match the other."
45 #if     BASE_NATIVE_OBJC_EXCEPTIONS
46 #error  "gnustep-base is configured to use 'native' exceptions, but you are building for 'traditional' exceptions."
47 #else
48 #error  "gnustep-base is configured to use 'traditional' exceptions, but you are building for 'native' exceptions."
49 #endif
50 #endif
51 
52 #import	<Foundation/NSString.h>
53 
54 #include <setjmp.h>
55 #include <stdarg.h>
56 
57 #if	defined(__WIN64__)
58 /* This hack is to deal with the fact that currently (June 2016) the
59  * implementation of longjmp in mingw-w64  sometimes crashes in msvcrt.dll
60  * but the builtin version provided by gcc seems to work.
61  */
62 #define	setjmp(X)	__builtin_setjmp(X)
63 #define	longjmp(X,Y)	__builtin_longjmp(X,Y)
64 #endif
65 
66 #if	defined(__cplusplus)
67 extern "C" {
68 #endif
69 
70 @class NSDictionary;
71 
72 /**
73    <p>
74    The <code>NSException</code> class helps manage errors in a program. It
75    provides a mechanism for lower-level methods to provide information about
76    problems to higher-level methods, which more often than not, have a
77    better ability to decide what to do about the problems.
78    </p>
79    <p>
80    Exceptions are typically handled by enclosing a sensitive section
81    of code inside the macros <code>NS_DURING</code> and <code>NS_HANDLER</code>,
82    and then handling any problems after this, up to the
83    <code>NS_ENDHANDLER</code> macro:
84    </p>
85    <example>
86    NS_DURING
87     code that might cause an exception
88    NS_HANDLER
89     code that deals with the exception. If this code cannot deal with
90     it, you can re-raise the exception like this
91     [localException raise]
92     so the next higher level of code can handle it
93    NS_ENDHANDLER
94    </example>
95    <p>
96    The local variable <code>localException</code> is the name of the exception
97    object you can use in the <code>NS_HANDLER</code> section.
98    The easiest way to cause an exception is using the +raise:format:,...
99    method.
100    </p>
101    <p>
102    If there is no NS_HANDLER ... NS_ENDHANDLER block enclosing (directly or
103    indirectly) code where an exception is raised, then control passes to
104    the <em>uncaught exception handler</em> function and the program is
105    then terminated.<br />
106    The uncaught exception handler is set using NSSetUncaughtExceptionHandler()
107    and if not set, defaults to a function which will simply print an error
108    message before the program terminates.
109    </p>
110 */
111 @interface NSException : NSObject <NSCoding, NSCopying>
112 {
113 #if	GS_EXPOSE(NSException)
114 @private
115   NSString *_e_name;
116   NSString *_e_reason;
117   void *_reserved;
118 #endif
119 }
120 
121 /**
122  * Create an an exception object with a name, reason and a dictionary
123  * userInfo which can be used to provide additional information or
124  * access to objects needed to handle the exception. After the
125  * exception is created you must -raise it.
126  */
127 + (NSException*) exceptionWithName: (NSString*)name
128 			    reason: (NSString*)reason
129 			  userInfo: (NSDictionary*)userInfo;
130 
131 /**
132  * Creates an exception with a name and a reason using the
133  * format string and any additional arguments. The exception is then
134  * <em>raised</em> using the -raise method.
135  */
136 + (void) raise: (NSString*)name
137 	format: (NSString*)format,...
138   NS_FORMAT_FUNCTION(2,3) GS_NORETURN_METHOD;
139 
140 /**
141  * Creates an exception with a name and a reason string using the
142  * format string and additional arguments specified as a variable
143  * argument list argList. The exception is then <em>raised</em>
144  * using the -raise method.
145  */
146 + (void) raise: (NSString*)name
147 	format: (NSString*)format
148      arguments: (va_list)argList
149   NS_FORMAT_FUNCTION(2,0) GS_NORETURN_METHOD;
150 
151 #if OS_API_VERSION(MAC_OS_X_VERSION_10_5,GS_API_LATEST) && GS_API_VERSION( 11501,GS_API_LATEST)
152 /** Returns an array of the call stack return addresses at the point when
153  * the exception was raised.  Re-raising the exception does not change
154  * this value.
155  */
156 - (NSArray*) callStackReturnAddresses;
157 #endif
158 
159 #if OS_API_VERSION(MAC_OS_X_VERSION_10_6,GS_API_LATEST) && GS_API_VERSION( 11903,GS_API_LATEST)
160 /**
161  * Returns an array of the symbolic names of the call stack return addresses.
162  * Note that, on some platforms, symbols are only exported in
163  * position-independent code and so these may only return numeric addresses for
164  * code in static libraries or the main application.
165  */
166 - (NSArray*) callStackSymbols;
167 #endif
168 
169 /**
170  * <init/>Initializes a newly allocated NSException object with a
171  * name, reason and a dictionary userInfo.
172  */
173 - (id) initWithName: (NSString*)name
174 	     reason: (NSString*)reason
175 	   userInfo: (NSDictionary*)userInfo;
176 
177 /** Returns the name of the exception. */
178 - (NSString*) name;
179 
180 /**
181  * Raises the exception. All code following the raise will not be
182  * executed and program control will be transfered to the closest
183  * calling method which encapsulates the exception code in an
184  * NS_DURING macro.<br />
185  * If the exception was not caught in a macro, the currently set
186  * uncaught exception handler is called to perform final logging
187  * and the program is then terminated.<br />
188  * If the uncaught exception handler fails to terminate the program,
189  * then the default behavior is to terminate the program as soon as
190  * the uncaught exception handler function returns.<br />
191  * NB. all other exception raising methods call this one, so if you
192  * want to set a breakpoint when debugging, set it in this method.
193  */
194 - (void) raise GS_NORETURN_METHOD;
195 
196 /** Returns the exception reason. */
197 - (NSString*) reason;
198 
199 /** Returns the exception userInfo dictionary.<br />
200  */
201 - (NSDictionary*) userInfo;
202 
203 @end
204 
205 /** An exception when character set conversion fails.
206  */
207 GS_EXPORT NSString* const NSCharacterConversionException;
208 
209 /** Attempt to use an invalidated destination.
210  */
211 GS_EXPORT NSString* const NSDestinationInvalidException;
212 
213 /** A generic exception for general purpose usage.
214  */
215 GS_EXPORT NSString* const NSGenericException;
216 
217 /** An exception for cases where unexpected state is detected within an object.
218  */
219 GS_EXPORT NSString* const NSInternalInconsistencyException;
220 
221 /** An exception used when an invalid argument is passed to a method
222  * or function.
223  */
224 GS_EXPORT NSString* const NSInvalidArgumentException;
225 
226 /** Attempt to use a receive port which has been invalidated.
227  */
228 GS_EXPORT NSString * const NSInvalidReceivePortException;
229 
230 /** Attempt to use a send port which has been invalidated.
231  */
232 GS_EXPORT NSString * const NSInvalidSendPortException;
233 
234 /** An exception used when the system fails to allocate required memory.
235  */
236 GS_EXPORT NSString* const NSMallocException;
237 
238 /**  An exception when a remote object is sent a message from a thread
239  *  unable to access the object.
240  */
241 GS_EXPORT NSString* const NSObjectInaccessibleException;
242 
243 /**  Attempt to send to an object which is no longer available.
244  */
245 GS_EXPORT NSString* const NSObjectNotAvailableException;
246 
247 /**  UNused ... for MacOS-X compatibility.
248  */
249 GS_EXPORT NSString* const NSOldStyleException;
250 
251 #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST)
252 /** An exception used when some form of parsing fails.
253  */
254 GS_EXPORT NSString* const NSParseErrorException;
255 #endif
256 
257 /** Some failure to receive on a port.
258  */
259 GS_EXPORT NSString * const NSPortReceiveException;
260 
261 /** Some failure to send on a port.
262  */
263 GS_EXPORT NSString * const NSPortSendException;
264 
265 /**
266  *  Exception raised by [NSPort], [NSConnection], and friends if sufficient
267  *  time elapses while waiting for a response, or if the receiving port is
268  *  invalidated before a request can be received.  See
269  *  [NSConnection-setReplyTimeout:].
270  */
271 GS_EXPORT NSString * const NSPortTimeoutException; /* OPENSTEP */
272 
273 /** An exception used when an illegal range is encountered ... usually this
274  * is used to provide more information than an invalid argument exception.
275  */
276 GS_EXPORT NSString* const NSRangeException;
277 
278 /**
279  * The actual structure for an NSHandler.  You shouldn't need to worry about it.
280  */
281 typedef struct _NSHandler
282 {
283     jmp_buf jumpState;			/* place to longjmp to */
284     struct _NSHandler *next;		/* ptr to next handler */
285     __unsafe_unretained NSException *exception;
286 } NSHandler;
287 
288 /**
289  *  This is the type of the exception handler called when an exception is
290  *  generated and not caught by the programmer.  See
291  *  NSGetUncaughtExceptionHandler(), NSSetUncaughtExceptionHandler().
292  */
293 typedef void NSUncaughtExceptionHandler(NSException *exception);
294 
295 /**
296  *  Returns the exception handler called when an exception is generated and
297  *  not caught by the programmer (by enclosing in <code>NS_DURING</code> and
298  *  <code>NS_HANDLER</code>...<code>NS_ENDHANDLER</code>).  The default prints
299  *  an error message and exits the program.  You can change this behavior by
300  *  calling NSSetUncaughtExceptionHandler().
301  */
302 GS_EXPORT NSUncaughtExceptionHandler *
303 NSGetUncaughtExceptionHandler();
304 
305 /**
306  *  <p>Sets the exception handler called when an exception is generated and
307  *  not caught by the programmer (by enclosing in <code>NS_DURING</code> and
308  *  <code>NS_HANDLER</code>...<code>NS_ENDHANDLER</code>).  The default prints
309  *  an error message and exits the program.  proc should take a single argument
310  *  of type <code>NSException *</code>.
311  *  </p>
312  *  <p>NB. If the exception handler set by this function does not terminate
313  *  the process, the process will be terminateed anyway.  This is a safety
314  *  precaution to ensure that, in the event of an exception being raised
315  *  and not handled, the program does not try to continue running in a
316  *  confused state (possibly doing horrible things like billing customers
317  *  who shouldn't be billed etc), but shuts down as cleanly as possible.
318  *  </p>
319  *  <p>Process termination is normally accomplished by calling the standard
320  *  exit function of the C runtime library, but if the environment variable
321  *  CRASH_ON_ABORT is set to YES or TRUE or 1 the termination will be
322  *  accomplished by calling the abort function instead, which should cause
323  *  a core dump to be made for debugging.
324  *  </p>
325  *  <p>The value of proc should be a pointer to a function taking an
326  *  [NSException] instance as an argument.
327  *  </p>
328  */
329 GS_EXPORT void
330 NSSetUncaughtExceptionHandler(NSUncaughtExceptionHandler *handler);
331 
332 /* NS_DURING, NS_HANDLER and NS_ENDHANDLER are always used like:
333 
334 	NS_DURING
335 	    some code which might raise an error
336 	NS_HANDLER
337 	    code that will be jumped to if an error occurs
338 	NS_ENDHANDLER
339 
340    If any error is raised within the first block of code, the second block
341    of code will be jumped to.  Typically, this code will clean up any
342    resources allocated in the routine, possibly case on the error code
343    and perform special processing, and default to RERAISE the error to
344    the next handler.  Within the scope of the handler, a local variable
345    called "localException" holds information about the exception raised.
346 
347    It is illegal to exit the first block of code by any other means than
348    NS_VALRETURN, NS_VOIDRETURN, or just falling out the bottom.
349  */
350 #if     USER_NATIVE_OBJC_EXCEPTIONS
351 
352 # define NS_DURING       @try {
353 # define NS_HANDLER      } @catch (NSException * localException) {
354 # define NS_ENDHANDLER   }
355 
356 # define NS_VALRETURN(val)              return (val)
357 # define NS_VALUERETURN(object, id)     return (object)
358 # define NS_VOIDRETURN                  return
359 
360 #elif   !USER_NATIVE_OBJC_EXCEPTIONS && !BASE_NATIVE_OBJC_EXCEPTIONS
361 
362 /** Private support routine.  Do not call directly. */
363 GS_EXPORT void _NSAddHandler( NSHandler *handler );
364 /** Private support routine.  Do not call directly. */
365 GS_EXPORT void _NSRemoveHandler( NSHandler *handler );
366 
367 #define NS_DURING { NSHandler NSLocalHandler;			\
368 		    _NSAddHandler(&NSLocalHandler);		\
369 		    if (!setjmp(NSLocalHandler.jumpState)) {
370 
371 #define NS_HANDLER _NSRemoveHandler(&NSLocalHandler); } else { \
372 		    NSException __attribute__((unused)) *localException \
373 		      = NSLocalHandler.exception; \
374 		    {
375 
376 #define NS_ENDHANDLER }}}
377 
378 #define NS_VALRETURN(val)  do { __typeof__(val) temp = (val);	\
379 			_NSRemoveHandler(&NSLocalHandler);	\
380 			return(temp); } while (0)
381 
382 #define NS_VALUERETURN(object, id) do { id temp = object;	\
383 			_NSRemoveHandler(&NSLocalHandler);	\
384 			return(temp); } while (0)
385 
386 #define NS_VOIDRETURN	do { _NSRemoveHandler(&NSLocalHandler);	\
387 			return; } while (0)
388 
389 #endif // _NATIVE_OBJC_EXCEPTIONS
390 
391 /* ------------------------------------------------------------------------ */
392 /*   Assertion Handling */
393 /* ------------------------------------------------------------------------ */
394 
395 /**
396  * <p>NSAssertionHandler objects are used to raise exceptions on behalf of
397  * macros implementing assertions.<br />
398  * Each thread has its own assertion handler instance.<br />
399  * </p>
400  * <p>The macros work together with the assertion handler object to
401  * produce meaningful exception messages containing the name of the
402  * source file, the position within that file, and the name of the
403  * ObjC method or C function in which the assertion failed.
404  * </p>
405  * <p>An NSAssertionHandler instance is created on demand for each thread
406  * and is stored in the thread's dictionary under the key NSAssertionHandler.
407  * A custom NSAssertionHandler can be used by adding it to the thread
408  * dictionary under this key.
409  * </p>
410  * The assertion macros are:
411  * NSAssert(), NSCAssert(),
412  * NSAssert1(), NSCAssert1(),
413  * NSAssert2(), NSCAssert2(),
414  * NSAssert3(), NSCAssert3(),
415  * NSAssert4(), NSCAssert4(),
416  * NSAssert5(), NSCAssert5(),
417  * NSParameterAssert(), NSCParameterAssert()<br />
418  * The numbered macros arre obsolete, dating from a time when NSAssert() and
419  * NSCAssert() did not support a variable number of arguments.
420  */
421 @interface NSAssertionHandler : NSObject
422 
423 + (NSAssertionHandler*) currentHandler;
424 
425 - (void) handleFailureInFunction: (NSString*)functionName
426 			    file: (NSString*)fileName
427 		      lineNumber: (NSInteger)line
428 		     description: (NSString*)format,... GS_NORETURN_METHOD;
429 
430 - (void) handleFailureInMethod: (SEL)aSelector
431 			object: object
432 			  file: (NSString*)fileName
433 		    lineNumber: (NSInteger)line
434 		   description: (NSString*)format,... GS_NORETURN_METHOD;
435 
436 @end
437 extern NSString *const NSAssertionHandlerKey;
438 
439 #ifdef	NS_BLOCK_ASSERTIONS
440 #define NSAssert(condition, desc, args...)
441 #define NSCAssert(condition, desc, args...)
442 #else
443 /** Used in an ObjC method body.<br />
444  * See [NSAssertionHandler] for details.<br />
445  * When condition is false, raise an exception using desc and args. */
446 #define NSAssert(condition, desc, args...)			\
447   do {							        \
448     if (!(condition)) {			                        \
449       [[NSAssertionHandler currentHandler] 		        \
450         handleFailureInMethod: _cmd 			        \
451         object: self 					        \
452         file: [NSString stringWithUTF8String: __FILE__] 	\
453         lineNumber: __LINE__ 				        \
454         description: (desc) , ## args]; 			\
455     }							        \
456   } while(0)
457 
458 /** Used in plain C code (not in an ObjC method body).<br />
459  * See [NSAssertionHandler] for details.<br />
460  * When condition is false, raise an exception using desc
461  */
462 #define NSCAssert(condition, desc, args...)		        \
463   do {							        \
464     if (!(condition)) {					        \
465       [[NSAssertionHandler currentHandler] 		        \
466       handleFailureInFunction: [NSString stringWithUTF8String:  \
467         __PRETTY_FUNCTION__] 				        \
468       file: [NSString stringWithUTF8String: __FILE__] 		\
469       lineNumber: __LINE__ 				        \
470       description: (desc) , ## args]; 			        \
471     }							        \
472   } while(0)
473 #endif
474 
475 /** Used in an ObjC method body (obsolete ... use NSAssert).<br />
476  * See [NSAssertionHandler] for details.<br />
477  * When condition is false, raise an exception using desc and arg1, arg2,
478  * arg3, arg4, arg5 */
479 #define NSAssert5(condition, desc, arg1, arg2, arg3, arg4, arg5)	\
480   NSAssert((condition), (desc), (arg1), (arg2), (arg3), (arg4), (arg5))
481 
482 /** Used in an ObjC method body (obsolete ... use NSAssert).<br />
483  * See [NSAssertionHandler] for details.<br />
484  * When condition is false, raise an exception using desc and arg1, arg2,
485  * arg3, arg4 */
486 #define NSAssert4(condition, desc, arg1, arg2, arg3, arg4)	\
487   NSAssert((condition), (desc), (arg1), (arg2), (arg3), (arg4))
488 
489 /** Used in an ObjC method body (obsolete ... use NSAssert).<br />
490  * See [NSAssertionHandler] for details.<br />
491  * When condition is false, raise an exception using desc and arg1, arg2,
492  * arg3 */
493 #define NSAssert3(condition, desc, arg1, arg2, arg3)	\
494   NSAssert((condition), (desc), (arg1), (arg2), (arg3))
495 
496 /** Used in an ObjC method body (obsolete ... use NSAssert).<br />
497  * See [NSAssertionHandler] for details.<br />
498  * When condition is false, raise an exception using desc and arg1, arg2 */
499 #define NSAssert2(condition, desc, arg1, arg2)		\
500   NSAssert((condition), (desc), (arg1), (arg2))
501 
502 /** Used in an ObjC method body (obsolete ... use NSAssert).<br />
503  * See [NSAssertionHandler] for details.<br />
504  * When condition is false, raise an exception using desc  and arg1 */
505 #define NSAssert1(condition, desc, arg1)		\
506   NSAssert((condition), (desc), (arg1))
507 
508 /** Used in an ObjC method body.<br />
509  * See [NSAssertionHandler] for details.<br />
510  * When condition is false, raise an exception saying that an invalid
511  * parameter was supplied to the method. */
512 #define NSParameterAssert(condition)			\
513   NSAssert((condition), @"Invalid parameter not satisfying: %s", #condition)
514 
515 /** Obsolete ... use NSCAssert().<br />
516  * See [NSAssertionHandler] for details.<br />
517  * When condition is false, raise an exception using desc and arg1, arg2,
518  * arg3, arg4, arg5 */
519 #define NSCAssert5(condition, desc, arg1, arg2, arg3, arg4, arg5)	\
520     NSCAssert((condition), (desc), (arg1), (arg2), (arg3), (arg4), (arg5))
521 
522 /** Obsolete ... use NSCAssert().<br />
523  * See [NSAssertionHandler] for details.<br />
524  * When condition is false, raise an exception using desc and arg1, arg2,
525  * arg3, arg4 */
526 #define NSCAssert4(condition, desc, arg1, arg2, arg3, arg4)	\
527     NSCAssert((condition), (desc), (arg1), (arg2), (arg3), (arg4))
528 
529 /** Obsolete ... use NSCAssert().<br />
530  * See [NSAssertionHandler] for details.<br />
531  * When condition is false, raise an exception using desc and arg1, arg2,
532  * arg3 */
533 #define NSCAssert3(condition, desc, arg1, arg2, arg3)	\
534     NSCAssert((condition), (desc), (arg1), (arg2), (arg3))
535 
536 /** Obsolete ... use NSCAssert().<br />
537  * See [NSAssertionHandler] for details.<br />
538  * When condition is false, raise an exception using desc and arg1, arg2
539  */
540 #define NSCAssert2(condition, desc, arg1, arg2)		\
541     NSCAssert((condition), (desc), (arg1), (arg2))
542 
543 /** Obsolete ... use NSCAssert().<br />
544  * See [NSAssertionHandler] for details.<br />
545  * When condition is false, raise an exception using desc and arg1
546  */
547 #define NSCAssert1(condition, desc, arg1)		\
548     NSCAssert((condition), (desc), (arg1))
549 
550 /** Used in plain C code (not in an ObjC method body).<br />
551  * See [NSAssertionHandler] for details.<br />
552  * When condition is false, raise an exception saying that an invalid
553  * parameter was supplied to the method. */
554 #define NSCParameterAssert(condition)			\
555     NSCAssert((condition), @"Invalid parameter not satisfying: %s", #condition)
556 
557 #if	defined(__cplusplus)
558 }
559 #endif
560 
561 #endif /* __NSException_h_GNUSTEP_BASE_INCLUDE */
562