aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2021-02-15 13:10:39 +0200
committerSergey Poznyakoff <gray@gnu.org>2021-02-15 13:40:51 +0200
commit5bacabb09f8f4808f8c3029cf31425aea91846a0 (patch)
treec598924201dadd2940b64538c232464515a048d5
parentb58dc6296515d0886bbd4197c74d26994d428d8d (diff)
downloadmailfromd-5bacabb09f8f4808f8c3029cf31425aea91846a0.tar.gz
mailfromd-5bacabb09f8f4808f8c3029cf31425aea91846a0.tar.bz2
Warn about uninitialized variables; meaningful use of string variables in boolean context
* src/mailfromd.h (variable) <initialized>: New member. (variable_check_initialized): New proto. * src/symbols.c (init_variable): Set initialized to 0. * src/gram.y: Convert the use of string variable in boolean context to s != ''. (create_asgn_node): Set var->initialized to 1. (create_node_variable): Check if the variable is initialized. (variable_check_initialized): New function. * src/lex.l (variable_or_const): Check if the variable is initialized. * mflib/dns.mf4 (dns_getname, dns_getaddr) (getns,getmx): Initialize result. * tests/arginit.at: New test. * tests/Makefile.am: Add new test. * tests/testsuite.at: Include new test. * doc/mailfromd.texi: Elaborate on default values of variables. * NEWS: Version 8.9.90 * configure.ac: Likewise.
-rw-r--r--NEWS25
-rw-r--r--configure.ac1
-rw-r--r--doc/mailfromd.texi30
-rw-r--r--mflib/dns.mf48
-rw-r--r--src/gram.y54
-rw-r--r--src/lex.l3
-rw-r--r--src/mailfromd.h5
-rw-r--r--src/symbols.c2
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/arginit.at56
-rw-r--r--tests/testsuite.at1
11 files changed, 165 insertions, 21 deletions
diff --git a/NEWS b/NEWS
index 84d3d8ff..e1d6a555 100644
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,31 @@
-Mailfromd NEWS -- history of user-visible changes. 2020-12-29
+Mailfromd NEWS -- history of user-visible changes. 2021-02-15
See the end of file for copying conditions.
Please send Mailfromd bug reports to <bug-mailfromd@gnu.org.ua>
+Version 8.9.90 (git)
+
+* Use of uninitialized automatic variables
+
+The MFL compiler issues a warning if it encounters the use of a
+previously uninitialized automatic variable. In future versions
+the warning will change to error.
+
+* Use of string variables in boolean context
+
+Strings can meaningfully be used in boolean context. For example
+
+ func f(string s)
+ do
+ if s
+ echo "non-empty
+ fi
+ done
+
+The use of "s" in conditional is equivalent to
+
+ if s != ""
+
Version 8.9, 2020-12-29
* The sed function.
diff --git a/configure.ac b/configure.ac
index 7d75d27f..287f09d0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,6 +17,7 @@
AC_PREREQ(2.63)
m4_define([MF_VERSION_MAJOR], 8)
m4_define([MF_VERSION_MINOR], 9)
+m4_define([MF_VERSION_PATCH], 90)
AC_INIT([mailfromd],
MF_VERSION_MAJOR.MF_VERSION_MINOR[]m4_ifdef([MF_VERSION_PATCH],.MF_VERSION_PATCH),
[bug-mailfromd@gnu.org.ua],
diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi
index b88ca5e3..8bfbda57 100644
--- a/doc/mailfromd.texi
+++ b/doc/mailfromd.texi
@@ -5184,6 +5184,11 @@ variables and @samp{number} for numeric ones.
string var
@end example
+ If a variable declaration occurs within a function
+(@pxref{Functions,User-defined}) or handler (@pxref{Handlers}), it
+declares an automatic variable, local to this function or handler.
+Otherwise, it declares a global variable.
+
@cindex qualifiers, variable declaration
@kwindex public
@kwindex static
@@ -5215,23 +5220,26 @@ or
precious static string rcpt_list
@end example
- The declaration can be followed by any valid @acronym{MFL}
-expression, which supplies the @dfn{initial value} for the
+ Declaration can be followed by any valid @acronym{MFL}
+expression, which supplies the initial value or @dfn{initializer} for the
variable, for example:
@example
string var "test"
@end example
- If a variable declaration occurs within a function
-(@pxref{Functions,User-defined}) or handler (@pxref{Handlers}), it
-declares an automatic variable, local to this function or handler.
-Otherwise, it declares a global variable.
+ A global variable declared without initializer is implicitly
+initialized to a null value: numeric variables assume initial value 0,
+string variable are initialized to empty string.
+
+ The value of an automatic variable declared without initializer is
+unspecified. It is an error to use such variable prior to assigning
+it a value.
@cindex variable, assigning a value
@cindex variable assignment
@kwindex set
- A variable is assigned a value using @code{set} statement:
+ A variable is assigned a value using the @code{set} statement:
@example
set @var{name} @var{expr}
@@ -5256,9 +5264,11 @@ topmost lexical level. This is called @dfn{implicit variable
declaration}.
@cindex variables, referencing
- Variables are referenced using the notation @samp{%@var{name}}. The
-variable being referenced must have been declared earlier (either
-explicitly or implicitly).
+ In the @acronym{MFL} program, variables are referenced by their
+name. When appearing inside a double-quoted string, variables are
+referenced using the notation @samp{%@var{name}}. Any variable being
+referenced must have been declared earlier (either explicitly or
+implicitly).
@menu
* Predefined variables::
diff --git a/mflib/dns.mf4 b/mflib/dns.mf4
index 9c7e7d85..3d52f086 100644
--- a/mflib/dns.mf4
+++ b/mflib/dns.mf4
@@ -85,7 +85,7 @@ done
func dns_getname (string ipstr)
returns string
do
- string result
+ string result ''
set n dns_query(DNS_TYPE_PTR, ipstr, 1)
loop for set i 0,
while i < dns_reply_count(n),
@@ -103,7 +103,7 @@ done
func dns_getaddr (string domain)
returns string
do
- string result
+ string result ''
set n dns_query(DNS_TYPE_A, domain, 1)
loop for set i 0,
while i < dns_reply_count(n),
@@ -121,7 +121,7 @@ done
func getns (string domain; number resolve_names, number sort_names)
returns string
do
- string result
+ string result ''
set n dns_query(DNS_TYPE_NS, domain, sort_names, resolve_names)
loop for set i 0,
while i < dns_reply_count(n),
@@ -139,7 +139,7 @@ done
func getmx (string domain; number resolve_names)
returns string
do
- string result
+ string result ''
set n dns_query(DNS_TYPE_MX, domain, 0, resolve_names)
loop for set i 0,
while i < dns_reply_count(n),
diff --git a/src/gram.y b/src/gram.y
index faa3884f..8384a115 100644
--- a/src/gram.y
+++ b/src/gram.y
@@ -449,7 +449,7 @@ _create_alias(void *item, void *data)
%type <node> decl stmt condition action sendmail_action header_action
if_cond else_cond on_cond atom argref paren_argref
- funcall expr maybe_expr maybe_xcode_expr
+ funcall expr bool_expr maybe_expr maybe_xcode_expr
simp_expr atom_expr
asgn catch simple_catch try_block throw return
case_cond autodcl constdecl
@@ -1392,7 +1392,7 @@ condition : if_cond
| on_cond
;
-if_cond : T_IF expr stmtlist else_cond T_FI
+if_cond : T_IF bool_expr stmtlist else_cond T_FI
{
$$ = alloc_node(node_type_if, &@1);
$$->v.cond.cond = $2;
@@ -1405,7 +1405,7 @@ else_cond : /* empty */
{
$$ = NULL;
}
- | T_ELIF expr stmtlist else_cond
+ | T_ELIF bool_expr stmtlist else_cond
{
$$ = alloc_node(node_type_if, &@1);
$$->v.cond.cond = $2;
@@ -2246,6 +2246,30 @@ return : T_RETURN
}
;
+bool_expr : expr
+ {
+ switch (node_type($1)) {
+ case dtype_string:
+ $$ = alloc_node(node_type_bin, &@1);
+ $$->v.bin.opcode = bin_ne;
+ $$->v.bin.arg[0] = $1;
+ $$->v.bin.arg[1] = alloc_node(node_type_string, &@1);
+ $$->v.bin.arg[1]->v.literal = literal_lookup("");
+ break;
+
+ case dtype_number:
+ case dtype_pointer:
+ $$ = $1;
+ break;
+
+ default:
+ parse_error_locus(&@1,
+ _("unspecified data type in conditional expression: please, report"));
+ YYERROR;
+ }
+ }
+ ;
+
/* *************************** */
/* ON statement */
/* *************************** */
@@ -3674,6 +3698,7 @@ create_asgn_node(struct variable *var, NODE *expr,
node->v.asgn.var = var;
node->v.asgn.nframes = catch_nesting;
node->v.asgn.node = cast_to(var->type, expr);
+ var->initialized = 1;
return node;
}
@@ -4487,7 +4512,10 @@ declare_function(struct function *func, struct mu_locus_range const *loc,
NODE *
create_node_variable(struct variable *var, struct mu_locus_range const *locus)
{
- NODE *node = alloc_node(node_type_variable, locus);
+ NODE *node;
+
+ variable_check_initialized(var, locus);
+ node = alloc_node(node_type_variable, locus);
node->v.var_ref.variable = var;
node->v.var_ref.nframes = catch_nesting;
return node;
@@ -4548,3 +4576,21 @@ create_node_backref(long num, struct mu_locus_range const *locus)
node->v.number = num;
return node;
}
+
+static inline int
+variable_is_initialized(struct variable *var)
+{
+ return var->storage_class != storage_auto || var->initialized;
+}
+
+void
+variable_check_initialized(struct variable *var,
+ struct mu_locus_range const *loc)
+{
+ if (!variable_is_initialized(var)) {
+ parse_warning_locus(loc,
+ _("use of uninitialized variable '%s'"),
+ var->sym.name);
+ var->initialized = 1;
+ }
+}
diff --git a/src/lex.l b/src/lex.l
index 7e24408d..7385d4b7 100644
--- a/src/lex.l
+++ b/src/lex.l
@@ -261,7 +261,7 @@ lex_new_source(const char *name, int flag)
/* Return constant or variable token corresponding to the current
value of yylval.literal->text. */
static int
-variable_or_const()
+variable_or_const(void)
{
struct variable *vptr;
const struct constant *cptr;
@@ -289,6 +289,7 @@ variable_or_const()
yylval.literal->text);
return T_BOGUS;
}
+ variable_check_initialized(vptr, &yylloc);
add_xref(vptr, &yylloc);
yylval.var = vptr;
return T_VARIABLE;
diff --git a/src/mailfromd.h b/src/mailfromd.h
index d6582e05..e0610a2f 100644
--- a/src/mailfromd.h
+++ b/src/mailfromd.h
@@ -502,6 +502,8 @@ struct variable {
size_t *addrptr; /* Address pointer (for built-in vars) */
struct variable *shadowed; /* Points to the variable shadowed by
this one */
+ int initialized; /* Is the variable initialized (for
+ automatic variables) */
mu_list_t xref; /* List of struct mu_locus_range */
struct variable *next; /* Next variable in this class */
};
@@ -765,6 +767,9 @@ void register_macro(enum smtp_state tag, const char *macro);
char *get_stage_macro_string(enum gacopyz_stage i);
struct exmask *exmask_create(void);
+void variable_check_initialized(struct variable *var,
+ struct mu_locus_range const *loc);
+
/* Data types and declarations for handling compiled configuration code */
diff --git a/src/symbols.c b/src/symbols.c
index ad0b6994..bed911b5 100644
--- a/src/symbols.c
+++ b/src/symbols.c
@@ -736,6 +736,7 @@ init_variable(struct variable *var)
var->off = 0;
var->addrptr = NULL;
var->shadowed = NULL;
+ var->initialized = 0;
var->xref = NULL;
var->next = NULL;
}
@@ -901,7 +902,6 @@ literal_lookup(const char *text)
}
return lit;
}
-
struct constant *
define_constant(const char *name, struct value *value, unsigned flags,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index dcea96dc..e6655304 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -44,6 +44,7 @@ TESTSUITE_AT = \
ack.at\
alias.at\
arg.at\
+ arginit.at\
ashadow.at\
bctx00.at\
bctx01.at\
diff --git a/tests/arginit.at b/tests/arginit.at
new file mode 100644
index 00000000..212ce62c
--- /dev/null
+++ b/tests/arginit.at
@@ -0,0 +1,56 @@
+# This file is part of Mailfromd testsuite. -*- Autotest -*-
+# Copyright (C) 2021 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
+# the Free Software Foundation; either version 3, 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, see <http://www.gnu.org/licenses/>.
+AT_SETUP([Use of uninitialized variables])
+AT_KEYWORDS([arginit variable variables])
+MF_RUN_TEXT([
+func x()
+do
+ string result
+ set y result
+done
+
+func main(...) returns number
+do
+ x()
+ x()
+done
+],
+[0],
+[],
+[],
+[mailfromd: prog:5.9-14: warning: use of uninitialized variable 'result'
+])
+
+MF_RUN_TEXT([
+func x()
+do
+ string result
+ set y "result is %result"
+done
+
+func main(...) returns number
+do
+ x()
+ x()
+done
+],
+[0],
+[],
+[],
+[mailfromd: prog:5.20-26: warning: use of uninitialized variable 'result'
+])
+
+AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 19532d08..3400738a 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -189,6 +189,7 @@ m4_include([ml.at])
m4_include([ml01.at])
m4_include([declvar.at])
+m4_include([arginit.at])
AT_BANNER([Macros])
m4_include([macros.at])

Return to:

Send suggestions and report system problems to the System administrator.