diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2010-03-19 09:41:18 +0100 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2010-03-19 09:41:18 +0100 |
commit | aa4612480424ad2fede0cd4ae4c7a893f61c6c0f (patch) | |
tree | 8241b7e72a8eb2f243f566cd81b072ccdb8ca183 | |
parent | 74e9331fe0892c4c96b4c4d7db3f14bb7e9d928e (diff) | |
download | bird-aa4612480424ad2fede0cd4ae4c7a893f61c6c0f.tar bird-aa4612480424ad2fede0cd4ae4c7a893f61c6c0f.zip |
Clear local variables in filters and functions.
Fixes crash when used uninitialized variables.
This problem was surprisingly tricky to fix.
-rw-r--r-- | filter/config.Y | 9 | ||||
-rw-r--r-- | filter/filter.c | 30 | ||||
-rw-r--r-- | filter/test.conf | 14 |
3 files changed, 30 insertions, 23 deletions
diff --git a/filter/config.Y b/filter/config.Y index fcbee71..1af5649 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -172,7 +172,14 @@ function_params: function_body: decls '{' cmds '}' { - $$ = $3; + if ($1) { + /* Prepend instruction to clear local variables */ + $$ = f_new_inst(); + $$->code = P('c','v'); + $$->a1.p = $1; + $$->next = $3; + } else + $$ = $3; } ; diff --git a/filter/filter.c b/filter/filter.c index bfb480a..de7a97b 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -473,27 +473,10 @@ interpret(struct f_inst *what) case 's': ARG(v2, a2.p); sym = what->a1.p; - switch (res.type = v2.type) { - case T_VOID: runtime( "Can't assign void values" ); - case T_ENUM: - case T_BOOL: - case T_INT: - case T_PAIR: - case T_STRING: - case T_IP: - case T_PREFIX: - case T_PREFIX_SET: - case T_SET: - case T_PATH: - case T_PATH_MASK: - case T_CLIST: - if (sym->class != (SYM_VARIABLE | v2.type)) - runtime( "Assigning to variable of incompatible type" ); - * (struct f_val *) sym->def = v2; - break; - default: - bug( "Set to invalid type" ); - } + if ((sym->class != (SYM_VARIABLE | v2.type)) && + (v2.type != T_VOID)) + runtime( "Assigning to variable of incompatible type" ); + * (struct f_val *) sym->def = v2; break; /* some constants have value in a2, some in *a1.p, strange. */ @@ -766,6 +749,10 @@ interpret(struct f_inst *what) return res; res.type &= ~T_RETURN; break; + case P('c','v'): /* Clear local variables */ + for (sym = what->a1.p; sym != NULL; sym = sym->aux2) + ((struct f_val *) sym->def)->type = T_VOID; + break; case P('S','W'): ONEARG; { @@ -948,6 +935,7 @@ i_same(struct f_inst *f1, struct f_inst *f2) return 0; f2->a2.p = f1->a2.p; break; + case P('c','v'): break; /* internal instruction */ case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break; case P('i','M'): TWOARGS; break; case P('A','p'): TWOARGS; break; diff --git a/filter/test.conf b/filter/test.conf index 395699b..8eeb5c3 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -75,7 +75,7 @@ clist l; p2 = prepend( p2, 1 ); print "Should be true: ", p2 ~ pm1, " ", p2, " ", pm1; - l = - empty -; +# l = - empty -; l = add( l, (1,2) ); l = add( l, (2,3) ); print "Community list (1,2) (2,3) ", l; @@ -124,6 +124,14 @@ function test_pxset(prefix set pxs) 11.0.0.0/10 ~ pxs, ",", 20.1.0.0/26 ~ pxs; } +function test_undef(int a) +int b; +{ + if a = 3 + then b = 4; + print "Defined: ", a, " ", b, " ", defined(b); +} + function __startup() int i; bool b; @@ -218,6 +226,10 @@ string s; print "1.2.3.4 = ", onetwo; + test_undef(2); + test_undef(3); + test_undef(2); + print "done"; quitbird; # print "*** FAIL: this is unreachable"; |