Wireshark 4.5.0
The Wireshark network protocol analyzer
Loading...
Searching...
No Matches
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 */