From 14cc2f2806c7b66992ca4a41d6f8da6020931194 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sun, 9 Mar 2008 10:04:03 +0000 Subject: Name clashes between constants and variables went unnoticed by the compiler. Bug reported by Thomas Lynch. Fix this and rename exception codes to minimize chances of such clashes. * src/symtab.c (lookup_or_install): Allow to search using state masks. (variable_or_constant_lookup): New function. (constant_lookup): Return const struct constant *. (constant_lookup_value): New function. * src/lex.l (get_const): Remove. (variable_or_const): New function. * src/gram.y: Display warnings on a clash of constant and variable names. (VARIABLE): Change union type to var. Modify `variable' production accordingly. * src/mailfromd.h (_SYM_COUNT,SYM_MASK,SYM_BITS): New defines. (constant_lookup): Return const struct constant *. (constant_lookup_value): New function. (variable_or_constant_lookup): New function. * src/status.mfi: Prefix exception codes with `e_' to avoid name clashes. Provide backward-compatible constants. * mflib/match_dnsbl.mf (match_dnsbl): Rename range to iprange to avoid name clashes with the exception code. Remove buggy conditions. Provide a correctly working replacement for them if the m3 symbol `COMPAT_4_3' is defined. * mflib/match_rhsbl.mf (match_rhsbl): Rename range to iprange to avoid name clashes with the exception code. Remove buggy conditions. Provide a correctly working replacement for them if the m3 symbol `COMPAT_4_3' is defined. * mflib/match_cidr.mf, mflib/safedb.mf4, tests/etc/catch.rc, tests/etc/catch01.rc: Use new exception codes. git-svn-id: file:///svnroot/mailfromd/branches/release_4_3_patches@1627 7a8a7f39-df28-0410-adc6-e0d955640f24 --- ChangeLog | 36 ++++++++++++++++++++++++++++++++++++ mflib/match_cidr.mf | 4 ++-- mflib/match_dnsbl.mf | 20 ++++++++++---------- mflib/match_rhsbl.mf | 12 ++++++++---- mflib/safedb.mf4 | 6 +++--- src/gram.y | 50 +++++++++++++++++++++++++++++++++++++------------- src/lex.l | 41 ++++++++++++++++++++++++++--------------- src/mailfromd.h | 10 ++++++++-- src/status.mfi | 20 +++++++++++++++++++- src/symtab.c | 38 +++++++++++++++++++++++++++++++++----- tests/etc/catch.rc | 4 ++-- tests/etc/catch01.rc | 6 +++--- 12 files changed, 187 insertions(+), 60 deletions(-) diff --git a/ChangeLog b/ChangeLog index f1ecc135..9abbf87e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +2008-03-09 Sergey Poznyakoff + + Name clashes between constants and variables went unnoticed by the + compiler. Bug reported by Thomas Lynch. + Fix this and rename exception codes to minimize chances of such + clashes. + + * src/symtab.c (lookup_or_install): Allow to search using state + masks. + (variable_or_constant_lookup): New function. + (constant_lookup): Return const struct constant *. + (constant_lookup_value): New function. + * src/lex.l (get_const): Remove. + (variable_or_const): New function. + * src/gram.y: Display warnings on a clash of constant and variable + names. + (VARIABLE): Change union type to var. Modify `variable' production + accordingly. + * src/mailfromd.h (_SYM_COUNT,SYM_MASK,SYM_BITS): New defines. + (constant_lookup): Return const struct constant *. + (constant_lookup_value): New function. + (variable_or_constant_lookup): New function. + * src/status.mfi: Prefix exception codes with `e_' to avoid name + clashes. + Provide backward-compatible constants. + * mflib/match_dnsbl.mf (match_dnsbl): Rename range to iprange to + avoid name clashes with the exception code. + Remove buggy conditions. Provide a correctly working replacement + for them if the m3 symbol `COMPAT_4_3' is defined. + * mflib/match_rhsbl.mf (match_rhsbl): Rename range to iprange to + avoid name clashes with the exception code. + Remove buggy conditions. Provide a correctly working replacement + for them if the m3 symbol `COMPAT_4_3' is defined. + * mflib/match_cidr.mf, mflib/safedb.mf4, tests/etc/catch.rc, + tests/etc/catch01.rc: Use new exception codes. + 2008-03-01 Sergey Poznyakoff * src/prog.c, src/prog.h (advance_pc): Fix type of the 2nd diff --git a/mflib/match_cidr.mf b/mflib/match_cidr.mf index bb3470ad..24220ab4 100644 --- a/mflib/match_cidr.mf +++ b/mflib/match_cidr.mf @@ -1,5 +1,5 @@ /* Implementation of match_cidr call - Copyright (C) 2007 Sergey Poznyakoff + Copyright (C) 2007, 2008 Sergey Poznyakoff 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 @@ -25,7 +25,7 @@ do if %cidr matches '^(([0-9]{1,3}\.){3}[0-9]{1,3})/([0-9][0-9]?)' return inet_aton(%ipstr) & len_to_netmask(\3) = inet_aton(\1) else - throw invcidr "invalid CIDR (%cidr)" + throw e_invcidr "invalid CIDR (%cidr)" fi return 0 done diff --git a/mflib/match_dnsbl.mf b/mflib/match_dnsbl.mf index 0621a98c..53603be5 100644 --- a/mflib/match_dnsbl.mf +++ b/mflib/match_dnsbl.mf @@ -1,5 +1,6 @@ /* DNSBL checker. Copyright (C) 2006, 2007 Jan Rafaj + Copyright (C) 2008 Sergey Poznyakoff 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 @@ -19,27 +20,26 @@ #pragma regex push +extended -func match_dnsbl(string address, string zone, string range) +func match_dnsbl(string address, string zone, string iprange) returns number do - string rbl_ip - if %range = 'ANY' - set rbl_ip '127.0.0.0/8' + if %iprange = 'ANY' + set iprange '127.0.0.0/8' + m4_ifdef(`COMPAT_4_3',` else - set rbl_ip %range - if not %range matches '^([0-9]{1,3}\.){3}[0-9]{1,3}$' + if not %iprange matches `'''`^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$`'''` return 0 fi fi - if not (%address matches '^([0-9]{1,3}\.){3}[0-9]{1,3}$' - and %address != %range) - return 0 + if not (%address matches `'''`^([0-9]{1,3}\.){3}[0-9]{1,3}$`'''` + and %address != %iprange) + return 0') fi if %address matches '^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$' - if match_cidr (resolve ("\4.\3.\2.\1", %zone), %rbl_ip) + if match_cidr (resolve ("\4.\3.\2.\1", %zone), %iprange) return 1 else return 0 diff --git a/mflib/match_rhsbl.mf b/mflib/match_rhsbl.mf index 9b2a492a..d08f103b 100644 --- a/mflib/match_rhsbl.mf +++ b/mflib/match_rhsbl.mf @@ -1,5 +1,6 @@ /* RHSBL checker. Copyright (C) 2006, 2007 Jan Rafaj + Copyright (C) 2008 Sergey Poznyakoff 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 @@ -18,14 +19,17 @@ #require match_cidr #pragma regex push +extended -func match_rhsbl(string email, string zone, string range) +func match_rhsbl(string email, string zone, string iprange) returns number do - if not (%email matches '@.+$' - and %range matches '^([0-9]{1,3}\.){3}[0-9]{1,3}$') + if %iprange = 'ANY' + set iprange '127.0.0.0/8' + fi + if not (%email matches '@.+$'m4_ifdef(`COMPAT_4_3',` + and %iprange matches `'''`^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$'`'')) return 0 fi - return match_cidr (resolve ((domainpart %email), %zone), %range) + return match_cidr (resolve ((domainpart %email), %zone), %iprange) done #pragma regex pop diff --git a/mflib/safedb.mf4 b/mflib/safedb.mf4 index f1d98b8a..822d3c7a 100644 --- a/mflib/safedb.mf4 +++ b/mflib/safedb.mf4 @@ -1,5 +1,5 @@ /* Safe DB I/O - Copyright (C) 2007 Sergey Poznyakoff + Copyright (C) 2007, 2008 Sergey Poznyakoff 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 @@ -19,7 +19,7 @@ func safedbget(string name, string key ; string defval, number null) returns string do - catch dbfailure + catch e_dbfailure do return "" done @@ -34,7 +34,7 @@ done func safedbput(string name, string key, string value ; number null) do - catch dbfailure + catch e_dbfailure do return done diff --git a/src/gram.y b/src/gram.y index 7732007f..bb68ded5 100644 --- a/src/gram.y +++ b/src/gram.y @@ -1,6 +1,6 @@ %{ /* This file is part of mailfromd. - Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff + Copyright (C) 2005, 2006, 2007, 2008 Sergey Poznyakoff 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 @@ -281,7 +281,7 @@ static void register_macro(enum smtp_state tag, const char *macro); %} %error-verbose -%expect 26 +%expect 27 %union { struct literal *literal; @@ -341,12 +341,14 @@ static void register_macro(enum smtp_state tag, const char *macro); %token SWITCH CASE DEFAULT CONST %token FOR LOOP WHILE BREAK NEXT ARGCOUNT %token STRING CODE XCODE -%token SYMBOL VARIABLE IDENTIFIER +%token SYMBOL IDENTIFIER %token ARG NUMBER BACKREF %token BUILTIN BUILTIN_PROC BUILTIN_P %token OR AND EQ NE LT LE GT GE NOT LOGAND LOGOR LOGXOR LOGNOT %token FUNCTION FUNCTION_PROC FUNCTION_P %token TYPE +%token VARIABLE +%token BOGUS %left CONCAT %left OR @@ -567,6 +569,18 @@ vardecl : TYPE IDENTIFIER constdecl : CONST IDENTIFIER expr { struct value value; + struct variable *pvar; + + /* FIXME: This is necessary because constants can be + referred to the same way as variables. */ + if (pvar = variable_lookup($2->text)) { + parse_warning(_("Constant name `%s' clashes with a variable name"), + $2->text); + parse_warning_locus(&pvar->locus, + _("This is the location of the " + "previous definition")); + } + if (optimization_level) optimize($3); @@ -1025,7 +1039,8 @@ value : STRING } | IDENTIFIER { - struct value *value_ptr = constant_lookup($1->text); + const struct value *value_ptr = + constant_lookup_value($1->text); if (value_ptr) $$ = *value_ptr; else { @@ -1655,17 +1670,15 @@ arglist : expr variable : VARIABLE { - $$ = variable_lookup($1->text); - if (!$$) { - parse_error(_("Variable %s is not defined"), - $1->text); - YYERROR; - } - add_xref($$, get_locus()); + add_xref($1, get_locus()); } - ; + | BOGUS + { + YYERROR; + } + ; -catch : CATCH catchlist DO +catch : CATCH catchlist DO { $$ = inner_context; inner_context = context_catch; catch_nesting++; } @@ -3440,6 +3453,7 @@ vardecl(const char *name, data_type_t type, storage_class_t sc, struct locus *loc) { struct variable *var; + const struct constant *cptr; if (type == dtype_unspecified) { parse_error(_("Cannot define variable of unspecified type")); @@ -3516,6 +3530,16 @@ vardecl(const char *name, data_type_t type, storage_class_t sc, } } + /* FIXME: This is necessary because constants can be + referred to the same way as variables. */ + if (cptr = constant_lookup(name)) { + parse_warning(_("Variable name `%s' clashes with a constant name"), + name); + parse_warning_locus(&cptr->locus, + _("This is the location of the " + "previous definition")); + } + var->type = type; var->storage_class = sc; switch (sc) { diff --git a/src/lex.l b/src/lex.l index 7b043bf1..c33f2a62 100644 --- a/src/lex.l +++ b/src/lex.l @@ -1,6 +1,6 @@ %{ /* This file is part of mailfromd. - Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff + Copyright (C) 2005, 2006, 2007, 2008 Sergey Poznyakoff 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 @@ -85,10 +85,26 @@ keyword(int kw) } while (0) static int -get_const(const char *name) +variable_or_const() { - struct value *value_ptr; - if (value_ptr = constant_lookup(name)) { + union { + struct variable *vptr; + struct constant *cptr; + } v; + const struct value *value_ptr; + + switch (variable_or_constant_lookup(yylval.literal->text, &v)) { + case SYM_UNDEF: + parse_error(_("Variable %s is not defined"), + yylval.literal->text); + return BOGUS; + + case SYM_VARIABLE: + yylval.var = v.vptr; + return VARIABLE; + + case SYM_CONSTANT: + value_ptr = &v.cptr->value; switch (value_ptr->type) { case dtype_number: yylval.number = value_ptr->v.number; @@ -102,8 +118,8 @@ get_const(const char *name) abort(); } } - return 0; } + static size_t input_line; @@ -259,19 +275,14 @@ end return keyword(KW_END); /* Variables */ \%({ICONST}) { return builtin_const(yytext+1); } \%{IDENT} { - int rc; string(yytext + 1, yyleng - 1); - if ((rc = get_const(yylval.literal->text)) != 0) - return rc; - else - return VARIABLE; } + return variable_or_const(); +} \%\{{IDENT}\} { - int rc; string(yytext + 2, yyleng - 3); - if ((rc = get_const(yylval.literal->text)) != 0) - return rc; - else - return VARIABLE; } + return variable_or_const(); +} + /* Positional arguments */ \$# { return ARGCOUNT; diff --git a/src/mailfromd.h b/src/mailfromd.h index 20e2d360..54449c43 100644 --- a/src/mailfromd.h +++ b/src/mailfromd.h @@ -1,5 +1,5 @@ /* This file is part of mailfromd. - Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff + Copyright (C) 2005, 2006, 2007, 2008 Sergey Poznyakoff 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 @@ -587,6 +587,9 @@ struct constant { #define SYM_VARIABLE 3 /* The entry holds a variable */ #define SYM_LITERAL 4 /* A literal */ #define SYM_CONSTANT 5 /* A constant */ +#define _SYM_COUNT 6 +#define SYM_MASK(n) (1<<(n)) +#define SYM_BITS SYM_MASK(_SYM_COUNT) typedef int (*symbol_enumerator_t)(void *sym, void *data); int symbol_enumerate(int state, symbol_enumerator_t fun, void *data); @@ -628,6 +631,8 @@ struct variable *builtin_variable_install(const char *name, unsigned flags); void defer_initialize_variable(char *arg, char *val); +int variable_or_constant_lookup(const char *name, void **dptr); + struct function *function_install(const char *name, size_t parmcnt, size_t optcnt, data_type_t *parmtypes, @@ -636,7 +641,8 @@ struct function *function_install(const char *name, struct function *function_lookup(const char *name); struct literal *literal_lookup(const char *text); void define_constant(const char *name, struct value *value, struct locus *loc); -struct value *constant_lookup(const char *name); +const struct constant *constant_lookup(const char *name); +const struct value *constant_lookup_value(const char *name); struct sym_regex { struct literal *lit; /* Corresponding literal */ diff --git a/src/status.mfi b/src/status.mfi index 6218bcd7..40ac06fb 100644 --- a/src/status.mfi +++ b/src/status.mfi @@ -8,4 +8,22 @@ const FAMILY_INET 2 # Exception codes -%{const %NAME %CODE%} +%{const e_%NAME %CODE%} + +# Backward-compatible definitions +const success e_success +const not_found e_not_found +const failure e_failure +const temp_failure e_temp_failure +const ston_conv e_ston_conv +const divzero e_divzero +const regcomp e_regcomp +const invip e_invip +const invcidr e_invcidr +const invtime e_invtime +const dbfailure e_dbfailure +const range e_range +const url e_url +const noresolve e_noresolve +const ioerr e_ioerr +const macroundef e_macroundef diff --git a/src/symtab.c b/src/symtab.c index c9c31194..cab45cc6 100644 --- a/src/symtab.c +++ b/src/symtab.c @@ -1,5 +1,5 @@ /* This file is part of mailfromd. - Copyright (C) 2006, 2007 Sergey Poznyakoff + Copyright (C) 2006, 2007, 2008 Sergey Poznyakoff 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 @@ -172,7 +172,8 @@ static struct symtab * lookup_or_install(int state, const char *name, int install) { unsigned i, pos; - + struct symtab *foundp = NULL; + if (!symtable) { if (install) { if (rehash()) @@ -187,13 +188,21 @@ lookup_or_install(int state, const char *name, int install) if ((state == SYM_UNDEF || symtable[i].state == state) && strcmp(symtable[i].vp->name, name) == 0) return &symtable[i]; + else if ((state & SYM_BITS) + && (SYM_MASK(symtable[i].state) & state) + && strcmp(symtable[i].vp->name, name) == 0) + foundp = &symtable[i]; + if (++i >= hash_size[hash_num]) i = 0; if (i == pos) break; } + + if ((state & SYM_BITS) && foundp) + return foundp; - if (!install || state == SYM_UNDEF) + if (!install || (state == SYM_UNDEF || (state & SYM_BITS))) return NULL; if (symtable[i].state == SYM_UNDEF) { @@ -398,6 +407,18 @@ variable_lookup(const char *name) return sp ? &sp->vp->variable : NULL; } +int +variable_or_constant_lookup(const char *name, void **dptr) +{ + struct symtab *sp = lookup_or_install( + SYM_BITS|SYM_MASK(SYM_VARIABLE)|SYM_MASK(SYM_CONSTANT), + name, 0); + if (!sp) + return SYM_UNDEF; + *dptr = sp->vp; + return sp->state; +} + struct function * function_install(const char *name, size_t parmcnt, size_t optcnt, @@ -467,11 +488,18 @@ define_constant(const char *name, struct value *value, struct locus *locus) sp->vp->constant.value = *value; } -struct value * +const struct constant * constant_lookup(const char *name) { struct symtab *sp = lookup_or_install(SYM_CONSTANT, name, 0); - return sp ? &sp->vp->constant.value : NULL; + return sp ? &sp->vp->constant : NULL; +} + +const struct value * +constant_lookup_value(const char *name) +{ + const struct constant *cptr = constant_lookup(name); + return cptr ? &cptr->value : NULL; } diff --git a/tests/etc/catch.rc b/tests/etc/catch.rc index 70be9596..1b91a3e4 100644 --- a/tests/etc/catch.rc +++ b/tests/etc/catch.rc @@ -1,5 +1,5 @@ /* This file is part of Mailfromd -*- mfl -*- - Copyright (C) 2006, 2007 Sergey Poznyakoff + Copyright (C) 2006, 2007, 2008 Sergey Poznyakoff Mailfromd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ set network "127.0.0.0/8" prog envfrom do - catch invip or invcidr + catch e_invip or e_invcidr do tempfail 450 "Catched condition " $1 done diff --git a/tests/etc/catch01.rc b/tests/etc/catch01.rc index 6820be96..966365b7 100644 --- a/tests/etc/catch01.rc +++ b/tests/etc/catch01.rc @@ -1,5 +1,5 @@ /* This file is part of Mailfromd -*- mfl -*- - Copyright (C) 2006, 2007 Sergey Poznyakoff + Copyright (C) 2006, 2007, 2008 Sergey Poznyakoff Mailfromd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ set network "127.0.0.0/8" func safe_cidr(s,s) returns n do - catch invip + catch e_invip do echo "safe_cidr: invalid IP address" return 0 @@ -31,7 +31,7 @@ done prog envfrom do - catch invip or invcidr + catch e_invip or e_invcidr do tempfail 450 "Catched condition " $1 done -- cgit v1.2.1