aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dfilter/dfunctions.c
diff options
context:
space:
mode:
authorJoão Valverde <j@v6e.pt>2022-12-26 03:42:07 +0000
committerJoão Valverde <j@v6e.pt>2022-12-27 02:21:06 +0000
commitb19bed43d19207355520b360cb7e7ed41a7b68c2 (patch)
tree3a26a1a5b072eb78dd6e50da32bd688de4521918 /epan/dfilter/dfunctions.c
parent6399f724d9c8f7926ba7bbd16eceb503f11b8602 (diff)
dfilter: Allow constants as the first or only argument to min/max
The strategy here is to delay resolving literals to values until we have looked at the entire argument list. Also we will try to commute the relation in a comparison if we do not have a type for the return value of the function, like any other constant. Before: Filter: max(1,_ws.ftypes.int8) == 1 dftest: Argument '1' is not valid for max() max(1,_ws.ftypes.int8) == 1 ^ After: Filter: max(1,_ws.ftypes.int8) == 1 Syntax tree: 0 TEST_ANY_EQ: 1 FUNCTION(max#2): 2 FVALUE(1 <FT_INT8>) 2 FIELD(_ws.ftypes.int8 <FT_INT8>) 1 FVALUE(1 <FT_INT8>) Instructions: 00000 STACK_PUSH 1 <FT_INT8> 00001 READ_TREE _ws.ftypes.int8 <FT_INT8> -> reg#1 00002 IF_FALSE_GOTO 3 00003 STACK_PUSH reg#1 00004 CALL_FUNCTION max(reg#1, 1 <FT_INT8>) -> reg#0 00005 STACK_POP 2 00006 IF_FALSE_GOTO 8 00007 ANY_EQ reg#0 == 1 <FT_INT8> 00008 RETURN
Diffstat (limited to 'epan/dfilter/dfunctions.c')
-rw-r--r--epan/dfilter/dfunctions.c75
1 files changed, 45 insertions, 30 deletions
diff --git a/epan/dfilter/dfunctions.c b/epan/dfilter/dfunctions.c
index 5c8b122878..e21f03898c 100644
--- a/epan/dfilter/dfunctions.c
+++ b/epan/dfilter/dfunctions.c
@@ -330,51 +330,52 @@ 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,
GSList *param_list, df_loc_t func_loc _U_)
{
stnode_t *arg;
+ sttype_id_t type;
ftenum_t ftype, ft_arg;
GSList *l;
fvalue_t *fv;
+ wmem_list_t *literals = NULL;
- arg = param_list->data;
-
- if (stnode_type_id(arg) == STTYPE_ARITHMETIC) {
- ftype = check_arithmetic(dfw, arg, lhs_ftype);
- }
- else if (stnode_type_id(arg) == STTYPE_LITERAL && lhs_ftype != FT_NONE) {
- fv = dfilter_fvalue_from_literal(dfw, lhs_ftype, arg, FALSE, NULL);
- stnode_replace(arg, STTYPE_FVALUE, fv);
- ftype = fvalue_type_ftenum(fv);
- }
- else if (stnode_type_id(arg) == STTYPE_FUNCTION) {
- ftype = check_function(dfw, arg, lhs_ftype);
- }
- else if (stnode_type_id(arg) == STTYPE_FIELD || stnode_type_id(arg) == STTYPE_REFERENCE) {
- ftype = sttype_field_ftenum(arg);
- }
- else {
- FAIL(dfw, arg, "Argument '%s' is not valid for %s()",
- stnode_todisplay(arg), func_name);
- }
+ ftype = lhs_ftype;
- for (l = param_list->next; l != NULL; l = l->next) {
+ for (l = param_list; l != NULL; l = l->next) {
arg = l->data;
+ type = stnode_type_id(arg);
- if (stnode_type_id(arg) == STTYPE_ARITHMETIC) {
+ if (type == STTYPE_ARITHMETIC) {
ft_arg = check_arithmetic(dfw, arg, ftype);
}
- else if (stnode_type_id(arg) == STTYPE_LITERAL && ftype != FT_NONE) {
- fv = dfilter_fvalue_from_literal(dfw, ftype, arg, FALSE, NULL);
- stnode_replace(arg, STTYPE_FVALUE, fv);
- ft_arg = fvalue_type_ftenum(fv);
+ else if (type == STTYPE_LITERAL) {
+ if (ftype != FT_NONE) {
+ fv = dfilter_fvalue_from_literal(dfw, ftype, arg, FALSE, NULL);
+ stnode_replace(arg, STTYPE_FVALUE, fv);
+ ft_arg = fvalue_type_ftenum(fv);
+ }
+ else {
+ if (literals == NULL) {
+ literals = wmem_list_new(dfw->dfw_scope);
+ }
+ wmem_list_append(literals, arg);
+ ft_arg = FT_NONE;
+ }
}
- else if (stnode_type_id(arg) == STTYPE_FUNCTION) {
+ else if (type == STTYPE_FUNCTION) {
ft_arg = check_function(dfw, arg, ftype);
}
- else if (stnode_type_id(arg) == STTYPE_FIELD || stnode_type_id(arg) == STTYPE_REFERENCE) {
+ else if (type == STTYPE_FIELD || type == STTYPE_REFERENCE) {
ft_arg = sttype_field_ftenum(arg);
}
else {
@@ -385,15 +386,29 @@ ul_semcheck_compare(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
if (ftype == FT_NONE) {
ftype = ft_arg;
}
- if (ft_arg != ftype) {
+ if (ft_arg != FT_NONE && ftype != FT_NONE && ft_arg != ftype) {
FAIL(dfw, arg, "Arguments to '%s' must have the same type (expected %s, got %s)",
func_name, ftype_name(ftype), ftype_name(ft_arg));
}
- if (!ftype_can_cmp(ft_arg)) {
+ if (ft_arg != FT_NONE && !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);
+ fv = dfilter_fvalue_from_literal(dfw, ftype, st, FALSE, NULL);
+ stnode_replace(st, STTYPE_FVALUE, fv);
+ }
+ }
+ wmem_destroy_list(literals);
+ }
+
return ftype;
}