diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/exceptions.h | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/exceptions.h')
-rw-r--r-- | epan/exceptions.h | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/epan/exceptions.h b/epan/exceptions.h new file mode 100644 index 00000000..8841e454 --- /dev/null +++ b/epan/exceptions.h @@ -0,0 +1,512 @@ +/** @file + * + * Wireshark's exceptions. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef __EXCEPTIONS_H__ +#define __EXCEPTIONS_H__ + +#include "except.h" +#include <wsutil/ws_assert.h> + +/* Wireshark has only one exception group, to make these macros simple */ +#define XCEPT_GROUP_WIRESHARK 1 + +/** + Index is beyond the captured length of the tvbuff. + This generally means that the capture was done with a "slice" + length or "snapshot" length less than the maximum packet size, + and a link-layer packet was cut short by that, so not all of the + data in the link-layer packet was available. +**/ +#define BoundsError 1 + +/** + Index is beyond the contained length of the tvbuff. + This generally means that the tvbuff was constructed as + a subset of a parent tvbuff, based on a length specified + by data in the packet, but the length in question runs + past the reported length of the data in the parent tvbuff. + That means that the packet is invalid, as the data indicating + the length says the length exceeds what's contained in the + packet. It is therefore currently reported as a "Malformed + packet". +**/ +#define ContainedBoundsError 2 + +/** + Index is beyond the reported length of the tvbuff. + This generally means that the packet is invalid, i.e. whatever + code constructed the packet and put it on the wire didn't put enough + data into it. It is therefore currently reported as a "Malformed + packet". +**/ +#define ReportedBoundsError 3 + +/** + Index is beyond the contained length, and possibly the reported length, + of the tvbuff, but we believe it is an unreassembled fragment, either + because the "this is an unreassembled fragment" flag or pinfo->fragmented + is set. This means that the packet wasn't reassembled, but could possibly + be correctly dissected if reassembly preferences were changed. It is + therefore not reported as a "Malformed packet". +**/ +#define FragmentBoundsError 4 + +/** + During dfilter parsing +**/ +#define TypeError 5 + +/** + A bug was detected in a dissector. + + DO NOT throw this with THROW(); that means that no details about + the dissector error will be reported. (Instead, the message will + blame you for not providing details.) + + Instead, use the DISSECTOR_ASSERT(), etc. macros in epan/proto.h. +**/ +#define DissectorError 6 + +/** + Index is out of range. + An attempt was made to read past the end of a buffer. + This error is specific to SCSI data transfers where for some CDBs + it is normal that the data PDU might be short. + I.e. ReportLuns initially called with allocation_length=8, just enough + to get the "size" of lun list back after which the initiator will + reissue the command with an allocation_length that is big enough. +**/ +#define ScsiBoundsError 7 + +/** + Running out of memory. + A dissector tried to allocate memory but that failed. +**/ +#define OutOfMemoryError 8 + +/** + The reassembly state machine was passed a bad fragment offset, + or other similar issues. We used to use DissectorError in these + cases, but they're not necessarily the dissector's fault - if the packet + contains a bad fragment offset, the dissector shouldn't have to figure + that out by itself since that's what the reassembly machine is for. +**/ +#define ReassemblyError 9 + +/* + * Catch errors that, if you're calling a subdissector and catching + * exceptions from the subdissector, and possibly dissecting more + * stuff after the subdissector returns or fails, mean it makes + * sense to continue dissecting: + * + * BoundsError indicates a configuration problem (the capture was + * set up to throw away data, and it did); there's no point in + * trying to dissect any more data, as there's no more data to dissect. + * + * FragmentBoundsError indicates a configuration problem (reassembly + * wasn't enabled or couldn't be done); there's no point in trying + * to dissect any more data, as there's no more data to dissect. + * + * OutOfMemoryError indicates what its name suggests; there's no point + * in trying to dissect any more data, as you're probably not going to + * have any more memory to use when dissecting them. + * + * Other errors indicate that there's some sort of problem with + * the packet; you should continue dissecting data, as it might + * be OK, and, even if it's not, you should report its problem + * separately. + */ +#define CATCH_NONFATAL_ERRORS \ + CATCH4(ReportedBoundsError, ContainedBoundsError, ScsiBoundsError, ReassemblyError) + +/* + * Catch all bounds-checking errors. + */ +#define CATCH_BOUNDS_ERRORS \ + CATCH5(BoundsError, FragmentBoundsError, ReportedBoundsError, \ + ContainedBoundsError, ScsiBoundsError) + +/* + * Catch all bounds-checking errors, and catch dissector bugs. + * Should only be used at the top level, so that dissector bugs + * go all the way to the top level and get reported immediately. + */ +#define CATCH_BOUNDS_AND_DISSECTOR_ERRORS \ + CATCH7(BoundsError, FragmentBoundsError, ContainedBoundsError, \ + ReportedBoundsError, ScsiBoundsError, DissectorError, \ + ReassemblyError) + +/* Usage: + * + * TRY { + * code; + * } + * + * CATCH(exception) { + * code; + * } + * + * CATCH2(exception1, exception2) { + * code; + * } + * + * CATCH3(exception1, exception2, exception3) { + * code; + * } + * + * CATCH4(exception1, exception2, exception3, exception4) { + * code; + * } + * + * CATCH5(exception1, exception2, exception3, exception4, exception5) { + * code; + * } + * + * CATCH6(exception1, exception2, exception3, exception4, exception5, exception6) { + * code; + * } + * + * CATCH7(exception1, exception2, exception3, exception4, exception5, exception6, exception7) { + * code; + * } + * + * CATCH_NONFATAL_ERRORS { + * code; + * } + * + * CATCH_BOUNDS_ERRORS { + * code; + * } + * + * CATCH_BOUNDS_AND_DISSECTOR_ERRORS { + * code; + * } + * + * CATCH_ALL { + * code; + * } + * + * FINALLY { + * code; + * } + * + * ENDTRY; + * + * ********* Never use 'goto' or 'return' inside the TRY, CATCH*, or + * ********* FINALLY blocks. Execution must proceed through ENDTRY before + * ********* branching out. + * + * This is really something like: + * + * { + * caught = FALSE: + * x = setjmp(); + * if (x == 0) { + * <TRY code> + * } + * if (!caught && x == 1) { + * caught = TRUE; + * <CATCH(1) code> + * } + * if (!caught && x == 2) { + * caught = TRUE; + * <CATCH(2) code> + * } + * if (!caught && (x == 3 || x == 4)) { + * caught = TRUE; + * <CATCH2(3,4) code> + * } + * if (!caught && (x == 5 || x == 6 || x == 7)) { + * caught = TRUE; + * <CATCH3(5,6,7) code> + * } + * if (!caught && x != 0) { + * caught = TRUE; + * <CATCH_ALL code> + * } + * <FINALLY code> + * if(!caught) { + * RETHROW(x) + * } + * }<ENDTRY tag> + * + * All CATCH's must precede a CATCH_ALL. + * FINALLY must occur after any CATCH or CATCH_ALL. + * ENDTRY marks the end of the TRY code. + * TRY and ENDTRY are the mandatory parts of a TRY block. + * CATCH, CATCH_ALL, and FINALLY are all optional (although + * you'll probably use at least one, otherwise why "TRY"?) + * + * GET_MESSAGE returns string ptr to exception message + * when exception is thrown via THROW_MESSAGE() + * + * To throw/raise an exception. + * + * THROW(exception) + * RETHROW rethrow the caught exception + * + * A cleanup callback is a function called in case an exception occurs + * and is not caught. It should be used to free any dynamically-allocated data. + * A pop or call_and_pop should occur at the same statement-nesting level + * as the push. + * + * CLEANUP_CB_PUSH(func, data) + * CLEANUP_CB_POP + * CLEANUP_CB_CALL_AND_POP + */ + +/* we do up to three passes through the bit of code after except_try_push(), + * and except_state is used to keep track of where we are. + */ +#define EXCEPT_CAUGHT 1 /* exception has been caught, no need to rethrow at + * ENDTRY */ + +#define EXCEPT_RETHROWN 2 /* the exception was rethrown from a CATCH + * block. Don't reenter the CATCH blocks, but do + * execute FINALLY and rethrow at ENDTRY */ + +#define EXCEPT_FINALLY 4 /* we've entered the FINALLY block - don't allow + * RETHROW, and don't reenter FINALLY if a + * different exception is thrown */ + +#define TRY \ +{\ + except_t *volatile exc; \ + volatile int except_state = 0; \ + static const except_id_t catch_spec[] = { \ + { XCEPT_GROUP_WIRESHARK, XCEPT_CODE_ANY } }; \ + except_try_push(catch_spec, 1, &exc); \ + \ + if(except_state & EXCEPT_CAUGHT) \ + except_state |= EXCEPT_RETHROWN; \ + except_state &= ~EXCEPT_CAUGHT; \ + \ + if (except_state == 0 && exc == 0) \ + /* user's code goes here */ + +#define ENDTRY \ + /* rethrow the exception if necessary */ \ + if(!(except_state&EXCEPT_CAUGHT) && exc != 0) \ + except_rethrow(exc); \ + except_try_pop();\ +} + +/* the (except_state |= EXCEPT_CAUGHT) in the below is a way of setting + * except_state before the user's code, without disrupting the user's code if + * it's a one-liner. + */ +#define CATCH(x) \ + if (except_state == 0 && exc != 0 && \ + exc->except_id.except_code == (x) && \ + (except_state |= EXCEPT_CAUGHT)) \ + /* user's code goes here */ + +#define CATCH2(x,y) \ + if (except_state == 0 && exc != 0 && \ + (exc->except_id.except_code == (x) || \ + exc->except_id.except_code == (y)) && \ + (except_state|=EXCEPT_CAUGHT)) \ + /* user's code goes here */ + +#define CATCH3(x,y,z) \ + if (except_state == 0 && exc != 0 && \ + (exc->except_id.except_code == (x) || \ + exc->except_id.except_code == (y) || \ + exc->except_id.except_code == (z)) && \ + (except_state|=EXCEPT_CAUGHT)) \ + /* user's code goes here */ + +#define CATCH4(w,x,y,z) \ + if (except_state == 0 && exc != 0 && \ + (exc->except_id.except_code == (w) || \ + exc->except_id.except_code == (x) || \ + exc->except_id.except_code == (y) || \ + exc->except_id.except_code == (z)) && \ + (except_state|=EXCEPT_CAUGHT)) \ + /* user's code goes here */ + +#define CATCH5(v,w,x,y,z) \ + if (except_state == 0 && exc != 0 && \ + (exc->except_id.except_code == (v) || \ + exc->except_id.except_code == (w) || \ + exc->except_id.except_code == (x) || \ + exc->except_id.except_code == (y) || \ + exc->except_id.except_code == (z)) && \ + (except_state|=EXCEPT_CAUGHT)) \ + /* user's code goes here */ + +#define CATCH6(u,v,w,x,y,z) \ + if (except_state == 0 && exc != 0 && \ + (exc->except_id.except_code == (u) || \ + exc->except_id.except_code == (v) || \ + exc->except_id.except_code == (w) || \ + exc->except_id.except_code == (x) || \ + exc->except_id.except_code == (y) || \ + exc->except_id.except_code == (z)) && \ + (except_state|=EXCEPT_CAUGHT)) \ + /* user's code goes here */ + +#define CATCH7(t,u,v,w,x,y,z) \ + if (except_state == 0 && exc != 0 && \ + (exc->except_id.except_code == (t) || \ + exc->except_id.except_code == (u) || \ + exc->except_id.except_code == (v) || \ + exc->except_id.except_code == (w) || \ + exc->except_id.except_code == (x) || \ + exc->except_id.except_code == (y) || \ + exc->except_id.except_code == (z)) && \ + (except_state|=EXCEPT_CAUGHT)) \ + /* user's code goes here */ + +#define CATCH_ALL \ + if (except_state == 0 && exc != 0 && \ + (except_state|=EXCEPT_CAUGHT)) \ + /* user's code goes here */ + +#define FINALLY \ + if( !(except_state & EXCEPT_FINALLY) && (except_state|=EXCEPT_FINALLY)) \ + /* user's code goes here */ + +#define THROW(x) \ + except_throw(XCEPT_GROUP_WIRESHARK, (x), NULL) + +#define THROW_ON(cond, x) G_STMT_START { \ + if ((cond)) \ + except_throw(XCEPT_GROUP_WIRESHARK, (x), NULL); \ +} G_STMT_END + +#define THROW_MESSAGE(x, y) \ + except_throw(XCEPT_GROUP_WIRESHARK, (x), (y)) + +#define THROW_MESSAGE_ON(cond, x, y) G_STMT_START { \ + if ((cond)) \ + except_throw(XCEPT_GROUP_WIRESHARK, (x), (y)); \ +} G_STMT_END + +/* Throws a formatted message, its memory is cleared after catching it. */ +#define THROW_FORMATTED(x, ...) \ + except_throwf(XCEPT_GROUP_WIRESHARK, (x), __VA_ARGS__) + +/* Like THROW_FORMATTED, but takes a va_list as an argument */ +#define VTHROW_FORMATTED(x, format, args) \ + except_vthrowf(XCEPT_GROUP_WIRESHARK, (x), format, args) + +#define GET_MESSAGE except_message(exc) + +#define RETHROW \ +{ \ + /* check we're in a catch block */ \ + ws_assert(except_state == EXCEPT_CAUGHT); \ + /* we can't use except_rethrow here, as that pops a catch block \ + * off the stack, and we don't want to do that, because we want to \ + * excecute the FINALLY {} block first. \ + * except_throw doesn't provide an interface to rethrow an existing \ + * exception; however, longjmping back to except_try_push() has the \ + * desired effect. \ + * \ + * Note also that THROW and RETHROW should provide much the same \ + * functionality in terms of which blocks to enter, so any messing \ + * about with except_state in here would indicate that THROW is \ + * doing the wrong thing. \ + */ \ + longjmp(except_ch.except_jmp,1); \ +} + +#define EXCEPT_CODE except_code(exc) + +/* Register cleanup functions in case an exception is thrown and not caught. + * From the Kazlib documentation, with modifications for use with the + * Wireshark-specific macros: + * + * CLEANUP_PUSH(func, arg) + * + * The call to CLEANUP_PUSH shall be matched with a call to + * CLEANUP_CALL_AND_POP or CLEANUP_POP which must occur in the same + * statement block at the same level of nesting. This requirement allows + * an implementation to provide a CLEANUP_PUSH macro which opens up a + * statement block and a CLEANUP_POP which closes the statement block. + * The space for the registered pointers can then be efficiently + * allocated from automatic storage. + * + * The CLEANUP_PUSH macro registers a cleanup handler that will be + * called if an exception subsequently occurs before the matching + * CLEANUP_[CALL_AND_]POP is executed, and is not intercepted and + * handled by a try-catch region that is nested between the two. + * + * The first argument to CLEANUP_PUSH is a pointer to the cleanup + * handler, a function that returns nothing and takes a single + * argument of type void*. The second argument is a void* value that + * is registered along with the handler. This value is what is passed + * to the registered handler, should it be called. + * + * Cleanup handlers are called in the reverse order of their nesting: + * inner handlers are called before outer handlers. + * + * The program shall not leave the cleanup region between + * the call to the macro CLEANUP_PUSH and the matching call to + * CLEANUP_[CALL_AND_]POP by means other than throwing an exception, + * or calling CLEANUP_[CALL_AND_]POP. + * + * Within the call to the cleanup handler, it is possible that new + * exceptions may happen. Such exceptions must be handled before the + * cleanup handler terminates. If the call to the cleanup handler is + * terminated by an exception, the behavior is undefined. The exception + * which triggered the cleanup is not yet caught; thus the program + * would be effectively trying to replace an exception with one that + * isn't in a well-defined state. + * + * + * CLEANUP_POP and CLEANUP_CALL_AND_POP + * + * A call to the CLEANUP_POP or CLEANUP_CALL_AND_POP macro shall match + * each call to CLEANUP_PUSH which shall be in the same statement block + * at the same nesting level. It shall match the most recent such a + * call that is not matched by a previous CLEANUP_[CALL_AND_]POP at + * the same level. + * + * These macros causes the registered cleanup handler to be removed. If + * CLEANUP_CALL_AND_POP is called, the cleanup handler is called. + * In that case, the registered context pointer is passed to the cleanup + * handler. If CLEANUP_POP is called, the cleanup handler is not called. + * + * The program shall not leave the region between the call to the + * macro CLEANUP_PUSH and the matching call to CLEANUP_[CALL_AND_]POP + * other than by throwing an exception, or by executing the + * CLEANUP_CALL_AND_POP. + * + */ + + +#define CLEANUP_PUSH(f,a) except_cleanup_push((f),(a)) +#define CLEANUP_POP except_cleanup_pop(0) +#define CLEANUP_CALL_AND_POP except_cleanup_pop(1) + +/* Variants to allow nesting of except_cleanup_push w/o "shadowing" variables */ +#define CLEANUP_PUSH_PFX(pfx,f,a) except_cleanup_push_pfx(pfx,(f),(a)) +#define CLEANUP_POP_PFX(pfx) except_cleanup_pop_pfx(pfx,0) +#define CLEANUP_CALL_AND_POP_PFX(pfx) except_cleanup_pop_pfx(pfx,1) + + + +#endif /* __EXCEPTIONS_H__ */ + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ |