forked from osmocom/wireshark
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
This commit is contained in:
parent
6399f724d9
commit
b19bed43d1
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue