/src/wireshark/epan/exceptions.h
Line | Count | Source (jump to first uncovered line) |
1 | | /** @file |
2 | | * |
3 | | * Wireshark's exceptions. |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
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 | 3.19M | #define XCEPT_GROUP_WIRESHARK 1 |
20 | | |
21 | | /** |
22 | | Index is beyond the captured length of the tvbuff. |
23 | | This generally means that the capture was done with a "slice" |
24 | | length or "snapshot" length less than the maximum packet size, |
25 | | and a link-layer packet was cut short by that, so not all of the |
26 | | data in the link-layer packet was available. |
27 | | **/ |
28 | 164 | #define BoundsError 1 |
29 | | |
30 | | /** |
31 | | Index is beyond the contained length of the tvbuff. |
32 | | This generally means that the tvbuff was constructed as |
33 | | a subset of a parent tvbuff, based on a length specified |
34 | | by data in the packet, but the length in question runs |
35 | | past the reported length of the data in the parent tvbuff. |
36 | | That means that the packet is invalid, as the data indicating |
37 | | the length says the length exceeds what's contained in the |
38 | | packet. It is therefore currently reported as a "Malformed |
39 | | packet". |
40 | | **/ |
41 | 88.4k | #define ContainedBoundsError 2 |
42 | | |
43 | | /** |
44 | | Index is beyond the reported length of the tvbuff. |
45 | | This generally means that the packet is invalid, i.e. whatever |
46 | | code constructed the packet and put it on the wire didn't put enough |
47 | | data into it. It is therefore currently reported as a "Malformed |
48 | | packet". |
49 | | **/ |
50 | 965k | #define ReportedBoundsError 3 |
51 | | |
52 | | /** |
53 | | Index is beyond the contained length, and possibly the reported length, |
54 | | of the tvbuff, but we believe it is an unreassembled fragment, either |
55 | | because the "this is an unreassembled fragment" flag or pinfo->fragmented |
56 | | is set. This means that the packet wasn't reassembled, but could possibly |
57 | | be correctly dissected if reassembly preferences were changed. It is |
58 | | therefore not reported as a "Malformed packet". |
59 | | **/ |
60 | 371k | #define FragmentBoundsError 4 |
61 | | |
62 | | /** |
63 | | During dfilter parsing |
64 | | **/ |
65 | | #define TypeError 5 |
66 | | |
67 | | /** |
68 | | A bug was detected in a dissector. |
69 | | |
70 | | DO NOT throw this with THROW(); that means that no details about |
71 | | the dissector error will be reported. (Instead, the message will |
72 | | blame you for not providing details.) |
73 | | |
74 | | Instead, use the DISSECTOR_ASSERT(), etc. macros in epan/proto.h. |
75 | | **/ |
76 | 636 | #define DissectorError 6 |
77 | | |
78 | | /** |
79 | | Index is out of range. |
80 | | An attempt was made to read past the end of a buffer. |
81 | | This error is specific to SCSI data transfers where for some CDBs |
82 | | it is normal that the data PDU might be short. |
83 | | I.e. ReportLuns initially called with allocation_length=8, just enough |
84 | | to get the "size" of lun list back after which the initiator will |
85 | | reissue the command with an allocation_length that is big enough. |
86 | | **/ |
87 | 0 | #define ScsiBoundsError 7 |
88 | | |
89 | | /** |
90 | | Running out of memory. |
91 | | A dissector tried to allocate memory but that failed. |
92 | | **/ |
93 | | #define OutOfMemoryError 8 |
94 | | |
95 | | /** |
96 | | The reassembly state machine was passed a bad fragment offset, |
97 | | or other similar issues. We used to use DissectorError in these |
98 | | cases, but they're not necessarily the dissector's fault - if the packet |
99 | | contains a bad fragment offset, the dissector shouldn't have to figure |
100 | | that out by itself since that's what the reassembly machine is for. |
101 | | **/ |
102 | 4 | #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 | 467k | CATCH4(ReportedBoundsError, ContainedBoundsError, ScsiBoundsError, ReassemblyError) |
129 | | |
130 | | /* |
131 | | * Catch all bounds-checking errors. |
132 | | */ |
133 | | #define CATCH_BOUNDS_ERRORS \ |
134 | 48.6k | CATCH5(BoundsError, FragmentBoundsError, ReportedBoundsError, \ |
135 | 48.6k | 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 | 614k | CATCH7(BoundsError, FragmentBoundsError, ContainedBoundsError, \ |
144 | 614k | ReportedBoundsError, ScsiBoundsError, DissectorError, \ |
145 | 614k | 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 | 8.19M | #define EXCEPT_CAUGHT 1 /* exception has been caught, no need to rethrow at |
270 | | * ENDTRY */ |
271 | | |
272 | 54.9k | #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 | 204k | #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 | 2.56M | #define TRY \ |
281 | 2.56M | {\ |
282 | 2.56M | except_t *volatile exc; \ |
283 | 2.56M | volatile int except_state = 0; \ |
284 | 2.56M | static const except_id_t catch_spec[] = { \ |
285 | 2.56M | { XCEPT_GROUP_WIRESHARK, XCEPT_CODE_ANY } }; \ |
286 | 2.56M | except_try_push(catch_spec, 1, &exc); \ |
287 | 2.56M | \ |
288 | 2.56M | if(except_state & EXCEPT_CAUGHT) \ |
289 | 2.56M | except_state |= EXCEPT_RETHROWN; \ |
290 | 2.56M | except_state &= ~EXCEPT_CAUGHT; \ |
291 | 2.56M | \ |
292 | 3.19M | if (except_state == 0 && exc == 0) \ |
293 | | /* user's code goes here */ |
294 | | |
295 | | #define ENDTRY \ |
296 | | /* rethrow the exception if necessary */ \ |
297 | 2.50M | if(!(except_state&EXCEPT_CAUGHT) && exc != 0) \ |
298 | 2.50M | except_rethrow(exc); \ |
299 | 2.50M | except_try_pop();\ |
300 | 2.50M | } |
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 | 1.14M | if (except_state == 0 && exc != 0 && \ |
308 | 1.14M | exc->except_id.except_code == (x) && \ |
309 | 1.14M | (except_state |= EXCEPT_CAUGHT)) \ |
310 | | /* user's code goes here */ |
311 | | |
312 | | #define CATCH2(x,y) \ |
313 | 307k | if (except_state == 0 && exc != 0 && \ |
314 | 307k | (exc->except_id.except_code == (x) || \ |
315 | 0 | exc->except_id.except_code == (y)) && \ |
316 | 307k | (except_state|=EXCEPT_CAUGHT)) \ |
317 | | /* user's code goes here */ |
318 | | |
319 | | #define CATCH3(x,y,z) \ |
320 | 834k | if (except_state == 0 && exc != 0 && \ |
321 | 834k | (exc->except_id.except_code == (x) || \ |
322 | 190k | exc->except_id.except_code == (y) || \ |
323 | 190k | exc->except_id.except_code == (z)) && \ |
324 | 834k | (except_state|=EXCEPT_CAUGHT)) \ |
325 | | /* user's code goes here */ |
326 | | |
327 | | #define CATCH4(w,x,y,z) \ |
328 | 467k | if (except_state == 0 && exc != 0 && \ |
329 | 467k | (exc->except_id.except_code == (w) || \ |
330 | 200k | exc->except_id.except_code == (x) || \ |
331 | 200k | exc->except_id.except_code == (y) || \ |
332 | 200k | exc->except_id.except_code == (z)) && \ |
333 | 467k | (except_state|=EXCEPT_CAUGHT)) \ |
334 | | /* user's code goes here */ |
335 | | |
336 | | #define CATCH5(v,w,x,y,z) \ |
337 | 48.6k | if (except_state == 0 && exc != 0 && \ |
338 | 48.6k | (exc->except_id.except_code == (v) || \ |
339 | 1.90k | exc->except_id.except_code == (w) || \ |
340 | 1.90k | exc->except_id.except_code == (x) || \ |
341 | 1.90k | exc->except_id.except_code == (y) || \ |
342 | 1.90k | exc->except_id.except_code == (z)) && \ |
343 | 48.6k | (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 | 614k | if (except_state == 0 && exc != 0 && \ |
359 | 614k | (exc->except_id.except_code == (t) || \ |
360 | 130k | exc->except_id.except_code == (u) || \ |
361 | 130k | exc->except_id.except_code == (v) || \ |
362 | 130k | exc->except_id.except_code == (w) || \ |
363 | 130k | exc->except_id.except_code == (x) || \ |
364 | 130k | exc->except_id.except_code == (y) || \ |
365 | 130k | exc->except_id.except_code == (z)) && \ |
366 | 614k | (except_state|=EXCEPT_CAUGHT)) \ |
367 | | /* user's code goes here */ |
368 | | |
369 | | #define CATCH_ALL \ |
370 | 188k | if (except_state == 0 && exc != 0 && \ |
371 | 183k | (except_state|=EXCEPT_CAUGHT)) \ |
372 | | /* user's code goes here */ |
373 | | |
374 | | #define FINALLY \ |
375 | 103k | if( !(except_state & EXCEPT_FINALLY) && (except_state|=EXCEPT_FINALLY)) \ |
376 | | /* user's code goes here */ |
377 | | |
378 | | #define THROW(x) \ |
379 | 626k | except_throw(XCEPT_GROUP_WIRESHARK, (x), NULL) |
380 | | |
381 | 5.53M | #define THROW_ON(cond, x) G_STMT_START { \ |
382 | 5.53M | if ((cond)) \ |
383 | 5.53M | except_throw(XCEPT_GROUP_WIRESHARK, (x), NULL); \ |
384 | 5.53M | } G_STMT_END |
385 | | |
386 | | #define THROW_MESSAGE(x, y) \ |
387 | 60 | 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 | 0 | 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 | 580 | except_vthrowf(XCEPT_GROUP_WIRESHARK, (x), format, args) |
401 | | |
402 | 310k | #define GET_MESSAGE except_message(exc) |
403 | | |
404 | 54.9k | #define RETHROW \ |
405 | 54.9k | { \ |
406 | 54.9k | /* check we're in a catch block */ \ |
407 | 54.9k | ws_assert(except_state == EXCEPT_CAUGHT); \ |
408 | 54.9k | /* we can't use except_rethrow here, as that pops a catch block \ |
409 | 54.9k | * off the stack, and we don't want to do that, because we want to \ |
410 | 54.9k | * execute the FINALLY {} block first. \ |
411 | 54.9k | * except_throw doesn't provide an interface to rethrow an existing \ |
412 | 54.9k | * exception; however, longjmping back to except_try_push() has the \ |
413 | 54.9k | * desired effect. \ |
414 | 54.9k | * \ |
415 | 54.9k | * Note also that THROW and RETHROW should provide much the same \ |
416 | 54.9k | * functionality in terms of which blocks to enter, so any messing \ |
417 | 54.9k | * about with except_state in here would indicate that THROW is \ |
418 | 54.9k | * doing the wrong thing. \ |
419 | 54.9k | */ \ |
420 | 54.9k | longjmp(except_ch.except_jmp,1); \ |
421 | 54.9k | } |
422 | | |
423 | 310k | #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 | 49.0M | #define CLEANUP_PUSH(f,a) except_cleanup_push((f),(a)) |
489 | 48.8M | #define CLEANUP_POP except_cleanup_pop(0) |
490 | 153k | #define CLEANUP_CALL_AND_POP except_cleanup_pop(1) |
491 | | |
492 | | /* Variants to allow nesting of except_cleanup_push w/o "shadowing" variables */ |
493 | 0 | #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 | 0 | #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 | | */ |