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