aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoão Valverde <j@v6e.pt>2023-10-17 20:10:29 +0100
committerJoão Valverde <j@v6e.pt>2023-10-18 09:32:48 +0000
commit4c3b5db000ead0873b5a4aafba05feac7b3db115 (patch)
tree265bf217e3cab2aa0183955b479f18e925d484da
parent311dacfe8eb516ae44fd8bd981bf8139a0f3f3b4 (diff)
dfilter: Improve type inferrence for constant values
The display filter language is statically typed, but the syntax is not declarative. This means every literal type must be inferred at compile time. This is not trivial if we have a constant expression on the left-hand side. To improve the flexibility and generality of the compiler we add a look-ahead type resolution step when the type of a value cannot be immediately inferred. This simplifies the code, improves some error messages and enables the correct handling of some expressions that were not supported before, such as "1 == frame.number".
-rw-r--r--epan/dfilter/dfunctions.c131
-rw-r--r--epan/dfilter/dfunctions.h4
-rw-r--r--epan/dfilter/semcheck.c184
-rw-r--r--epan/dfilter/semcheck.h9
-rw-r--r--test/suite_dfilter/group_function.py5
-rw-r--r--test/suite_dfilter/group_syntax.py14
6 files changed, 197 insertions, 150 deletions
diff --git a/epan/dfilter/dfunctions.c b/epan/dfilter/dfunctions.c
index 1bd8bdcd2c..3939d59a56 100644
--- a/epan/dfilter/dfunctions.c
+++ b/epan/dfilter/dfunctions.c
@@ -241,7 +241,7 @@ df_func_abs(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
/* For upper() and lower() checks that the parameter passed to
* it is an FT_STRING */
static ftenum_t
-ul_semcheck_is_field_string(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype _U_,
+ul_semcheck_is_field_string(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype _U_,
GSList *param_list, df_loc_t func_loc _U_)
{
header_field_info *hfinfo;
@@ -260,7 +260,7 @@ ul_semcheck_is_field_string(dfwork_t *dfw, const char *func_name, ftenum_t lhs_f
}
static ftenum_t
-ul_semcheck_is_field(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype _U_,
+ul_semcheck_is_field(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype _U_,
GSList *param_list, df_loc_t func_loc _U_)
{
ws_assert(g_slist_length(param_list) == 1);
@@ -275,13 +275,13 @@ ul_semcheck_is_field(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype _U
}
static ftenum_t
-ul_semcheck_can_length(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
+ul_semcheck_can_length(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype,
GSList *param_list, df_loc_t func_loc)
{
ws_assert(g_slist_length(param_list) == 1);
stnode_t *st_node = param_list->data;
- ul_semcheck_is_field(dfw, func_name, lhs_ftype, param_list, func_loc);
+ ul_semcheck_is_field(dfw, func_name, logical_ftype, param_list, func_loc);
if (!ftype_can_length(sttype_field_ftenum(st_node))) {
FAIL(dfw, st_node, "Field %s does not support the %s() function", stnode_todisplay(st_node), func_name);
}
@@ -289,7 +289,7 @@ ul_semcheck_can_length(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
}
static ftenum_t
-ul_semcheck_string_param(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype _U_,
+ul_semcheck_string_param(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype _U_,
GSList *param_list, df_loc_t func_loc _U_)
{
header_field_info *hfinfo;
@@ -343,48 +343,28 @@ ul_semcheck_string_param(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftyp
}
/* Check arguments are all the same type and they can be compared. */
-/*
- Every STTYPE_LITERAL needs to be resolved to a STTYPE_FVALUE. If we don't
- have type information (lhs_ftype is FT_NONE) and we have not seen an argument
- with a definite type we defer resolving literals to values until we have examined
- the entire list of function arguments. If we still cannot resolve to a definite
- type after that (all arguments must have the same type) then we give up and
- return FT_NONE.
-*/
static ftenum_t
-ul_semcheck_compare(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
+ul_semcheck_compare(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype,
GSList *param_list, df_loc_t func_loc _U_)
{
stnode_t *arg;
sttype_id_t type;
- ftenum_t ftype, ft_arg;
+ ftenum_t ft_arg;
GSList *l;
- wmem_list_t *literals = NULL;
-
- ftype = lhs_ftype;
for (l = param_list; l != NULL; l = l->next) {
arg = l->data;
type = stnode_type_id(arg);
if (type == STTYPE_ARITHMETIC) {
- ft_arg = check_arithmetic(dfw, arg, ftype);
+ ft_arg = check_arithmetic(dfw, arg, logical_ftype);
}
else if (type == STTYPE_LITERAL) {
- if (ftype != FT_NONE) {
- dfilter_fvalue_from_literal(dfw, ftype, arg, false, NULL);
- ft_arg = sttype_pointer_ftenum(arg);
- }
- else {
- if (literals == NULL) {
- literals = wmem_list_new(dfw->dfw_scope);
- }
- wmem_list_append(literals, arg);
- ft_arg = FT_NONE;
- }
+ dfilter_fvalue_from_literal(dfw, logical_ftype, arg, false, NULL);
+ ft_arg = sttype_pointer_ftenum(arg);
}
else if (type == STTYPE_FUNCTION) {
- ft_arg = check_function(dfw, arg, ftype);
+ ft_arg = check_function(dfw, arg, logical_ftype);
}
else if (type == STTYPE_FIELD) {
dfw->field_count++;
@@ -398,36 +378,21 @@ ul_semcheck_compare(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
stnode_todisplay(arg), func_name);
}
- if (ftype == FT_NONE) {
- ftype = ft_arg;
- }
- if (ft_arg != FT_NONE && ftype != FT_NONE && !compatible_ftypes(ft_arg, ftype)) {
- FAIL(dfw, arg, "Arguments to '%s' must be type compatible (expected %s, got %s)",
- func_name, ftype_name(ftype), ftype_name(ft_arg));
+ if (!compatible_ftypes(ft_arg, logical_ftype)) {
+ FAIL(dfw, arg, "Arguments to '%s' must be of compatible type (expected %s, got %s)",
+ func_name, ftype_name(logical_ftype), ftype_name(ft_arg));
}
- if (ft_arg != FT_NONE && !ftype_can_cmp(ft_arg)) {
+ if (!ftype_can_cmp(ft_arg)) {
FAIL(dfw, arg, "Argument '%s' to '%s' cannot be ordered",
stnode_todisplay(arg), func_name);
}
}
- if (literals != NULL) {
- if (ftype != FT_NONE) {
- wmem_list_frame_t *fp;
- stnode_t *st;
- for (fp = wmem_list_head(literals); fp != NULL; fp = wmem_list_frame_next(fp)) {
- st = wmem_list_frame_data(fp);
- dfilter_fvalue_from_literal(dfw, ftype, st, false, NULL);
- }
- }
- wmem_destroy_list(literals);
- }
-
- return ftype;
+ return logical_ftype;
}
static ftenum_t
-ul_semcheck_absolute_value(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
+ul_semcheck_absolute_value(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype,
GSList *param_list, df_loc_t func_loc _U_)
{
ws_assert(g_slist_length(param_list) == 1);
@@ -437,30 +402,20 @@ ul_semcheck_absolute_value(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ft
st_node = param_list->data;
if (stnode_type_id(st_node) == STTYPE_ARITHMETIC) {
- ftype = check_arithmetic(dfw, st_node, lhs_ftype);
+ ftype = check_arithmetic(dfw, st_node, logical_ftype);
}
else if (stnode_type_id(st_node) == STTYPE_LITERAL) {
- if (lhs_ftype != FT_NONE) {
- /* Convert RHS literal to the same ftype as LHS. */
- dfilter_fvalue_from_literal(dfw, lhs_ftype, st_node, false, NULL);
- ftype = sttype_pointer_ftenum(st_node);
- }
- else {
- FAIL(dfw, st_node, "Need a field or field-like value on the LHS.");
- }
+ dfilter_fvalue_from_literal(dfw, logical_ftype, st_node, false, NULL);
+ ftype = sttype_pointer_ftenum(st_node);
}
else if (stnode_type_id(st_node) == STTYPE_FUNCTION) {
- ftype = check_function(dfw, st_node, lhs_ftype);
+ ftype = check_function(dfw, st_node, logical_ftype);
}
else if (stnode_type_id(st_node) == STTYPE_FIELD) {
dfw->field_count++;
ftype = sttype_field_ftenum(st_node);
}
else {
- ftype = FT_NONE;
- }
-
- if (ftype == FT_NONE) {
FAIL(dfw, st_node, "Type %s is not valid for %s",
stnode_type_name(st_node), func_name);
}
@@ -471,19 +426,45 @@ ul_semcheck_absolute_value(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ft
return ftype;
}
+static ftenum_t
+return_string(GSList *param_list _U_)
+{
+ return FT_STRING;
+}
+
+static ftenum_t
+return_unsigned(GSList *param_list _U_)
+{
+ return FT_UINT32;
+}
+
+static ftenum_t
+return_compare(GSList *param_list)
+{
+ GSList *l;
+ ftenum_t ftype;
+
+ for (l = param_list; l != NULL; l = l->next) {
+ ftype = get_logical_ftype(l->data);
+ if (ftype != FT_NONE)
+ return ftype;
+ }
+ return FT_NONE;
+}
+
/* The table of all display-filter functions */
static df_func_def_t
df_functions[] = {
- { "lower", df_func_lower, 1, 1, ul_semcheck_is_field_string },
- { "upper", df_func_upper, 1, 1, ul_semcheck_is_field_string },
+ { "lower", df_func_lower, 1, 1, return_string, ul_semcheck_is_field_string },
+ { "upper", df_func_upper, 1, 1, return_string, ul_semcheck_is_field_string },
/* Length function is implemented as a DFVM instruction. */
- { "len", NULL, 1, 1, ul_semcheck_can_length },
- { "count", df_func_count, 1, 1, ul_semcheck_is_field },
- { "string", df_func_string, 1, 1, ul_semcheck_string_param },
- { "max", df_func_max, 1, 0, ul_semcheck_compare },
- { "min", df_func_min, 1, 0, ul_semcheck_compare },
- { "abs", df_func_abs, 1, 1, ul_semcheck_absolute_value },
- { NULL, NULL, 0, 0, NULL }
+ { "len", NULL, 1, 1, return_unsigned, ul_semcheck_can_length },
+ { "count", df_func_count, 1, 1, return_unsigned, ul_semcheck_is_field },
+ { "string", df_func_string, 1, 1, return_string, ul_semcheck_string_param },
+ { "max", df_func_max, 1, 0, return_compare, ul_semcheck_compare },
+ { "min", df_func_min, 1, 0, return_compare, ul_semcheck_compare },
+ { "abs", df_func_abs, 1, 1, return_compare, ul_semcheck_absolute_value },
+ { NULL, NULL, 0, 0, NULL, NULL }
};
/* Lookup a display filter function record by name */
diff --git a/epan/dfilter/dfunctions.h b/epan/dfilter/dfunctions.h
index 25485e77cd..dde87d091a 100644
--- a/epan/dfilter/dfunctions.h
+++ b/epan/dfilter/dfunctions.h
@@ -20,6 +20,9 @@
/* The run-time logic of the dfilter function */
typedef bool (*DFFuncType)(GSList *stack, uint32_t arg_count, df_cell_t *retval);
+/* The return type for the dfilter function */
+typedef ftenum_t (*DFReturnType)(GSList *param_list);
+
/* The semantic check for the dfilter function */
typedef ftenum_t (*DFSemCheckType)(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
GSList *param_list, df_loc_t func_loc);
@@ -31,6 +34,7 @@ typedef struct {
DFFuncType function;
unsigned min_nargs;
unsigned max_nargs; /* 0 for no limit */
+ DFReturnType return_type;
DFSemCheckType semcheck_param_function;
} df_func_def_t;
diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c
index c94f968a7b..b5f6c339d4 100644
--- a/epan/dfilter/semcheck.c
+++ b/epan/dfilter/semcheck.c
@@ -43,12 +43,19 @@
THROW(TypeError); \
} while (0)
+#define IS_FIELD_ENTITY(ft) \
+ ((ft) == STTYPE_FIELD || \
+ (ft) == STTYPE_REFERENCE)
+
typedef bool (*FtypeCanFunc)(enum ftenum);
static ftenum_t
+find_logical_ftype(dfwork_t *dfw, stnode_t *st_node);
+
+static ftenum_t
check_arithmetic_LHS(dfwork_t *dfw, stnode_op_t st_op,
stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2,
- ftenum_t lhs_ftype);
+ ftenum_t logical_ftype);
static void
check_relation(dfwork_t *dfw, stnode_op_t st_op,
@@ -580,6 +587,83 @@ is_bytes_type(enum ftenum type)
return false;
}
+static ftenum_t
+get_slice_ftype(stnode_t *st_node)
+{
+ stnode_t *entity1 = sttype_slice_entity(st_node);
+ ws_assert(entity1);
+ ftenum_t ftype = get_logical_ftype(entity1);
+ return FT_IS_STRING(ftype) ? FT_STRING : FT_BYTES;
+}
+
+static ftenum_t
+get_function_ftype(stnode_t *st_node)
+{
+ df_func_def_t *funcdef;
+ GSList *params;
+ unsigned nparams;
+
+ funcdef = sttype_function_funcdef(st_node);
+ params = sttype_function_params(st_node);
+ nparams = g_slist_length(params);
+
+ if (nparams < 1)
+ return FT_NONE;
+ return funcdef->return_type(params);
+}
+
+ftenum_t
+get_logical_ftype(stnode_t *st_node)
+{
+ stnode_t *st_arg1, *st_arg2;
+ ftenum_t ft;
+
+ switch(stnode_type_id(st_node)) {
+ case STTYPE_FIELD:
+ case STTYPE_REFERENCE:
+ return sttype_field_ftenum(st_node);
+
+ case STTYPE_STRING:
+ case STTYPE_LITERAL:
+ case STTYPE_CHARCONST:
+ return FT_NONE;
+
+ case STTYPE_FUNCTION:
+ return get_function_ftype(st_node);
+
+ case STTYPE_ARITHMETIC:
+ case STTYPE_TEST:
+ sttype_oper_get(st_node, NULL, &st_arg1, &st_arg2);
+ if (st_arg1 && (ft = get_logical_ftype(st_arg1)) != FT_NONE)
+ return ft;
+ if (st_arg2 && (ft = get_logical_ftype(st_arg2)) != FT_NONE)
+ return ft;
+ return FT_NONE;
+
+ case STTYPE_SLICE:
+ return get_slice_ftype(st_node);
+
+ case STTYPE_SET:
+ case STTYPE_UNINITIALIZED:
+ case STTYPE_NUM_TYPES:
+ case STTYPE_FVALUE:
+ case STTYPE_PCRE:
+ ws_error("invalid syntax type %s", stnode_type_name(st_node));
+ }
+
+ ws_assert_not_reached();
+}
+
+static ftenum_t
+find_logical_ftype(dfwork_t *dfw, stnode_t *st_node)
+{
+ ftenum_t ftype = get_logical_ftype(st_node);
+ if (ftype == FT_NONE) {
+ FAIL(dfw, st_node, "Constant expression is invalid");
+ }
+ return ftype;
+}
+
/* Check the semantics of an existence test. */
static void
check_exists(dfwork_t *dfw, stnode_t *st_arg1)
@@ -618,7 +702,7 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
}
ftenum_t
-check_slice(dfwork_t *dfw, stnode_t *st, ftenum_t lhs_ftype)
+check_slice(dfwork_t *dfw, stnode_t *st, ftenum_t logical_ftype)
{
stnode_t *entity1;
header_field_info *hfinfo1;
@@ -639,14 +723,14 @@ check_slice(dfwork_t *dfw, stnode_t *st, ftenum_t lhs_ftype)
hfinfo1->abbrev, ftype_pretty_name(ftype1));
}
} else if (stnode_type_id(entity1) == STTYPE_FUNCTION) {
- ftype1 = check_function(dfw, entity1, lhs_ftype);
+ ftype1 = check_function(dfw, entity1, logical_ftype);
if (!ftype_can_slice(ftype1)) {
FAIL(dfw, entity1, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
sttype_function_name(entity1), ftype_pretty_name(ftype1));
}
} else if (stnode_type_id(entity1) == STTYPE_SLICE) {
- ftype1 = check_slice(dfw, entity1, lhs_ftype);
+ ftype1 = check_slice(dfw, entity1, logical_ftype);
} else {
FAIL(dfw, entity1, "Range is not supported for entity %s",
stnode_todisplay(entity1));
@@ -655,10 +739,6 @@ check_slice(dfwork_t *dfw, stnode_t *st, ftenum_t lhs_ftype)
return FT_IS_STRING(ftype1) ? FT_STRING : FT_BYTES;
}
-#define IS_FIELD_ENTITY(ft) \
- ((ft) == STTYPE_FIELD || \
- (ft) == STTYPE_REFERENCE)
-
static void
convert_to_bytes(stnode_t *arg)
{
@@ -675,7 +755,7 @@ convert_to_bytes(stnode_t *arg)
}
ftenum_t
-check_function(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype)
+check_function(dfwork_t *dfw, stnode_t *st_node, ftenum_t logical_ftype)
{
df_func_def_t *funcdef;
GSList *params;
@@ -695,7 +775,7 @@ check_function(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype)
funcdef->name, funcdef->max_nargs);
}
- return funcdef->semcheck_param_function(dfw, funcdef->name, lhs_ftype, params,
+ return funcdef->semcheck_param_function(dfw, funcdef->name, logical_ftype, params,
stnode_location(st_node));
}
@@ -842,7 +922,8 @@ static void
check_relation_LHS_FVALUE(dfwork_t *dfw, stnode_op_t st_op,
FtypeCanFunc can_func, bool allow_partial_value,
stnode_t *st_node,
- stnode_t *st_arg1, stnode_t *st_arg2)
+ stnode_t *st_arg1, stnode_t *st_arg2,
+ ftenum_t logical_ftype)
{
sttype_id_t type1, type2;
header_field_info *hfinfo2 = NULL;
@@ -872,7 +953,7 @@ check_relation_LHS_FVALUE(dfwork_t *dfw, stnode_op_t st_op,
FAIL(dfw, st_node, "Constant expression is invalid.");
}
else if (type2 == STTYPE_SLICE) {
- ftype2 = check_slice(dfw, st_arg2, FT_NONE);
+ ftype2 = check_slice(dfw, st_arg2, logical_ftype);
if (!can_func(ftype2)) {
FAIL(dfw, st_arg2, "%s (type=%s) cannot participate in specified comparison.",
@@ -880,7 +961,7 @@ check_relation_LHS_FVALUE(dfwork_t *dfw, stnode_op_t st_op,
}
}
else if (type2 == STTYPE_FUNCTION) {
- ftype2 = check_function(dfw, st_arg2, FT_NONE);
+ ftype2 = check_function(dfw, st_arg2, logical_ftype);
if (!can_func(ftype2)) {
FAIL(dfw, st_arg2, "return value of %s() (type=%s) cannot participate in specified comparison.",
@@ -888,7 +969,7 @@ check_relation_LHS_FVALUE(dfwork_t *dfw, stnode_op_t st_op,
}
}
else if (type2 == STTYPE_ARITHMETIC) {
- ftype2 = check_arithmetic(dfw, st_arg2, FT_NONE);
+ ftype2 = check_arithmetic(dfw, st_arg2, logical_ftype);
if (!can_func(ftype2)) {
FAIL(dfw, st_arg2, "%s (type=%s) cannot participate in specified comparison.",
@@ -930,14 +1011,15 @@ check_relation_LHS_SLICE(dfwork_t *dfw, stnode_op_t st_op _U_,
FtypeCanFunc can_func _U_,
bool allow_partial_value,
stnode_t *st_node _U_,
- stnode_t *st_arg1, stnode_t *st_arg2)
+ stnode_t *st_arg1, stnode_t *st_arg2,
+ ftenum_t logical_ftype)
{
sttype_id_t type2;
ftenum_t ftype1, ftype2;
LOG_NODE(st_node);
- ftype1 = check_slice(dfw, st_arg1, FT_NONE);
+ ftype1 = check_slice(dfw, st_arg1, logical_ftype);
if (!can_func(ftype1)) {
FAIL(dfw, st_arg1, "%s cannot participate in %s comparison.",
stnode_todisplay(st_arg1), stnode_todisplay(st_node));
@@ -1023,17 +1105,15 @@ check_relation_LHS_SLICE(dfwork_t *dfw, stnode_op_t st_op _U_,
static void
check_relation_LHS_FUNCTION(dfwork_t *dfw, stnode_op_t st_op _U_,
FtypeCanFunc can_func, bool allow_partial_value,
- stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2)
+ stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2,
+ ftenum_t logical_ftype)
{
sttype_id_t type2;
ftenum_t ftype1, ftype2;
LOG_NODE(st_node);
- ftype1 = check_function(dfw, st_arg1, FT_NONE);
- if (ftype1 == FT_NONE) {
- FAIL(dfw, st_arg1, "Constant expression is invalid on the LHS.");
- }
+ ftype1 = check_function(dfw, st_arg1, logical_ftype);
if (!can_func(ftype1)) {
FAIL(dfw, st_arg1, "Function %s (type=%s) cannot participate in %s comparison.",
sttype_function_name(st_arg1), ftype_pretty_name(ftype1),
@@ -1130,17 +1210,15 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, stnode_op_t st_op _U_,
static void
check_relation_LHS_ARITHMETIC(dfwork_t *dfw, stnode_op_t st_op _U_,
FtypeCanFunc can_func, bool allow_partial_value,
- stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2)
+ stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2,
+ ftenum_t logical_ftype)
{
sttype_id_t type2;
ftenum_t ftype1, ftype2;
LOG_NODE(st_node);
- ftype1 = check_arithmetic(dfw, st_arg1, FT_NONE);
- if (ftype1 == FT_NONE) {
- FAIL(dfw, st_arg1, "Constant expression is invalid on the LHS.");
- }
+ ftype1 = check_arithmetic(dfw, st_arg1, logical_ftype);
if (!can_func(ftype1)) {
FAIL(dfw, st_arg1, "Result with type %s cannot participate in %s comparison.",
ftype_pretty_name(ftype1),
@@ -1244,21 +1322,21 @@ check_relation(dfwork_t *dfw, stnode_op_t st_op,
break;
case STTYPE_SLICE:
check_relation_LHS_SLICE(dfw, st_op, can_func,
- allow_partial_value, st_node, st_arg1, st_arg2);
+ allow_partial_value, st_node, st_arg1, st_arg2, find_logical_ftype(dfw, st_node));
break;
case STTYPE_FUNCTION:
check_relation_LHS_FUNCTION(dfw, st_op, can_func,
- allow_partial_value, st_node, st_arg1, st_arg2);
+ allow_partial_value, st_node, st_arg1, st_arg2, find_logical_ftype(dfw, st_node));
break;
case STTYPE_ARITHMETIC:
check_relation_LHS_ARITHMETIC(dfw, st_op, can_func,
- allow_partial_value, st_node, st_arg1, st_arg2);
+ allow_partial_value, st_node, st_arg1, st_arg2, find_logical_ftype(dfw, st_node));
break;
case STTYPE_LITERAL:
case STTYPE_STRING:
case STTYPE_CHARCONST:
check_relation_LHS_FVALUE(dfw, st_op, can_func,
- allow_partial_value, st_node, st_arg1, st_arg2);
+ allow_partial_value, st_node, st_arg1, st_arg2, find_logical_ftype(dfw, st_node));
break;
default:
/* Should not happen. */
@@ -1302,11 +1380,11 @@ check_relation_contains(dfwork_t *dfw, stnode_t *st_node,
break;
case STTYPE_FUNCTION:
check_relation_LHS_FUNCTION(dfw, STNODE_OP_CONTAINS, ftype_can_contains,
- true, st_node, st_arg1, st_arg2);
+ true, st_node, st_arg1, st_arg2, find_logical_ftype(dfw, st_node));
break;
case STTYPE_SLICE:
check_relation_LHS_SLICE(dfw, STNODE_OP_CONTAINS, ftype_can_contains,
- true, st_node, st_arg1, st_arg2);
+ true, st_node, st_arg1, st_arg2, find_logical_ftype(dfw, st_node));
break;
default:
FAIL(dfw, st_arg1, "Left side of %s expression must be a field or function, not %s.",
@@ -1350,11 +1428,11 @@ check_relation_matches(dfwork_t *dfw, stnode_t *st_node,
break;
case STTYPE_FUNCTION:
check_relation_LHS_FUNCTION(dfw, STNODE_OP_MATCHES, ftype_can_matches,
- true, st_node, st_arg1, st_arg2);
+ true, st_node, st_arg1, st_arg2, find_logical_ftype(dfw, st_arg1));
break;
case STTYPE_SLICE:
check_relation_LHS_SLICE(dfw, STNODE_OP_MATCHES, ftype_can_matches,
- true, st_node, st_arg1, st_arg2);
+ true, st_node, st_arg1, st_arg2, find_logical_ftype(dfw, st_arg1));
break;
default:
FAIL(dfw, st_arg1, "Left side of %s expression must be a field or function, not %s.",
@@ -1465,25 +1543,19 @@ check_test(dfwork_t *dfw, stnode_t *st_node)
static void
check_nonzero(dfwork_t *dfw, stnode_t *st_node)
{
- ftenum_t ftype = FT_NONE;
-
LOG_NODE(st_node);
switch (stnode_type_id(st_node)) {
case STTYPE_ARITHMETIC:
- ftype = check_arithmetic(dfw, st_node, FT_NONE);
+ check_arithmetic(dfw, st_node, find_logical_ftype(dfw, st_node));
break;
case STTYPE_SLICE:
- ftype = check_slice(dfw, st_node, FT_NONE);
+ check_slice(dfw, st_node, find_logical_ftype(dfw, st_node));
break;
default:
ws_assert_not_reached();
break;
}
-
- if (ftype == FT_NONE) {
- FAIL(dfw, st_node, "Constant expression is invalid.");
- }
}
static const char *
@@ -1512,7 +1584,7 @@ op_to_error_msg(stnode_op_t st_op)
static ftenum_t
check_arithmetic_LHS(dfwork_t *dfw, stnode_op_t st_op,
stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2,
- ftenum_t lhs_ftype)
+ ftenum_t logical_ftype)
{
ftenum_t ftype1, ftype2;
FtypeCanFunc can_func = NULL;
@@ -1520,9 +1592,7 @@ check_arithmetic_LHS(dfwork_t *dfw, stnode_op_t st_op,
LOG_NODE(st_node);
if (st_op == STNODE_OP_UNARY_MINUS) {
- ftype1 = check_arithmetic(dfw, st_arg1, lhs_ftype);
- if (ftype1 == FT_NONE)
- return FT_NONE;
+ ftype1 = check_arithmetic(dfw, st_arg1, logical_ftype);
if (!ftype_can_unary_minus(ftype1)) {
FAIL(dfw, st_arg1, "%s %s.",
ftype_name(ftype1), op_to_error_msg(st_op));
@@ -1566,10 +1636,7 @@ check_arithmetic_LHS(dfwork_t *dfw, stnode_op_t st_op,
ws_assert_not_reached();
}
- ftype1 = check_arithmetic(dfw, st_arg1, lhs_ftype);
- if (ftype1 == FT_NONE) {
- FAIL(dfw, st_arg1, "Unknown type for left side of %s", stnode_todisplay(st_node));
- }
+ ftype1 = check_arithmetic(dfw, st_arg1, logical_ftype);
if (!can_func(ftype1)) {
FAIL(dfw, st_arg1, "%s %s.",
ftype_name(ftype1), op_to_error_msg(st_op));
@@ -1590,7 +1657,7 @@ check_arithmetic_LHS(dfwork_t *dfw, stnode_op_t st_op,
}
ftenum_t
-check_arithmetic(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype)
+check_arithmetic(dfwork_t *dfw, stnode_t *st_node, ftenum_t logical_ftype)
{
sttype_id_t type;
stnode_op_t st_op;
@@ -1603,13 +1670,8 @@ check_arithmetic(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype)
switch (type) {
case STTYPE_LITERAL:
- if (lhs_ftype != FT_NONE) {
- dfilter_fvalue_from_literal(dfw, lhs_ftype, st_node, false, NULL);
- ftype = sttype_pointer_ftenum(st_node);
- }
- else {
- ftype = FT_NONE;
- }
+ dfilter_fvalue_from_literal(dfw, logical_ftype, st_node, false, NULL);
+ ftype = sttype_pointer_ftenum(st_node);
break;
case STTYPE_FIELD:
@@ -1620,11 +1682,11 @@ check_arithmetic(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype)
break;
case STTYPE_FUNCTION:
- ftype = check_function(dfw, st_node, lhs_ftype);
+ ftype = check_function(dfw, st_node, logical_ftype);
break;
case STTYPE_SLICE:
- ftype = check_slice(dfw, st_node, lhs_ftype);
+ ftype = check_slice(dfw, st_node, logical_ftype);
break;
case STTYPE_FVALUE:
@@ -1633,7 +1695,7 @@ check_arithmetic(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype)
case STTYPE_ARITHMETIC:
sttype_oper_get(st_node, &st_op, &st_arg1, &st_arg2);
- ftype = check_arithmetic_LHS(dfw, st_op, st_node, st_arg1, st_arg2, lhs_ftype);
+ ftype = check_arithmetic_LHS(dfw, st_op, st_node, st_arg1, st_arg2, logical_ftype);
break;
default:
diff --git a/epan/dfilter/semcheck.h b/epan/dfilter/semcheck.h
index 261bdc6559..3a8b4c7fb1 100644
--- a/epan/dfilter/semcheck.h
+++ b/epan/dfilter/semcheck.h
@@ -17,13 +17,16 @@ bool
dfw_semcheck(dfwork_t *dfw);
ftenum_t
-check_arithmetic(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype);
+check_arithmetic(dfwork_t *dfw, stnode_t *st_node, ftenum_t logical_ftype);
ftenum_t
-check_function(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype);
+check_function(dfwork_t *dfw, stnode_t *st_node, ftenum_t logical_ftype);
ftenum_t
-check_slice(dfwork_t *dfw, stnode_t *st, ftenum_t lhs_ftype);
+check_slice(dfwork_t *dfw, stnode_t *st, ftenum_t logical_ftype);
+
+ftenum_t
+get_logical_ftype(stnode_t *st_node);
bool
compatible_ftypes(ftenum_t a, ftenum_t b);
diff --git a/test/suite_dfilter/group_function.py b/test/suite_dfilter/group_function.py
index 68ca624222..530972a4eb 100644
--- a/test/suite_dfilter/group_function.py
+++ b/test/suite_dfilter/group_function.py
@@ -67,10 +67,9 @@ class TestFunctionMaxMin:
dfilter = 'max(5060, udp.dstport) == udp.srcport'
checkDFilterCount(dfilter, 2)
- def test_max_5(self, checkDFilterFail):
- error = 'Constant expression is invalid on the LHS'
+ def test_max_5(self, checkDFilterCount):
dfilter = 'max(5060, 5070) == udp.srcport'
- checkDFilterFail(dfilter, error)
+ checkDFilterCount(dfilter, 1)
class TestFunctionAbs:
trace_file = "dhcp.pcapng"
diff --git a/test/suite_dfilter/group_syntax.py b/test/suite_dfilter/group_syntax.py
index 4f6afc03dd..699e516771 100644
--- a/test/suite_dfilter/group_syntax.py
+++ b/test/suite_dfilter/group_syntax.py
@@ -252,10 +252,9 @@ class TestDfilterUnaryMinus:
dfilter = "tcp.window_size_scalefactor == +tcp.dstport"
checkDFilterCount(dfilter, 0)
- def test_unary_3(self, checkDFilterFail):
- error = 'Constant expression is invalid on the LHS'
+ def test_unary_3(self, checkDFilterCount):
dfilter = "-2 == tcp.dstport"
- checkDFilterFail(dfilter, error)
+ checkDFilterCount(dfilter, 0)
def test_unary_4(self, checkDFilterCount):
dfilter = "tcp.window_size_scalefactor == -{tcp.dstport * 20}"
@@ -281,18 +280,17 @@ class TestDfilterArithmetic:
dfilter = "udp.dstport == 66+1"
checkDFilterCount(dfilter, 2)
- def test_add_4(self, checkDFilterFail):
- error = 'Unknown type for left side of +'
+ def test_add_4(self, checkDFilterCount):
dfilter = "1 + 2 == frame.number"
- checkDFilterFail(dfilter, error)
+ checkDFilterCount(dfilter, 1)
def test_add_5(self, checkDFilterFail):
- error = 'Unknown type for left side of +'
+ error = 'Constant expression is invalid'
dfilter = "1 + 2 == 2 + 1"
checkDFilterFail(dfilter, error)
def test_add_6(self, checkDFilterFail):
- error = 'Unknown type for left side of -'
+ error = 'Constant expression is invalid'
dfilter = "1 - 2"
checkDFilterFail(dfilter, error)