xref: /freebsd/contrib/sendmail/libsm/exc.html (revision 38f0b757fd84d17d0fc24739a7cda160c4516d81)
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.13 2006/06/20 17:18:16 ca 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 then 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>
758