The Shore return code class, shrc, is a data structure that is fundamental to all error-handling for Shore applications. It is a pointer to a data structure that contains an error code and a small stack trace (limited to 3 levels) of the functions in which the error was detected.
Most Shore functions return a shrc. The include files for application programs define a set of macros that are useful for interpreting and using the shrc. The macros are described in some detail in the sections below. They are summarized here:
The rest of this manual page describes some common errors that application programs have to address and some common programming errors. These examples use the following macro (not supplied in any of the Shore include files):
#define PERROR(rc) { if(rc) {\ cerr << __LINE__ << " " <<__FILE__<<":"<<endl;\ cerr << rc << endl; if(rc = RCOK);\ } }
char *fname = "/nonexistentdir/junk"; Ref<SdlUnixFile> o; o = new (fname, 0755) SdlUnixFile;results in the following message, printed by the default error handler, when /nonexistentdir does not exist:
1. error in ObjCache.C:3539 The named object was not found called from: 0) OCRef.C:69 1) ../../src/sdl/include/sdl_UnixFile.h:28 2) in operator new():0 2. error in ObjCache.C:949 The requested object was not found
The preferable way to create objects, when an error might occur during their creation, is with Ref<T>::new_persistent. The following example shows how:
char *fname = "/nonexistentdir/junk"; Ref<SdlUnixFile> o; rc = Ref<SdlUnixFile>::new_persistent(fname, 0755, o); SH_NEW_ERROR_STACK(rc); if(!o) { cerr << "Could not create " << fname << endl; PERROR(rc); ... perhaps abort the transaction }
This results in the following message,
Could not create /nonexistentdir/junk 174 error.C: 1. error in error.C:171 The named object was not found
If a bad Ref<T> is dereferenced, and if the lower layers can detect the problem in time (e.g., the reference is null), the error handler will be called. If the value of the reference is garbage, but not null (perhaps a wayward pointer resulted in scribbling on the reference), the lower layers will not detect the bad reference, and your program will behave in undefined ways like any other program that uses a garbage pointer.
References are initialized to null, so that these two statements are equivalent:
Ref<SdlUnixFile> o(0); Ref<SdlUnixFile> o;
If the error handler is called during a dereference (operator->), the program exits after calling the handler. If you are debugging a program that suffers this fate, you can use a debugger to break (stop) in the error handler, and see a full stack trace that shows the source of the problem. If you have not installed your own error handler, set the breakpoint in
OCRef::default_error_handler
When a shrc is printed directly after returning from a method in the class Shore, or from any low-level Shore library function, the stack trace is of little use to you if you don't care to look through the source code for the Shore libraries. You can use the macro SH_NEW_ERROR_STACK to replace this stack trace with a trace of the application functions in which the error is detected, or he can retain the low-level stack and attach a new stack that traces the application functions in which the error is detected, The following example illustrates how the this is done.
shrc stat_it(const char *fname) { shrc rc; rc = Shore::stat(fname, &statbuf); SH_NEW_ERROR_STACK(rc); PERROR(rc); // prints rc, clears rc ... return rc; }In this example, when the application is handed a return code from a method of class Shore , it checks the return code, and if appropriate, it replaces the return code with a new one. The new return-code's stack trace begins with the line that creates the new return code.
The above code produces a message like this, if there is no object with the name fname:
1. error in error.C:35 The named object was not found
If your application program has many levels of function calls and you want the intermediate functions to add stack trace information to the return code, follow this example:
shrc stat_it(const char *fname) { shrc rc; rc = Shore::stat(fname, &statbuf); SH_NEW_ERROR_STACK(rc); // leave rc intact, don't print return rc; } shrc intermediate_func(const char *fname) { shrc rc = stat_it(fname); ... // add stack trace info if error SH_RETURN_ERROR(rc); } main() { ... if (rc=intermediate_func(fname)) PERROR(rc); ...
The above example yields error message like this, if the caller of
1. error in error.C:46 The named object was not found called from: 0) error.C:53
The implementation of the return code classes permits at most 3-level stacks of trace information.
Finally, if you would rather keep the entire stack trace from lower layers, and you would like to use your installed error handler (see below), use the macro SH_HANDLE_NONFATAL_ERROR or the macro use the macro SH_HANDLE_ERROR as follows:
SH_HANDLE_NONFATAL_ERROR(Shore::stat(fname, &statbuf)); or SH_HANDLE_ERROR(Shore::stat(fname, &statbuf));both of which produce results like this:
1. error in ObjCache.C:3539 The named object was not found called from: 0) Shore.C:457 1) error.C:62 2. error in ObjCache.C:1258 The requested object was not found
The macro SH_HANDLE_NONFATAL_ERROR calls the installed error handler and returns; SH_HANDLE_ERROR calls the installed error handler and exits. If you have not installed an error handler, the default error handler will be called. See errors(oc) for information about installing an error handler.
This message comes from the bowels of the code that implements the shrc class. It is printed if a shrc is created, then destroyed without ever having been checked, for example
{ shrc rc1 = RC(EINTR); shrc rc2 = RC(EINTR); if(rc2) { ... } }When the scope of rc1 is left, the message will be printed. When the scope of rc2 is left, no message will be printed because rc2 was checked.
You can locate the causes of these errors with gdb by setting a breakpoint in w_rc_t::error_not_checked , and printing a stack trace when the breakpoint is reached.
If you try apply a non-const method to a const reference, you will get an error at compile-time.
int errno; SH_DO(Shore::access(fname, W_OK, errno)); if(errno) { rc = RC(errno); SH_NEW_ERROR_STACK(rc); PERROR(rc); }See access(oc) for details. The result of the above code is:
1. error in error.C:257 Permission denied