#define XCEPT_GROUP_ETHEREAL 1
/* Ethereal's exceptions */
-#define BoundsError 1 /* Index is out of range */
-#define ReportedBoundsError 2 /* Index is beyond reported length (not cap_len) */
-#define TypeError 3 /* During dfilter parsing */
+
+/**
+ Index is out of range.
+ An attempt was made to read past the end of a buffer.
+ 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 reported length (not cap_len)
+ An attempt was made to read past the logical end of a buffer. This
+ differs from a BoundsError in that the parent protocol established a
+ limit past which this dissector should not process in the buffer and that
+ limit was execeeded.
+ 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".
+ However, it also happens in some cases where the packet was fragmented
+ and the fragments weren't reassembled. We need to add another length
+ field to a tvbuff, so that "length of the packet from the link layer"
+ and "length of the packet were it fully reassembled" are different,
+ and going past the first of those without going past the second would
+ throw a different exception, which would be reported as an "Unreassembled
+ packet" rather than a "Malformed packet".
+**/
+#define ReportedBoundsError 2
+
+/**
+ During dfilter parsing
+**/
+#define TypeError 3
+
+/**
+ 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 4
+
+/**
+ 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 5
+
/* Usage:
*
* This is really something like:
*
* {
- * x = setjmp()
+ * caught = FALSE:
+ * x = setjmp();
* if (x == 0) {
* <TRY code>
* }
- * else if (x == 1) {
+ * if (!caught && x == 1) {
+ * caught = TRUE;
* <CATCH(1) code>
* }
- * else if (x == 2) {
+ * if (!caught && x == 2) {
+ * caught = TRUE;
* <CATCH(2) code>
* }
- * else if (x == 3 || x == 4) {
+ * if (!caught && (x == 3 || x == 4)) {
+ * caught = TRUE;
* <CATCH2(3,4) code>
* }
- * else {
- * <CATCH_ALL 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.
* 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
+ * END_TRY */
+
+#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 END_TRY */
+#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 *exc; \
+ volatile int except_state = 0; \
static const except_id_t catch_spec[] = { \
{ XCEPT_GROUP_ETHEREAL, XCEPT_CODE_ANY } }; \
except_try_push(catch_spec, 1, &exc); \
- if (exc == 0) { \
+ \
+ 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) \
- } \
- else if (exc->except_id.except_code == (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) \
- } \
- else if (exc->except_id.except_code == (x) || exc->except_id.except_code == (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 CATCH_ALL \
- } \
- else { \
+ 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_ETHEREAL, (x), "XCEPT_GROUP_ETHEREAL")
+ except_throw(XCEPT_GROUP_ETHEREAL, (x), NULL)
#define THROW_MESSAGE(x, y) \
except_throw(XCEPT_GROUP_ETHEREAL, (x), (y))
#define GET_MESSAGE except_message(exc)
-#define RETHROW except_rethrow(exc)
+#define RETHROW \
+ { \
+ /* check we're in a catch block */ \
+ g_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)