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