diff options
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | epan/Makefile.am | 8 | ||||
-rw-r--r-- | epan/dissectors/packet-frame.c | 9 | ||||
-rw-r--r-- | epan/exceptions.h | 84 | ||||
-rw-r--r-- | epan/exntest.c | 202 |
5 files changed, 286 insertions, 18 deletions
@@ -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); +} |