aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGilbert Ramirez <gram@alumni.rice.edu>2005-08-04 13:54:46 +0000
committerGilbert Ramirez <gram@alumni.rice.edu>2005-08-04 13:54:46 +0000
commitc8cd8f21a4431b1880ce3360553e0abd4861cf99 (patch)
tree27a5d61208c07301e13843fac71cef1a58cb686c
parent2c65361b8a25d69d560dfc88d4abf14e91cd1dbd (diff)
Exception handling fixes, and a fix to packet-frame.c,
from Richard van der Hoff. svn path=/trunk/; revision=15205
-rw-r--r--AUTHORS1
-rw-r--r--epan/Makefile.am8
-rw-r--r--epan/dissectors/packet-frame.c9
-rw-r--r--epan/exceptions.h84
-rw-r--r--epan/exntest.c202
5 files changed, 286 insertions, 18 deletions
diff --git a/AUTHORS b/AUTHORS
index 6e0dc8737f..c11f31b919 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2188,6 +2188,7 @@ Dominic Béchaz <bdo [AT] zhwin.ch> {
Richard van der Hoff <richardv [AT] mxtelecom.com> {
IAX2 updates
CRC16 routines
+ Exception logic fixes
}
Shaun Jackman <sjackman [AT] telus.net> {
diff --git a/epan/Makefile.am b/epan/Makefile.am
index ca564fe335..f0de38dd4c 100644
--- a/epan/Makefile.am
+++ b/epan/Makefile.am
@@ -57,6 +57,7 @@ EXTRA_DIST = \
make-sminmpec.pl \
radius_dict.l \
tvbtest.c \
+ exntest.c \
doxygen.cfg.in
CLEANFILES = \
@@ -77,11 +78,16 @@ libethereal_la_LIBADD = @G_ASCII_STRTOULL_LO@ @INET_ATON_LO@ @INET_PTON_LO@ @INE
libethereal_la_DEPENDENCIES = @G_ASCII_STRTOULL_LO@ @INET_ATON_LO@ @INET_PTON_LO@ @INET_NTOP_LO@ dfilter/libdfilter.la ftypes/libftypes.la dissectors/libdissectors.la
tvbtest: tvbtest.o tvbuff.o except.o strutil.o
- $(LINK) -o tvbtest tvbtest.o tvbuff.o except.o strutil.o `glib-config --libs`
+ $(LINK) $^ $(GLIB_LIBS) -lz
+
+exntest: exntest.o except.o
+ $(LINK) $^ $(GLIB_LIBS)
radius_dict.c: radius_dict.l
$(LEX) radius_dict.l
+tvbtest.o exntest.o: exceptions.h
+
sminmpec.c: enterprise-numbers make-sminmpec.pl
$(PERL) make-sminmpec.pl enterprise-numbers sminmpec.c
diff --git a/epan/dissectors/packet-frame.c b/epan/dissectors/packet-frame.c
index 2aa4fba4e3..aa2c705b11 100644
--- a/epan/dissectors/packet-frame.c
+++ b/epan/dissectors/packet-frame.c
@@ -198,6 +198,15 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
0, 0, cap_len, "Capture Length: %d byte%s", cap_len,
plurality(cap_len, "", "s"));
+ /* we are going to be using proto_item_append_string() on
+ * hf_frame_protocols, and we must therefore disable the
+ * TRY_TO_FAKE_THIS_ITEM() optimisation for the tree by
+ * setting it as visible.
+ *
+ * See proto.h for details.
+ */
+ PTREE_DATA(fh_tree)->visible=1;
+
ti = proto_tree_add_string(fh_tree, hf_frame_protocols, tvb,
0, 0, "");
PROTO_ITEM_SET_GENERATED(ti);
diff --git a/epan/exceptions.h b/epan/exceptions.h
index 66bbcce485..355224e930 100644
--- a/epan/exceptions.h
+++ b/epan/exceptions.h
@@ -81,23 +81,31 @@
* 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.
@@ -125,40 +133,65 @@
* 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) \
@@ -169,7 +202,24 @@
#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)
diff --git a/epan/exntest.c b/epan/exntest.c
new file mode 100644
index 0000000000..3d6b63b385
--- /dev/null
+++ b/epan/exntest.c
@@ -0,0 +1,202 @@
+/* Standalone program to test functionality of exceptions.
+ *
+ * $Id$
+ *
+ * Copyright (c) 2004 MX Telecom Ltd. <richardv@mxtelecom.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include "exceptions.h"
+
+gboolean failed = FALSE;
+
+void
+run_tests(void)
+{
+ volatile unsigned int ex_thrown, finally_called;
+
+ /* check that the right catch, and the finally, are called, on exception */
+ ex_thrown = finally_called = 0;
+ TRY {
+ THROW(BoundsError);
+ }
+ CATCH(BoundsError) {
+ ex_thrown++;
+ }
+ CATCH(ReportedBoundsError) {
+ printf("01: Caught wrong exception: ReportedBoundsError\n");
+ failed = TRUE;
+ }
+ CATCH_ALL {
+ printf("01: Caught wrong exception: %lu\n", exc->except_id.except_code);
+ failed = TRUE;
+ }
+ FINALLY {
+ finally_called ++;
+ }
+ ENDTRY;
+
+ if (ex_thrown != 1) {
+ printf("01: %u BoundsErrors (not 1) on caught exception\n", ex_thrown);
+ failed = TRUE;
+ }
+
+ if (finally_called != 1) {
+ printf("01: FINALLY called %u times (not 1) on caught exception\n", finally_called);
+ failed = TRUE;
+ }
+
+
+ /* check that no catch at all is called when there is no exn */
+ ex_thrown = finally_called = 0;
+ TRY {
+ }
+ CATCH(BoundsError) {
+ printf("02: Caught wrong exception: BoundsError\n");
+ failed = TRUE;
+ }
+ CATCH(ReportedBoundsError) {
+ printf("02: Caught wrong exception: ReportedBoundsError\n");
+ failed = TRUE;
+ }
+ CATCH_ALL {
+ printf("02: Caught wrong exception: %lu\n", exc->except_id.except_code);
+ failed = TRUE;
+ }
+ FINALLY {
+ finally_called ++;
+ }
+ ENDTRY;
+
+ if (finally_called != 1) {
+ printf("02: FINALLY called %u times (not 1) on no exception\n", finally_called);
+ failed = TRUE;
+ }
+
+
+ /* check that finally is called on an uncaught exception */
+ ex_thrown = finally_called = 0;
+ TRY {
+ TRY {
+ THROW(BoundsError);
+ }
+ FINALLY {
+ finally_called ++;
+ }
+ ENDTRY;
+ }
+ CATCH(BoundsError) {
+ ex_thrown++;
+ }
+ ENDTRY;
+
+ if (finally_called != 1) {
+ printf("03: FINALLY called %u times (not 1) on uncaught exception\n", finally_called);
+ failed = TRUE;
+ }
+
+ if (ex_thrown != 1) {
+ printf("03: %u BoundsErrors (not 1) on uncaught exception\n", ex_thrown);
+ failed = TRUE;
+ }
+
+
+ /* check that finally is called on an rethrown exception */
+ ex_thrown = finally_called = 0;
+ TRY {
+ TRY {
+ THROW(BoundsError);
+ }
+ CATCH_ALL {
+ ex_thrown += 10;
+ RETHROW;
+ }
+ FINALLY {
+ finally_called += 10;
+ }
+ ENDTRY;
+ }
+ CATCH(BoundsError) {
+ ex_thrown ++;
+ }
+ FINALLY {
+ finally_called ++;
+ }
+ ENDTRY;
+
+ if (finally_called != 11) {
+ printf("04: finally_called = %u (not 11) on rethrown exception\n", finally_called);
+ failed = TRUE;
+ }
+
+ if (ex_thrown != 11) {
+ printf("04: %u BoundsErrors (not 11) on rethrown exception\n", ex_thrown);
+ failed = TRUE;
+ }
+
+
+ /* check that finally is called on an exception thrown from a CATCH block */
+ ex_thrown = finally_called = 0;
+ TRY {
+ TRY {
+ THROW(BoundsError);
+ }
+ CATCH_ALL {
+ if(ex_thrown > 0) {
+ printf("05: Looping exception\n");
+ failed = TRUE;
+ } else {
+ ex_thrown += 10;
+ THROW(BoundsError);
+ }
+ }
+ FINALLY {
+ finally_called += 10;
+ }
+ ENDTRY;
+ }
+ CATCH(BoundsError) {
+ ex_thrown ++;
+ }
+ FINALLY {
+ finally_called ++;
+ }
+ ENDTRY;
+
+ if (finally_called != 11) {
+ printf("05: finally_called = %u (not 11) on exception thrown from CATCH\n", finally_called);
+ failed = TRUE;
+ }
+
+ if (ex_thrown != 11) {
+ printf("05: %u BoundsErrors (not 11) on exception thrown from CATCH\n", ex_thrown);
+ failed = TRUE;
+ }
+
+ if(failed == FALSE )
+ printf("success\n");
+}
+
+int main(void)
+{
+ except_init();
+ run_tests();
+ except_deinit();
+ exit(failed?1:0);
+}