source: trunk/third/sendmail/libsm/exc.html @ 19204

Revision 19204, 23.3 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19203, which included commits to RCS files with non-trunk default branches.
Line 
1<html>
2<head>
3    <title>libsm : Exception Handling</title>
4</head>
5<body>
6
7<a href="index.html">Back to libsm overview</a>
8
9<center>
10    <h1> libsm : Exception Handling </h1>
11    <br> $Id: exc.html,v 1.1.1.1 2003-04-08 15:11:54 zacheiss Exp $
12</center>
13
14<h2> Introduction </h2>
15
16The exception handling package provides the facilities that
17functions in libsm use to report errors.
18Here are the basic concepts:
19
20<ol>
21<li>
22    When a function detects an exceptional condition at the library level,
23    it does not print an error message, or call syslog, or
24    exit the program.  Instead, it reports the error back to its
25    caller, and lets the caller decide what to do.
26    This improves modularity, because error handling is separated
27    from error reporting.
28    <p>
29<li>
30    Errors are not represented by a single integer error code,
31    because that you can't represent everything that an error handler
32    might need to know about an error by a single integer.
33    Instead, errors are represented by exception objects.
34    An exception object contains an exception code and an array
35    of zero or more exception arguments.
36    The exception code is a string that specifies what kind of exception
37    this is, and the arguments may be integers, strings or exception objects.
38    <p>
39<li>
40    Errors are not reported using a special return value,
41    because if you religiously check for error returns from every
42    function call that could fail, then most of your code ends up being
43    error handling code.  Errors are reported by raising an exception.
44    When an exception is raised, we unwind the call stack
45    until we find an exception handler.  If the exception is
46    not handled, then we print the exception on stderr and
47    exit the program.
48</ol>
49
50<h2> Synopsis </h2>
51
52<pre>
53#include &lt;sm/exc.h&gt;
54
55typedef struct sm_exc_type SM_EXC_TYPE_T;
56typedef struct sm_exc SM_EXC_T;
57typedef union sm_val SM_VAL_T;
58
59/*
60**  Exception types
61*/
62
63extern const char SmExcTypeMagic[];
64
65struct sm_exc_type
66{
67        const char      *sm_magic;
68        const char      *etype_category;
69        const char      *etype_argformat;
70        void            (*etype_print)(SM_EXC_T *exc, SM_FILE_T *stream);
71        const char      *etype_printcontext;
72};
73
74extern const SM_EXC_TYPE_T SmEtypeOs;
75extern const SM_EXC_TYPE_T SmEtypeErr;
76
77void
78sm_etype_printf(
79        SM_EXC_T *exc,
80        SM_FILE_T *stream);
81
82/*
83**  Exception objects
84*/
85
86extern const char SmExcMagic[];
87
88union sm_val
89{
90        int             v_int;
91        long            v_long;
92        char            *v_str;
93        SM_EXC_T        *v_exc;
94};
95
96struct sm_exc
97{
98        const char              *sm_magic;
99        size_t                  exc_refcount;
100        const SM_EXC_TYPE_T     *exc_type;
101        SM_VAL_T                *exc_argv;
102};
103
104SM_EXC_T *
105sm_exc_new_x(
106        const SM_EXC_TYPE_T *type,
107        ...);
108
109SM_EXC_T *
110sm_exc_addref(
111        SM_EXC_T *exc);
112
113void
114sm_exc_free(
115        SM_EXC_T *exc);
116
117bool
118sm_exc_match(
119        SM_EXC_T *exc,
120        const char *pattern);
121
122void
123sm_exc_print(
124        SM_EXC_T *exc,
125        SM_FILE_T *stream);
126
127void
128sm_exc_write(
129        SM_EXC_T *exc,
130        SM_FILE_T *stream);
131
132void
133sm_exc_raise_x(
134        SM_EXC_T *exc);
135
136void
137sm_exc_raisenew_x(
138        const SM_EXC_TYPE_T *type,
139        ...);
140
141/*
142**  Ensure that cleanup code is executed,
143**  and/or handle an exception.
144*/
145SM_TRY
146        Block of code that may raise an exception.
147SM_FINALLY
148        Cleanup code that may raise an exception.
149        This clause is guaranteed to be executed even if an exception is
150        raised by the SM_TRY clause or by an earlier SM_FINALLY clause.
151        You may have 0 or more SM_FINALLY clauses.
152SM_EXCEPT(exc, pattern)
153        Exception handling code, triggered by an exception
154        whose category matches 'pattern'.
155        You may have 0 or more SM_EXCEPT clauses.
156SM_END_TRY
157</pre>
158
159<h2> Overview </h2>
160
161    An exception is an object which represents an exceptional condition,
162    which might be an error condition like "out of memory", or might be
163    a condition like "end of file".
164<p>
165    Functions in libsm report errors and other unusual conditions by
166    raising an exception, rather than by returning an error code or
167    setting a global variable such as errno.  If a libsm function is
168    capable of raising an exception, its name ends in "_x".
169    (We do not raise an exception when a bug is detected in the
170    program; instead, we terminate the program using <tt>sm_abort</tt>.
171    See <a href="assert.html">the assertion package</a>
172    for details.)
173<p>
174    When you are using the libsm exception handling package,
175    you are using a new programming paradigm.
176    You will need to abandon some of the programming idioms
177    you are accustomed to, and switch to new idioms.
178    Here is an overview of some of these idioms.
179<ol>
180<li>
181        When a function is unable to complete its task because
182        of an exceptional condition, it reports this condition
183        by raising an exception.
184        <p>
185        Here is an example of how to construct an exception object
186        and raise an exception.
187        In this example, we convert a Unix system error into an exception.
188<blockquote><pre>
189fd = open(path, O_RDONLY);
190if (fd == -1)
191        sm_exc_raise_x(sm_exc_new_x(&SmEtypeOs, errno, "open", "%s", path));
192</pre></blockquote>
193
194        Because the idiom <tt>sm_exc_raise_x(sm_exc_new_x(...))</tt>
195        is so common, it can be abbreviated as <tt>sm_exc_raisenew_x(...)</tt>.
196<p>
197<li>
198        When you detect an error at the application level,
199        you don't call a function like BSD's <tt>errx</tt>,
200        which prints an error message on stderr and exits the program.
201        Instead, you raise an exception.
202        This causes cleanup code in surrounding exception handlers
203        to be run before the program exits.
204        For example, instead of this:
205<blockquote><pre>
206errx(1, "%s:%d: syntax error", filename, lineno);
207</pre></blockquote>
208
209        use this:
210
211<blockquote><pre>
212sm_exc_raisenew_x(&SmEtypeErr, "%s:%d: syntax error", filename, lineno);
213</pre></blockquote>
214
215        The latter code raises an exception, unwinding the call stack
216        and executing cleanup code.
217        If the exception is not handled, then the exception is printed
218        to stderr and the program exits.
219        The end result is substantially the same as a call to <tt>errx</tt>.
220<p>
221<li>
222        The SM_TRY ... SM_FINALLY ... control structure
223        ensures that cleanup code is executed and resources are released
224        in the presence of exceptions.
225<p>
226        For example, suppose that you have written the following code:
227
228<blockquote><pre>
229rpool = sm_rpool_new_x(&SmRpoolRoot, 0);
230... some code ...
231sm_rpool_free_x(rpool);
232</pre></blockquote>
233
234        If any of the functions called within "... some code ..." have
235        names ending in _x, then it is possible that an exception will be
236        raised, and if that happens, then "rpool" will not be freed.
237        And that's a bug.  To fix this bug, change your code so it looks
238        like this:
239
240<blockquote><pre>
241rpool = sm_rpool_new_x(&SmRpoolRoot, 0);
242SM_TRY
243        ... some code that can raise an exception ...
244SM_FINALLY
245        sm_rpool_free_x(rpool);
246SM_END_TRY
247</pre></blockquote>
248
249<li>
250        The SM_TRY ... SM_EXCEPT ... control structure handles an exception.
251        Unhandled exceptions terminate the program.
252        For example, here is a simple exception handler
253        that traps all exceptions, and prints the exceptions:
254
255<blockquote><pre>
256SM_TRY
257        /* code that can raise an exception */
258        ...
259SM_EXCEPT(exc, "*")
260        /* catch all exceptions */
261        sm_exc_print(exc, stderr);
262SM_END_TRY
263</pre></blockquote>
264
265    Exceptions are reference counted.  The SM_END_TRY macro contains a
266    call to sm_exc_free, so you don't normally need to worry about freeing
267    an exception after handling it.  In the rare case that you want an
268    exception to outlive an exception handler, then you increment its
269    reference count by calling sm_exc_addref.
270<p>
271<li>
272    The second argument of the SM_EXCEPT macro is a glob pattern
273    which specifies the types of exceptions that are to be handled.
274    For example, you might want to handle an end-of-file exception
275    differently from other exceptions.
276    Here's how you do that:
277
278<blockquote><pre>
279SM_TRY
280        /* code that might raise end-of-file, or some other exception */
281        ...
282SM_EXCEPT(exc, "E:sm.eof")
283        /* what to do if end-of-file is encountered */
284        ...
285SM_EXCEPT(exc, "*")
286        /* what to do if some other exception is raised */
287        ...
288SM_END_TRY
289</pre></blockquote>
290</ol>
291
292<h2> Exception Values </h2>
293
294In traditional C code, errors are usually denoted by a single integer,
295such as errno.  In practice, errno does not carry enough information
296to describe everything that an error handler might want to know about
297an error.  And the scheme is not very extensible: if several different
298packages want to add additional error codes, it is hard to avoid
299collisions.
300
301<p>
302In libsm, an exceptional condition is described
303by an object of type SM_EXC_T.
304An exception object is created by specifying an exception type
305and a list of exception arguments.
306
307<p>
308The exception arguments are an array of zero or more values.
309The values may be a mixture of ints, longs, strings, and exceptions.
310In the SM_EXC_T structure, the argument vector is represented
311by <tt>SM_VAL_T&nbsp;*exc_argv</tt>, where <tt>SM_VAL_T</tt>
312is a union of the possible argument types.
313The number and types of exception arguments is determined by
314the exception type.
315
316<p>
317An exception type is a statically initialized const object
318of type SM_EXC_TYPE_T, which has the following members:
319
320<dl>
321<dt>
322<tt> const char *sm_magic </tt>
323<dd>
324        A pointer to <tt>SmExcTypeMagic</tt>.
325        <p>
326<dt>
327<tt> const char *etype_category </tt>
328<dd>
329        This is a string of the form
330        <tt>"</tt><i>class</i><tt>:</tt><i>name</i><tt>"</tt>.
331        <p>
332        The <i>class</i> is used to assign the exception type to
333        one of a number of broad categories of exceptions on which an
334        exception handler might want to discriminate.
335        I suspect that what we want is a hierarchical taxonomy,
336        but I don't have a full design for this yet.
337        For now, I am recommending the following classes:
338        <dl>
339        <dt><tt>"F"</tt>
340        <dd>A fatal error has occurred.
341            This is an error that prevents the application
342            from making any further progress, so the only
343            recourse is to raise an exception, execute cleanup code
344            as the stack is unwound, then exit the application.
345            The out-of-memory exception raised by sm_malloc_x
346            has category "F:sm.heap" because sendmail commits suicide
347            (after logging the error and cleaning up) when it runs out
348            of memory.
349
350        <dt><tt>"E"</tt>
351        <dd>The function could not complete its task because an error occurred.
352            (It might be useful to define subclasses of this category,
353            in which case our taxonony becomes a tree, and 'F' becomes
354            a subclass of 'E'.)
355
356        <dt><tt>"J"</tt>
357        <dd>This exception is being raised in order to effect a
358            non-local jump.  No error has occurred; we are just
359            performing the non-local equivalent of a <tt>continue</tt>,
360            <tt>break</tt> or <tt>return</tt>.
361
362        <dt><tt>"S"</tt>
363        <dd>The function was interrupted by a signal.
364            Signals are not errors because they occur asynchronously,
365            and they are semantically unrelated to the function that
366            happens to be executing when the signal arrives.
367            Note that it is extremely dangerous to raise an exception
368            from a signal handler.  For example, if you are in the middle
369            of a call to malloc, you might corrupt the heap.
370        </dl>
371        Eric's libsm paper defines <tt>"W"</tt>, <tt>"D"</tt> and <tt>"I"</tt>
372        for Warning, Debug and Informational:
373        I suspect these categories only make sense in the context of
374        Eric's 1985 exception handling system which allowed you to
375        raise conditions without terminating the calling function.
376        <p>
377        The <i>name</i> uniquely identifies the exception type.
378        I recommend a string of the form
379        <i>library</i><tt>.</tt><i>package</i><tt>.</tt><i>detail</i>.
380        <p>
381<dt>
382<tt> const char *etype_argformat </tt>
383<dd>
384        This is an array of single character codes.
385        Each code indicates the type of one of the exception arguments.
386        <tt>sm_exc_new_x</tt> uses this string to decode its variable
387        argument list into an exception argument vector.
388        The following type codes are supported:
389        <dl>
390        <dt><tt>i</tt>
391        <dd>
392                The exception argument has type <tt>int</tt>.
393        <dt><tt>l</tt>
394        <dd>
395                The exception argument has type <tt>long</tt>.
396        <dt><tt>e</tt>
397        <dd>
398                The exception argument has type <tt>SM_EXC_T*</tt>.
399                The value may either be <tt>NULL</tt> or a pointer
400                to an exception.  The pointer value is simply copied
401                into the exception argument vector.
402        <dt><tt>s</tt>
403        <dd>
404                The exception argument has type <tt>char*</tt>.
405                The value may either be <tt>NULL</tt> or a pointer
406                to a character string.  In the latter case,
407                <tt>sm_exc_new_x</tt> will make a copy of the string.
408        <dt><tt>r</tt>
409        <dd>
410                The exception argument has type <tt>char*</tt>.
411                <tt>sm_exc_new_x</tt> will read a printf-style
412                format string argument followed by a list of printf
413                arguments from its variable argument list, and convert
414                these into a string.
415                This type code can only occur as the last element
416                of <tt>exc_argformat</tt>.
417        </dl>
418        <p>
419<dt>
420<tt> void (*etype_print)(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
421<dd>
422        This function prints an exception of the specified type
423        onto an output stream.
424        The final character printed is not a newline.
425</dl>
426
427<h2> Standard Exceptions and Exception Types </h2>
428
429Libsm defines one standard exception value, <tt>SmHeapOutOfMemory</tt>.
430This is a statically initialized const variable, because it seems
431like a bad idea to dynamically allocate an exception object to
432report a low memory condition.
433This exception has category <tt>"F:sm.heap"</tt>.
434If you need to, you can explicitly raise this exception
435with <tt>sm_exc_raise_x(&SmHeapOutOfMemory)</tt>.
436
437<p>
438Statically initialized exception values cannot contain any
439run-time parameters, so the normal case is to dynamically allocate
440a new exception object whenever you raise an exception.
441Before you can create an exception, you need an exception type.
442Libsm defines the following standard exception types.
443
444<dl>
445<dt>
446<tt> SmEtypeOs </tt>
447<dd>
448        This represents a generic operating system error.
449        The category is <tt>"E:sm.os"</tt>.
450        The argformat is <tt>"isr"</tt>,
451        where argv[0] is the value of <tt>errno</tt>
452        after a system call has failed,
453        argv[1] is the name of the function (usually a system call) that failed,
454        and argv[2] is either <tt>NULL</tt>
455        or a character string which describes some of the arguments
456        to the failing system call (usually it is just a file name).
457        Here's an example of raising an exception:
458
459<blockquote><pre>
460fd = open(filename, O_RDONLY);
461if (fd == -1)
462        sm_exc_raisenew_x(&SmEtypeOs, errno, "open", "%s", filename);
463</pre></blockquote>
464
465        If errno is ENOENT and filename is "/etc/mail/snedmail.cf",
466        then the exception raised by the above code will be printed as
467
468<blockquote><pre>
469/etc/mail/snedmail.cf: open failed: No such file or directory
470</pre></blockquote>
471
472<dt>
473<tt> SmEtypeErr </tt>
474<dd>
475        This represents a generic error.
476        The category is <tt>"E:sm.err"</tt>,
477        and the argformat is <tt>"r"</tt>.
478        You can use it
479        in application contexts where you are raising an exception
480        for the purpose of terminating the program.
481        You know the exception won't be handled,
482        so you don't need to worry about packaging the error for
483        later analysis by an exception handler.
484        All you need to specify is the message string that
485        will be printed to stderr before the program exits.
486        For example,
487
488<blockquote><pre>
489sm_exc_raisenew_x(&SmEtypeErr, "name lookup failed: %s", name);
490</pre></blockquote>
491</dl>
492
493<h2> Custom Exception Types </h2>
494
495If you are writing a library package, and you need to raise
496exceptions that are not standard Unix system errors,
497then you need to define one or more new exception types.
498
499<p>
500Every new exception type needs a print function.
501The standard print function <tt>sm_etype_printf</tt>
502is all you need in the majority of cases.
503It prints the <tt>etype_printcontext</tt> string of the exception type,
504substituting occurrences of %0 through %9 with the corresponding
505exception argument.
506If exception argument 3 is an int or long,
507then %3 will print the argument in decimal,
508and %o3 or %x3 will print it in octal or hex.
509
510<p>
511In the following example, I will assume that your library
512package implements regular expressions, and can raise 5 different exceptions.
513When compiling a regular expression, 3 different syntax errors
514can be reported:
515<ul>
516<li>unbalanced parenthesis
517<li>unbalanced bracket
518<li>missing argument for repetition operator
519</ul>
520Whenever one of these errors is reported, you will also report
521the index of the character within the regex string at which the
522syntax error was detected.
523The fourth exception is raised if a compiled regular expression
524is invalid: this exception has no arguments.
525The fifth exception is raised if the package runs out of memory:
526for this, you use the standard <tt>SmHeapOutOfMemory</tt> exception.
527
528<p>
529The obvious approach is to define 4 separate exception types.
530Here they are:
531
532<blockquote><pre>
533/* print a regular expression syntax error */
534void
535rx_esyntax_print(SM_EXC_T *exc, SM_FILE_T *stream)
536{
537        sm_io_fprintf(stream, "rx syntax error at character %d: %s",
538                exc-&gt;exc_argv[0].v_int,
539                exc-&gt;exc_type-&gt;etype_printcontext);
540}
541SM_EXC_TYPE_T RxSyntaxParen = {
542        SmExcTypeMagic,
543        "E:mylib.rx.syntax.paren",
544        "i",
545        rx_esyntax_print,
546        "unbalanced parenthesis"
547};
548SM_EXC_TYPE_T RxSyntaxBracket = {
549        SmExcTypeMagic,
550        "E:mylib.rx.syntax.bracket",
551        "i",
552        rx_esyntax_print,
553        "unbalanced bracket"
554};
555SM_EXC_TYPE_T RxSyntaxMissingArg = {
556        SmExcTypeMagic,
557        "E:mylib.rx.syntax.missingarg",
558        "i",
559        rx_esyntax_print,
560        "missing argument for repetition operator"
561};
562
563SM_EXC_TYPE_T RxRunCorrupt = {
564        SmExcTypeMagic,
565        "E:mylib.rx.run.corrupt",
566        "",
567        sm_etype_printf,
568        "rx runtime error: compiled regular expression is corrupt"
569};
570</pre></blockquote>
571
572<p>
573With the above definitions, you can raise a syntax error reporting
574an unbalanced parenthesis at string offset <tt>i</tt> using:
575<blockquote><pre>
576sm_exc_raisenew_x(&RxSyntaxParen, i);
577</pre></blockquote>
578
579If <tt>i==42</tt> then this exception will be printed as:
580<blockquote><pre>
581rx syntax error at character 42: unbalanced parenthesis
582</pre></blockquote>
583
584An exception handler can provide special handling for regular
585expression syntax errors using this code:
586<blockquote><pre>
587SM_TRY
588        ... code that might raise an exception ...
589SM_EXCEPT(exc, "E:mylib.rx.syntax.*")
590        int i = exc-&gt;exc_argv[0].v_int;
591        ... handle a regular expression syntax error ...
592SM_END_TRY
593</pre></blockquote>
594
595<p>
596External requirements may force you to define an integer code
597for each error reported by your package.  Or you may be wrapping
598an existing package that works this way.  In this case, it might
599make sense to define a single exception type, patterned after SmEtypeOs,
600and include the integer code as an exception argument.
601
602<p>
603Your package might intercept an exception E generated by a lower
604level package, and then reclassify it as a different expression E'.
605For example, a package for reading a configuration file might
606reclassify one of the regular expression syntax errors from the
607previous example as a configuration file syntax error.
608When you do this, the new exception E' should include the original
609exception E as an exception parameter, and the print function for
610exception E' should print the high level description of the exception
611(eg, "syntax error in configuration file %s at line %d\n"),
612then print the subexception that is stored as an exception parameter.
613
614<h2> Function Reference </h2>
615
616<dl>
617<dt>
618<tt> SM_EXC_T *sm_exc_new_x(const SM_EXC_TYPE_T *type, ...) </tt>
619<dd>
620        Create a new exception.  Raise an exception on heap exhaustion.
621        The new exception has a reference count of 1.
622        <p>
623
624        A list of zero or more exception arguments follows the exception type;
625        these are copied into the new exception object.
626        The number and types of these arguments is determined
627        by <tt>type-&gt;etype_argformat</tt>.
628        <p>
629
630        Note that there is no rpool argument to sm_exc_new_x.
631        Exceptions are allocated directly from the heap.
632        This is because exceptions are normally raised at low levels
633        of abstraction and handled at high levels.  Because the low
634        level code typically has no idea of how or at what level the
635        exception will be handled, it also has no idea of which resource
636        pool, if any, should own the exception.
637        <p>
638<dt>
639<tt> SM_EXC_T *sm_exc_addref(SM_EXC_T *exc) </tt>
640<dd>
641        Increment the reference count of an exception.
642        Return the first argument.
643        <p>
644<dt>
645<tt> void sm_exc_free(SM_EXC_T *exc) </tt>
646<dd>
647        Decrement the reference count of an exception.
648        If it reaches 0, free the exception object.
649        <p>
650<dt>
651<tt> bool sm_exc_match(SM_EXC_T *exc, const char *pattern) </tt>
652<dd>
653        Compare the exception's category to the specified glob pattern,
654        return true if they match.
655        <p>
656<dt>
657<tt> void sm_exc_print(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
658<dd>
659        Print the exception on the stream
660        as a sequence of one or more newline terminated lines.
661        <p>
662<dt>
663<tt> void sm_exc_write(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
664<dd>
665        Write the exception on the stream without a terminating newline.
666        <p>
667<dt>
668<tt> void sm_exc_raise_x(SM_EXC_T *exc) </tt>
669<dd>
670        Raise the exception.  This function does not return to its caller.
671        <p>
672<dt>
673<tt> void sm_exc_raisenew_x(const SM_EXC_TYPE_T *type, ...) </tt>
674<dd>
675        A short form for <tt>sm_exc_raise_x(sm_exc_new_x(type,...))</tt>.
676</dl>
677
678<h2> Macro Reference </h2>
679
680The SM_TRY ... SM_END_TRY control structure
681ensures that cleanup code is executed in the presence of exceptions,
682and permits exceptions to be handled.
683
684<blockquote><pre>
685SM_TRY
686        A block of code that may raise an exception.
687SM_FINALLY
688        Cleanup code that may raise an exception.
689        This code is guaranteed to be executed whether or not
690        an exception was raised by a previous clause.
691        You may have 0 or more SM_FINALLY clauses.
692SM_EXCEPT(e, pat)
693        Exception handling code, which is triggered by an exception
694        whose category matches the glob pattern 'pat'.
695        The exception value is bound to the local variable 'e'.
696        You may have 0 or more SM_EXCEPT clauses.
697SM_END_TRY
698</pre></blockquote>
699
700First, the SM_TRY clause is executed, then each SM_FINALLY clause is
701executed in sequence.
702If one or more of these clauses was terminated by an exception,
703then the first such exception is remembered, and the other exceptions
704are lost.
705
706If no exception was raised, then we are done.
707
708Otherwise, each of the SM_EXCEPT clauses is examined in sequence.
709and the first SM_EXCEPT clause whose pattern argument matches the exception
710(see <tt>sm_exc_match</tt>) is executed.
711If none of the SM_EXCEPT clauses matched the exception, or if there are
712no SM_EXCEPT clauses, then the remembered exception is re-raised.
713
714<p>
715SM_TRY .. SM_END_TRY clauses may be nested arbitrarily.
716
717<p>
718It is illegal to jump out of a SM_TRY or SM_FINALLY clause
719using goto, break, continue, return or longjmp.
720If you do this, you will corrupt the internal exception handling stack.
721You can't use <tt>break</tt> or <tt>continue</tt> in an SM_EXCEPT clause;
722these are reserved for use by the implementation.
723It is legal to jump out of an SM_EXCEPT clause using goto or return;
724however, in this case, you must take responsibility
725for freeing the exception object.
726
727<p>
728The SM_TRY and SM_FINALLY macros contain calls to setjmp,
729and consequently, they suffer from the limitations imposed on setjmp
730by the C standard.
731Suppose you declare an auto variable <tt>i</tt> outside of a
732SM_TRY ... SM_END_TRY statement, initializing it to 0.
733Then you modify <tt>i</tt> inside of a SM_TRY or SM_FINALLY clause,
734setting it to 1.
735If you reference <tt>i</tt> in a different SM_FINALLY clause, or in
736an SM_EXCEPT clause, then it is implementation dependent whether <tt>i</tt>
737will be 0 or 1, unless you have declared <tt>i</tt> to be <tt>volatile</tt>.
738
739<blockquote><pre>
740int volatile i = 0;
741
742SM_TRY
743        i = 1;
744        ...
745SM_FINALLY
746        /* the following reference to i only works if i is declared volatile */
747        use(i);
748        ...
749SM_EXCEPT(exc, "*")
750        /* the following reference to i only works if i is declared volatile */
751        use(i);
752        ...
753SM_END_TRY
754</pre></blockquote>
755
756</body>
757</html>
Note: See TracBrowser for help on using the repository browser.