Wireshark  2.9.0-477-g68ec514b
The Wireshark network protocol analyzer
exceptions.h
1 /* exceptions.h
2  * Wireshark's exceptions.
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #ifndef __EXCEPTIONS_H__
12 #define __EXCEPTIONS_H__
13 
14 #include "except.h"
15 
16 /* Wireshark has only one exception group, to make these macros simple */
17 #define XCEPT_GROUP_WIRESHARK 1
18 
26 #define BoundsError 1
27 
39 #define ContainedBoundsError 2
40 
48 #define ReportedBoundsError 3
49 
54 #define FragmentBoundsError 4
55 
59 #define TypeError 5
60 
70 #define DissectorError 6
71 
81 #define ScsiBoundsError 7
82 
87 #define OutOfMemoryError 8
88 
96 #define ReassemblyError 9
97 
98 /*
99  * Catch errors that, if you're calling a subdissector and catching
100  * exceptions from the subdissector, and possibly dissecting more
101  * stuff after the subdissector returns or fails, mean it makes
102  * sense to continue dissecting:
103  *
104  * BoundsError indicates a configuration problem (the capture was
105  * set up to throw away data, and it did); there's no point in
106  * trying to dissect any more data, as there's no more data to dissect.
107  *
108  * FragmentBoundsError indicates a configuration problem (reassembly
109  * wasn't enabled or couldn't be done); there's no point in trying
110  * to dissect any more data, as there's no more data to dissect.
111  *
112  * OutOfMemoryError indicates what its name suggests; there's no point
113  * in trying to dissect any more data, as you're probably not going to
114  * have any more memory to use when dissecting them.
115  *
116  * Other errors indicate that there's some sort of problem with
117  * the packet; you should continue dissecting data, as it might
118  * be OK, and, even if it's not, you should report its problem
119  * separately.
120  */
121 #define CATCH_NONFATAL_ERRORS \
122  CATCH4(ReportedBoundsError, ContainedBoundsError, ScsiBoundsError, ReassemblyError)
123 
124 /*
125  * Catch all bounds-checking errors.
126  */
127 #define CATCH_BOUNDS_ERRORS \
128  CATCH5(BoundsError, FragmentBoundsError, ReportedBoundsError, \
129  ContainedBoundsError, ScsiBoundsError)
130 
131 /*
132  * Catch all bounds-checking errors, and catch dissector bugs.
133  * Should only be used at the top level, so that dissector bugs
134  * go all the way to the top level and get reported immediately.
135  */
136 #define CATCH_BOUNDS_AND_DISSECTOR_ERRORS \
137  CATCH7(BoundsError, FragmentBoundsError, ContainedBoundsError, \
138  ReportedBoundsError, ScsiBoundsError, DissectorError, \
139  ReassemblyError)
140 
141 /* Usage:
142  *
143  * TRY {
144  * code;
145  * }
146  *
147  * CATCH(exception) {
148  * code;
149  * }
150  *
151  * CATCH2(exception1, exception2) {
152  * code;
153  * }
154  *
155  * CATCH3(exception1, exception2, exception3) {
156  * code;
157  * }
158  *
159  * CATCH4(exception1, exception2, exception3, exception4) {
160  * code;
161  * }
162  *
163  * CATCH5(exception1, exception2, exception3, exception4, exception5) {
164  * code;
165  * }
166  *
167  * CATCH6(exception1, exception2, exception3, exception4, exception5, exception6) {
168  * code;
169  * }
170  *
171  * CATCH7(exception1, exception2, exception3, exception4, exception5, exception6, exception7) {
172  * code;
173  * }
174  *
175  * CATCH_NONFATAL_ERRORS {
176  * code;
177  * }
178  *
179  * CATCH_BOUNDS_ERRORS {
180  * code;
181  * }
182  *
183  * CATCH_BOUNDS_AND_DISSECTOR_ERRORS {
184  * code;
185  * }
186  *
187  * CATCH_ALL {
188  * code;
189  * }
190  *
191  * FINALLY {
192  * code;
193  * }
194  *
195  * ENDTRY;
196  *
197  * ********* Never use 'goto' or 'return' inside the TRY, CATCH*, or
198  * ********* FINALLY blocks. Execution must proceed through ENDTRY before
199  * ********* branching out.
200  *
201  * This is really something like:
202  *
203  * {
204  * caught = FALSE:
205  * x = setjmp();
206  * if (x == 0) {
207  * <TRY code>
208  * }
209  * if (!caught && x == 1) {
210  * caught = TRUE;
211  * <CATCH(1) code>
212  * }
213  * if (!caught && x == 2) {
214  * caught = TRUE;
215  * <CATCH(2) code>
216  * }
217  * if (!caught && (x == 3 || x == 4)) {
218  * caught = TRUE;
219  * <CATCH2(3,4) code>
220  * }
221  * if (!caught && (x == 5 || x == 6 || x == 7)) {
222  * caught = TRUE;
223  * <CATCH3(5,6,7) code>
224  * }
225  * if (!caught && x != 0) {
226  * caught = TRUE;
227  * <CATCH_ALL code>
228  * }
229  * <FINALLY code>
230  * if(!caught) {
231  * RETHROW(x)
232  * }
233  * }<ENDTRY tag>
234  *
235  * All CATCH's must precede a CATCH_ALL.
236  * FINALLY must occur after any CATCH or CATCH_ALL.
237  * ENDTRY marks the end of the TRY code.
238  * TRY and ENDTRY are the mandatory parts of a TRY block.
239  * CATCH, CATCH_ALL, and FINALLY are all optional (although
240  * you'll probably use at least one, otherwise why "TRY"?)
241  *
242  * GET_MESSAGE returns string ptr to exception message
243  * when exception is thrown via THROW_MESSAGE()
244  *
245  * To throw/raise an exception.
246  *
247  * THROW(exception)
248  * RETHROW rethrow the caught exception
249  *
250  * A cleanup callback is a function called in case an exception occurs
251  * and is not caught. It should be used to free any dynamically-allocated data.
252  * A pop or call_and_pop should occur at the same statement-nesting level
253  * as the push.
254  *
255  * CLEANUP_CB_PUSH(func, data)
256  * CLEANUP_CB_POP
257  * CLEANUP_CB_CALL_AND_POP
258  */
259 
260 /* we do up to three passes through the bit of code after except_try_push(),
261  * and except_state is used to keep track of where we are.
262  */
263 #define EXCEPT_CAUGHT 1 /* exception has been caught, no need to rethrow at
264  * ENDTRY */
265 
266 #define EXCEPT_RETHROWN 2 /* the exception was rethrown from a CATCH
267  * block. Don't reenter the CATCH blocks, but do
268  * execute FINALLY and rethrow at ENDTRY */
269 
270 #define EXCEPT_FINALLY 4 /* we've entered the FINALLY block - don't allow
271  * RETHROW, and don't reenter FINALLY if a
272  * different exception is thrown */
273 
274 #define TRY \
275 {\
276  except_t *volatile exc; \
277  volatile int except_state = 0; \
278  static const except_id_t catch_spec[] = { \
279  { XCEPT_GROUP_WIRESHARK, XCEPT_CODE_ANY } }; \
280  except_try_push(catch_spec, 1, &exc); \
281  \
282  if(except_state & EXCEPT_CAUGHT) \
283  except_state |= EXCEPT_RETHROWN; \
284  except_state &= ~EXCEPT_CAUGHT; \
285  \
286  if (except_state == 0 && exc == 0) \
287  /* user's code goes here */
288 
289 #define ENDTRY \
290  /* rethrow the exception if necessary */ \
291  if(!(except_state&EXCEPT_CAUGHT) && exc != 0) \
292  except_rethrow(exc); \
293  except_try_pop();\
294 }
295 
296 /* the (except_state |= EXCEPT_CAUGHT) in the below is a way of setting
297  * except_state before the user's code, without disrupting the user's code if
298  * it's a one-liner.
299  */
300 #define CATCH(x) \
301  if (except_state == 0 && exc != 0 && \
302  exc->except_id.except_code == (x) && \
303  (except_state |= EXCEPT_CAUGHT)) \
304  /* user's code goes here */
305 
306 #define CATCH2(x,y) \
307  if (except_state == 0 && exc != 0 && \
308  (exc->except_id.except_code == (x) || \
309  exc->except_id.except_code == (y)) && \
310  (except_state|=EXCEPT_CAUGHT)) \
311  /* user's code goes here */
312 
313 #define CATCH3(x,y,z) \
314  if (except_state == 0 && exc != 0 && \
315  (exc->except_id.except_code == (x) || \
316  exc->except_id.except_code == (y) || \
317  exc->except_id.except_code == (z)) && \
318  (except_state|=EXCEPT_CAUGHT)) \
319  /* user's code goes here */
320 
321 #define CATCH4(w,x,y,z) \
322  if (except_state == 0 && exc != 0 && \
323  (exc->except_id.except_code == (w) || \
324  exc->except_id.except_code == (x) || \
325  exc->except_id.except_code == (y) || \
326  exc->except_id.except_code == (z)) && \
327  (except_state|=EXCEPT_CAUGHT)) \
328  /* user's code goes here */
329 
330 #define CATCH5(v,w,x,y,z) \
331  if (except_state == 0 && exc != 0 && \
332  (exc->except_id.except_code == (v) || \
333  exc->except_id.except_code == (w) || \
334  exc->except_id.except_code == (x) || \
335  exc->except_id.except_code == (y) || \
336  exc->except_id.except_code == (z)) && \
337  (except_state|=EXCEPT_CAUGHT)) \
338  /* user's code goes here */
339 
340 #define CATCH6(u,v,w,x,y,z) \
341  if (except_state == 0 && exc != 0 && \
342  (exc->except_id.except_code == (u) || \
343  exc->except_id.except_code == (v) || \
344  exc->except_id.except_code == (w) || \
345  exc->except_id.except_code == (x) || \
346  exc->except_id.except_code == (y) || \
347  exc->except_id.except_code == (z)) && \
348  (except_state|=EXCEPT_CAUGHT)) \
349  /* user's code goes here */
350 
351 #define CATCH7(t, u,v,w,x,y,z) \
352  if (except_state == 0 && exc != 0 && \
353  (exc->except_id.except_code == (t) || \
354  exc->except_id.except_code == (u) || \
355  exc->except_id.except_code == (v) || \
356  exc->except_id.except_code == (w) || \
357  exc->except_id.except_code == (x) || \
358  exc->except_id.except_code == (y) || \
359  exc->except_id.except_code == (z)) && \
360  (except_state|=EXCEPT_CAUGHT)) \
361  /* user's code goes here */
362 
363 #define CATCH_ALL \
364  if (except_state == 0 && exc != 0 && \
365  (except_state|=EXCEPT_CAUGHT)) \
366  /* user's code goes here */
367 
368 #define FINALLY \
369  if( !(except_state & EXCEPT_FINALLY) && (except_state|=EXCEPT_FINALLY)) \
370  /* user's code goes here */
371 
372 #define THROW(x) \
373  except_throw(XCEPT_GROUP_WIRESHARK, (x), NULL)
374 
375 #define THROW_ON(cond, x) G_STMT_START { \
376  if ((cond)) \
377  except_throw(XCEPT_GROUP_WIRESHARK, (x), NULL); \
378 } G_STMT_END
379 
380 #define THROW_MESSAGE(x, y) \
381  except_throw(XCEPT_GROUP_WIRESHARK, (x), (y))
382 
383 #define THROW_MESSAGE_ON(cond, x, y) G_STMT_START { \
384  if ((cond)) \
385  except_throw(XCEPT_GROUP_WIRESHARK, (x), (y)); \
386 } G_STMT_END
387 
388 /* Throws a formatted message, its memory is cleared after catching it. */
389 #define THROW_FORMATTED(x, ...) \
390  except_throwf(XCEPT_GROUP_WIRESHARK, (x), __VA_ARGS__)
391 
392 /* Like THROW_FORMATTED, but takes a va_list as an argument */
393 #define VTHROW_FORMATTED(x, format, args) \
394  except_vthrowf(XCEPT_GROUP_WIRESHARK, (x), format, args)
395 
396 #define GET_MESSAGE except_message(exc)
397 
398 #define RETHROW \
399  { \
400  /* check we're in a catch block */ \
401  g_assert(except_state == EXCEPT_CAUGHT); \
402  /* we can't use except_rethrow here, as that pops a catch block \
403  * off the stack, and we don't want to do that, because we want to \
404  * excecute the FINALLY {} block first. \
405  * except_throw doesn't provide an interface to rethrow an existing \
406  * exception; however, longjmping back to except_try_push() has the \
407  * desired effect. \
408  * \
409  * Note also that THROW and RETHROW should provide much the same \
410  * functionality in terms of which blocks to enter, so any messing \
411  * about with except_state in here would indicate that THROW is \
412  * doing the wrong thing. \
413  */ \
414  longjmp(except_ch.except_jmp,1); \
415  }
416 
417 #define EXCEPT_CODE except_code(exc)
418 
419 /* Register cleanup functions in case an exception is thrown and not caught.
420  * From the Kazlib documentation, with modifications for use with the
421  * Wireshark-specific macros:
422  *
423  * CLEANUP_PUSH(func, arg)
424  *
425  * The call to CLEANUP_PUSH shall be matched with a call to
426  * CLEANUP_CALL_AND_POP or CLEANUP_POP which must occur in the same
427  * statement block at the same level of nesting. This requirement allows
428  * an implementation to provide a CLEANUP_PUSH macro which opens up a
429  * statement block and a CLEANUP_POP which closes the statement block.
430  * The space for the registered pointers can then be efficiently
431  * allocated from automatic storage.
432  *
433  * The CLEANUP_PUSH macro registers a cleanup handler that will be
434  * called if an exception subsequently occurs before the matching
435  * CLEANUP_[CALL_AND_]POP is executed, and is not intercepted and
436  * handled by a try-catch region that is nested between the two.
437  *
438  * The first argument to CLEANUP_PUSH is a pointer to the cleanup
439  * handler, a function that returns nothing and takes a single
440  * argument of type void*. The second argument is a void* value that
441  * is registered along with the handler. This value is what is passed
442  * to the registered handler, should it be called.
443  *
444  * Cleanup handlers are called in the reverse order of their nesting:
445  * inner handlers are called before outer handlers.
446  *
447  * The program shall not leave the cleanup region between
448  * the call to the macro CLEANUP_PUSH and the matching call to
449  * CLEANUP_[CALL_AND_]POP by means other than throwing an exception,
450  * or calling CLEANUP_[CALL_AND_]POP.
451  *
452  * Within the call to the cleanup handler, it is possible that new
453  * exceptions may happen. Such exceptions must be handled before the
454  * cleanup handler terminates. If the call to the cleanup handler is
455  * terminated by an exception, the behavior is undefined. The exception
456  * which triggered the cleanup is not yet caught; thus the program
457  * would be effectively trying to replace an exception with one that
458  * isn't in a well-defined state.
459  *
460  *
461  * CLEANUP_POP and CLEANUP_CALL_AND_POP
462  *
463  * A call to the CLEANUP_POP or CLEANUP_CALL_AND_POP macro shall match
464  * each call to CLEANUP_PUSH which shall be in the same statement block
465  * at the same nesting level. It shall match the most recent such a
466  * call that is not matched by a previous CLEANUP_[CALL_AND_]POP at
467  * the same level.
468  *
469  * These macros causes the registered cleanup handler to be removed. If
470  * CLEANUP_CALL_AND_POP is called, the cleanup handler is called.
471  * In that case, the registered context pointer is passed to the cleanup
472  * handler. If CLEANUP_POP is called, the cleanup handler is not called.
473  *
474  * The program shall not leave the region between the call to the
475  * macro CLEANUP_PUSH and the matching call to CLEANUP_[CALL_AND_]POP
476  * other than by throwing an exception, or by executing the
477  * CLEANUP_CALL_AND_POP.
478  *
479  */
480 
481 
482 #define CLEANUP_PUSH(f,a) except_cleanup_push((f),(a))
483 #define CLEANUP_POP except_cleanup_pop(0)
484 #define CLEANUP_CALL_AND_POP except_cleanup_pop(1)
485 
486 /* Variants to allow nesting of except_cleanup_push w/o "shadowing" variables */
487 #define CLEANUP_PUSH_PFX(pfx,f,a) except_cleanup_push_pfx(pfx,(f),(a))
488 #define CLEANUP_POP_PFX(pfx) except_cleanup_pop_pfx(pfx,0)
489 #define CLEANUP_CALL_AND_POP_PFX(pfx) except_cleanup_pop_pfx(pfx,1)
490 
491 
492 
493 #endif /* __EXCEPTIONS_H__ */