diff --git a/epan/dfilter/dfilter-int.h b/epan/dfilter/dfilter-int.h index 0e4bf3f752..b477d7418a 100644 --- a/epan/dfilter/dfilter-int.h +++ b/epan/dfilter/dfilter-int.h @@ -56,6 +56,10 @@ typedef struct { GHashTable *raw_references; /* hfinfo -> pointer to array of references */ char *expanded_text; gboolean apply_optimization; + wmem_allocator_t *dfw_scope; /* Because we use exceptions for error handling sometimes + cleaning up memory allocations is inconvenient. Memory + allocated from this pool will be freed when the dfwork_t + context is destroyed. */ } dfwork_t; /* diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c index b1a96f8a5d..03e367e698 100644 --- a/epan/dfilter/dfilter.c +++ b/epan/dfilter/dfilter.c @@ -234,6 +234,8 @@ dfwork_new(void) g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)free_refs_array); + dfw->dfw_scope = wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE); + return dfw; } @@ -273,6 +275,8 @@ dfwork_free(dfwork_t *dfw) g_free(dfw->expanded_text); + wmem_destroy_allocator(dfw->dfw_scope); + /* * We don't free the error message string; our caller will return * it to its caller. 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; + ftype = lhs_ftype; - 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); - } - - 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; } diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c index b93707289f..6c67e0a914 100644 --- a/epan/dfilter/semcheck.c +++ b/epan/dfilter/semcheck.c @@ -787,8 +787,8 @@ check_relation_LHS_SLICE(dfwork_t *dfw, stnode_op_t st_op, static void check_relation_LHS_FUNCTION(dfwork_t *dfw, stnode_op_t st_op, FtypeCanFunc can_func, gboolean 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, + int commute) { sttype_id_t type2; ftenum_t ftype1, ftype2; @@ -797,7 +797,11 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, stnode_op_t st_op, LOG_NODE(st_node); ftype1 = check_function(dfw, st_arg1, FT_NONE); - + if (ftype1 == FT_NONE) { + check_relation(dfw, st_op, can_func, allow_partial_value, + st_node, st_arg2, st_arg1, commute - 1); + return; + } 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), @@ -1006,7 +1010,7 @@ check_relation(dfwork_t *dfw, stnode_op_t st_op, 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, commute); break; case STTYPE_ARITHMETIC: check_relation_LHS_ARITHMETIC(dfw, st_op, can_func, @@ -1042,7 +1046,7 @@ 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, 0); break; case STTYPE_SLICE: check_relation_LHS_SLICE(dfw, STNODE_OP_CONTAINS, ftype_can_contains, @@ -1089,7 +1093,7 @@ 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, 0); break; case STTYPE_SLICE: check_relation_LHS_SLICE(dfw, STNODE_OP_MATCHES, ftype_can_matches, diff --git a/test/suite_dfilter/group_function.py b/test/suite_dfilter/group_function.py index 9d80082b3f..517fa91f34 100644 --- a/test/suite_dfilter/group_function.py +++ b/test/suite_dfilter/group_function.py @@ -66,10 +66,13 @@ class case_dfunction_maxmin(unittest.TestCase): dfilter = 'max(udp.srcport, udp.dstport) < 5060' checkDFilterCount(dfilter, 1) - def test_max_4(self, checkDFilterFail): - error = 'Argument \'1\' is not valid for max()' - dfilter = 'max(1,_ws.ftypes.int8) == 1' - checkDFilterFail(dfilter, error) + def test_max_4(self, checkDFilterCount): + dfilter = 'max(5060, udp.dstport) == udp.srcport' + checkDFilterCount(dfilter, 2) + + def test_max_5(self, checkDFilterCount): + dfilter = 'max(5060, 5070) == udp.srcport' + checkDFilterCount(dfilter, 1) @fixtures.uses_fixtures class case_dfunction_abs(unittest.TestCase):