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