Fix several issues with command-line option redefs

* Variables of `string` type can now be set to an empty string

* Trying to set a variable with non-`string` type to an empty value
  now emits an error instead of silently doing nothing

* Providing an invalid identifier now emits an "unknown identifier"
  error instead of silently doing nothing
This commit is contained in:
Jon Siwek 2020-06-18 20:07:47 -07:00
parent 7ae5589469
commit 8c90ef4459
6 changed files with 78 additions and 20 deletions

View file

@ -984,34 +984,54 @@ int yywrap()
for ( unsigned int i = 0; i < params.size(); ++i ) for ( unsigned int i = 0; i < params.size(); ++i )
{ {
char* param = copy_string(params[i].c_str()); std::string pi = params[i];
char* eq = strchr(param, '='); auto first_non_id_char = 0;
char* val = eq + 1;
*eq = '\0'; for ( size_t j = 0; j < pi.size(); ++j )
if ( strlen(val) == 0 )
{ {
delete [] param; if ( ! isalnum(pi[j]) && pi[j] != '_' && pi[j] != ':' )
break;
++first_non_id_char;
}
auto eq_idx = pi.find('=', first_non_id_char);
// Omit the '=' from op just to make fmt string below clearer.
auto op = pi.substr(first_non_id_char, eq_idx - first_non_id_char);
auto id_str = pi.substr(0, first_non_id_char);
auto val_str = pi.substr(eq_idx + 1);
const auto& id = zeek::id::find(id_str);
if ( ! id )
{
reporter->Error("unknown identifier '%s' in command-line options",
id_str.data());
continue; continue;
} }
// Try to find the type of the param, and interpret // Interpret the value based on the identifier's type.
// the value intelligently for that type. (So far, // So far, that just means quoting the value for strings types.
// that just means quoting the value if it's a const auto& type = id->GetType();
// string type.) If no type is found, the value
// is left unchanged.
std::string opt_quote; // no optional quote by default
const auto& param_id = lookup_ID(param, GLOBAL_MODULE_NAME);
Val* v = param_id ? param_id->GetVal().get() : nullptr;
if ( v && v->GetType() && v->GetType()->Tag() == zeek::TYPE_STRING ) if ( ! type )
opt_quote = "\""; // use quotes {
reporter->Error("can't set value of '%s' in command-line "
"options: unknown type", id_str.data());
continue;
}
policy += std::string("redef ") + param + "=" if ( val_str.empty() && ! zeek::IsString(type->Tag()) )
+ opt_quote + val + opt_quote + ";"; {
reporter->Error("must assign non-empty value to '%s' in "
"command-line options", id_str.data());
continue;
}
delete [] param; auto use_quotes = zeek::IsString(type->Tag());
auto fmt_str = use_quotes ? "redef %s %s= \"%s\";"
: "redef %s %s= %s;";
policy += fmt(fmt_str, id_str.data(), op.data(), val_str.data());
} }
params.clear(); params.clear();

View file

@ -0,0 +1,4 @@
mystr,
mynum, 0
mytable, {"one":"1"}
MyMod::str, Good

View file

@ -0,0 +1,4 @@
mystr, default
mynum, 0
mytable, {"zero":"0","one":"1"}
MyMod::str, def

View file

@ -0,0 +1 @@
error: unknown identifier 'no_such_var' in command-line options

View file

@ -0,0 +1,2 @@
error: must assign non-empty value to 'mynum' in command-line options
error: must assign non-empty value to 'mytable' in command-line options

View file

@ -0,0 +1,27 @@
# @TEST-EXEC: zeek -b %INPUT mynum=0 mytable='{["one"] = "1"}' mystr="" MyMod::str="Good" >1.out
# @TEST-EXEC: zeek -b %INPUT mynum=0 mytable+='{["one"] = "1"}' >2.out
# @TEST-EXEC-FAIL: zeek -b %INPUT no_such_var=13 >3.out 2>&1
# @TEST-EXEC-FAIL: zeek -b %INPUT mynum="" mytable="" >4.out 2>&1
# @TEST-EXEC: btest-diff 1.out
# @TEST-EXEC: btest-diff 2.out
# @TEST-EXEC: btest-diff 3.out
# @TEST-EXEC: btest-diff 4.out
const mynum: count &redef;
const mytable: table[string] of string = {["zero"] = "0"} &redef;
option mystr="default";
module MyMod;
export { option str="def"; }
module GLOBAL;
event zeek_init()
{
print "mystr", mystr;
print "mynum", mynum;
print "mytable", to_json(mytable);
print "MyMod::str", MyMod::str;
}