dfilter: Fix invalid character constant error message

This reverts commit d635ff4933.

A charconst cannot be a value string, for that reason it is not
redundant with unparsed.

Maybe character constants should be parsed in the lexical scanner
instead.

Before:
  Filter: ip.proto == '\g'
  dftest: "'\g'" cannot be found among the possible values for ip.proto.

After:
  Filter: ip.proto == '\g'
  dftest: "'\g'" isn't a valid character constant.
This commit is contained in:
João Valverde 2021-11-23 16:02:35 +00:00 committed by Wireshark GitLab Utility
parent b657396d44
commit 7028646f9e
9 changed files with 76 additions and 24 deletions

View File

@ -148,8 +148,7 @@ entity(E) ::= STRING(S).
}
entity(E) ::= CHARCONST(C).
{
/* A charconst uses "unparsed" semantic rules. */
E = stnode_new_unparsed(df_lval_value(C));
E = stnode_new_charconst(df_lval_value(C));
df_lval_free(C);
}
entity(E) ::= UNPARSED(U).

View File

@ -433,6 +433,7 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
/* This is OK */
break;
case STTYPE_STRING:
case STTYPE_CHARCONST:
case STTYPE_UNPARSED:
FAIL(dfw, "\"%s\" is neither a field nor a protocol name.",
stnode_todisplay(st_arg1));
@ -539,6 +540,31 @@ check_function(dfwork_t *dfw, stnode_t *st_node)
}
}
/* Convert a character constant to a 1-byte BYTE_STRING containing the
* character. */
WS_RETNONNULL
static fvalue_t *
dfilter_fvalue_from_charconst_string(dfwork_t *dfw, ftenum_t ftype, stnode_t *st, gboolean allow_partial_value)
{
fvalue_t *fvalue;
const char *s = stnode_data(st);
fvalue = fvalue_from_unparsed(FT_CHAR, s, allow_partial_value,
dfw->error_message == NULL ? &dfw->error_message : NULL);
if (fvalue == NULL)
THROW(TypeError);
char *temp_string;
/* It's valid. Create a 1-byte BYTE_STRING from its value. */
temp_string = g_strdup_printf("%02x", fvalue->value.uinteger);
fvalue_free(fvalue);
fvalue = fvalue_from_unparsed(ftype, temp_string, allow_partial_value, NULL);
ws_assert(fvalue);
g_free(temp_string);
return fvalue;
}
/* If the LHS of a relation test is a FIELD, run some checks
* and possibly some modifications of syntax tree nodes. */
static void
@ -578,7 +604,8 @@ check_relation_LHS_FIELD(dfwork_t *dfw, test_op_t st_op,
hfinfo2->abbrev, ftype_pretty_name(ftype2));
}
}
else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED) {
else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED ||
type2 == STTYPE_CHARCONST) {
/* Skip incompatible fields */
while (hfinfo1->same_name_prev_id != -1 &&
((type2 == STTYPE_STRING && ftype1 != FT_STRING && ftype1!= FT_STRINGZ) ||
@ -590,6 +617,17 @@ check_relation_LHS_FIELD(dfwork_t *dfw, test_op_t st_op,
if (type2 == STTYPE_STRING) {
fvalue = dfilter_fvalue_from_string(dfw, ftype1, st_arg2, hfinfo1);
}
else if (type2 == STTYPE_CHARCONST && st_op == TEST_OP_CONTAINS) {
/* The RHS should be the same type as the LHS,
* but a character is just a one-byte byte
* string. */
fvalue = dfilter_fvalue_from_charconst_string(dfw, ftype1, st_arg2, allow_partial_value);
}
else if (type2 == STTYPE_CHARCONST) {
/* If this is a character constant don't try to treat it as a string from
* a value_string table. */
fvalue = dfilter_fvalue_from_unparsed(dfw, ftype1, st_arg2, allow_partial_value, NULL);
}
else {
fvalue = dfilter_fvalue_from_unparsed(dfw, ftype1, st_arg2, allow_partial_value, hfinfo1);
}
@ -660,7 +698,8 @@ check_relation_LHS_STRING(dfwork_t *dfw, test_op_t st_op,
fvalue = dfilter_fvalue_from_string(dfw, ftype2, st_arg1, hfinfo2);
stnode_replace(st_arg1, STTYPE_FVALUE, fvalue);
}
else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED) {
else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED ||
type2 == STTYPE_CHARCONST) {
/* Well now that's silly... */
FAIL(dfw, "Neither \"%s\" nor \"%s\" are field or protocol names.",
stnode_todisplay(st_arg1),
@ -718,7 +757,8 @@ check_relation_LHS_UNPARSED(dfwork_t *dfw, test_op_t st_op,
fvalue = dfilter_fvalue_from_unparsed(dfw, ftype2, st_arg1, allow_partial_value, hfinfo2);
stnode_replace(st_arg1, STTYPE_FVALUE, fvalue);
}
else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED) {
else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED ||
type2 == STTYPE_CHARCONST) {
/* Well now that's silly... */
FAIL(dfw, "Neither \"%s\" nor \"%s\" are field or protocol names.",
stnode_todisplay(st_arg1),
@ -787,6 +827,12 @@ check_relation_LHS_RANGE(dfwork_t *dfw, test_op_t st_op,
fvalue = dfilter_fvalue_from_unparsed(dfw, FT_BYTES, st_arg2, allow_partial_value, NULL);
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
}
else if (type2 == STTYPE_CHARCONST) {
/* The RHS should be FT_BYTES, but a character is just a
* one-byte byte string. */
fvalue = dfilter_fvalue_from_charconst_string(dfw, FT_BYTES, st_arg2, allow_partial_value);
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
}
else if (type2 == STTYPE_RANGE) {
check_drange_sanity(dfw, st_arg2);
}
@ -862,7 +908,7 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, test_op_t st_op,
fvalue = dfilter_fvalue_from_string(dfw, ftype1, st_arg2, NULL);
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
}
else if (type2 == STTYPE_UNPARSED) {
else if (type2 == STTYPE_UNPARSED || type2 == STTYPE_CHARCONST) {
fvalue = dfilter_fvalue_from_unparsed(dfw, ftype1, st_arg2, allow_partial_value, NULL);
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
}

View File

@ -40,6 +40,15 @@ sttype_register_string(void)
string_tostr
};
static sttype_t charconst_type = {
STTYPE_CHARCONST,
"CHARCONST",
NULL,
string_free,
string_dup,
string_tostr
};
static sttype_t unparsed_type = {
STTYPE_UNPARSED,
"UNPARSED",
@ -50,6 +59,7 @@ sttype_register_string(void)
};
sttype_register(&string_type);
sttype_register(&charconst_type);
sttype_register(&unparsed_type);
}

View File

@ -184,6 +184,12 @@ stnode_new_unparsed(const char *str)
return stnode_new(STTYPE_UNPARSED, g_strdup(str));
}
stnode_t *
stnode_new_charconst(const char *str)
{
return stnode_new(STTYPE_CHARCONST, g_strdup(str));
}
stnode_t*
stnode_dup(const stnode_t *node)
{

View File

@ -24,6 +24,7 @@ typedef enum {
STTYPE_TEST,
STTYPE_UNPARSED,
STTYPE_STRING,
STTYPE_CHARCONST,
STTYPE_FIELD,
STTYPE_FVALUE,
STTYPE_RANGE,
@ -110,6 +111,9 @@ stnode_new_string(const char *str);
stnode_t *
stnode_new_unparsed(const char *str);
stnode_t *
stnode_new_charconst(const char *str);
stnode_t*
stnode_dup(const stnode_t *org);

View File

@ -174,20 +174,6 @@ byte_array_from_unparsed(const char *s, gchar **err_msg)
GByteArray *bytes;
gboolean res;
if (s[0] == '\'') {
/*
* byte array with length 1 represented as a C-style character constant.
*/
unsigned long value;
if (!parse_charconst(s, &value, err_msg))
return NULL;
ws_assert(value <= UINT8_MAX);
uint8_t one_byte = (uint8_t)value;
bytes = g_byte_array_new();
g_byte_array_append(bytes, &one_byte, 1);
return bytes;
}
/*
* Special case where the byte string is specified using a one byte
* hex literal. We can't allow this for byte strings that are longer

View File

@ -48,7 +48,7 @@ get_sinteger(fvalue_t *fv)
return fv->value.sinteger;
}
gboolean
static gboolean
parse_charconst(const char *s, unsigned long *valuep, gchar **err_msg)
{
const char *cp;

View File

@ -106,9 +106,6 @@ void ftype_register_tvbuff(void);
GByteArray *
byte_array_from_unparsed(const char *s, gchar **err_msg);
gboolean
parse_charconst(const char *s, unsigned long *valuep, gchar **err_msg);
#endif /* FTYPES_INT_H */
/*

View File

@ -99,3 +99,7 @@ class case_syntax(unittest.TestCase):
def test_charconst_bytes_2(self, checkDFilterCount):
dfilter = "frame[54] == 'H'"
checkDFilterCount(dfilter, 1)
def test_charconst_invalid(self, checkDFilterFail):
dfilter = r"ip.proto == '\Z'"
checkDFilterFail(dfilter, "isn't a valid character constant")