wireshark/epan/dfilter/sttype-test.c

406 lines
6.6 KiB
C
Raw Normal View History

/*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 2001 Gerald Combs
*
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "syntax-tree.h"
#include "sttype-test.h"
typedef struct {
guint32 magic;
test_op_t op;
stnode_t *val1;
stnode_t *val2;
} test_t;
#define TEST_MAGIC 0xab9009ba
static gpointer
test_new(gpointer junk)
{
test_t *test;
ws_assert(junk == NULL);
test = g_new(test_t, 1);
test->magic = TEST_MAGIC;
test->op = TEST_OP_UNINITIALIZED;
test->val1 = NULL;
test->val2 = NULL;
return test;
}
static gpointer
test_dup(gconstpointer data)
{
const test_t *org = data;
test_t *test;
test = test_new(NULL);
test->op = org->op;
test->val1 = stnode_dup(org->val1);
test->val2 = stnode_dup(org->val1);
return test;
}
static void
test_free(gpointer value)
{
test_t *test = value;
ws_assert_magic(test, TEST_MAGIC);
if (test->val1)
stnode_free(test->val1);
if (test->val2)
stnode_free(test->val2);
g_free(test);
}
static const char *
test_todisplay(test_op_t op)
{
const char *s = "<notset>";
switch(op) {
case TEST_OP_EXISTS:
s = "<exists>";
break;
case TEST_OP_NOT:
s = "!";
break;
case TEST_OP_AND:
s = "&&";
break;
case TEST_OP_OR:
s = "||";
break;
case TEST_OP_ALL_EQ:
s = "===";
break;
case TEST_OP_ANY_EQ:
s = "==";
break;
case TEST_OP_ALL_NE:
s = "!=";
break;
case TEST_OP_ANY_NE:
s = "~=";
break;
case TEST_OP_GT:
s = ">";
break;
case TEST_OP_GE:
s = ">=";
break;
case TEST_OP_LT:
s = "<";
break;
case TEST_OP_LE:
s = "<=";
break;
case OP_BITWISE_AND:
s = "&";
break;
case OP_ADD:
s = "+";
break;
case OP_UNARY_MINUS:
case OP_SUBTRACT:
s = "-";
break;
case OP_MULTIPLY:
s = "*";
break;
case OP_DIVIDE:
s = "/";
break;
case OP_MODULO:
s = "%";
break;
case TEST_OP_NOTZERO:
s = "<notzero>";
break;
case TEST_OP_CONTAINS:
s = "contains";
break;
case TEST_OP_MATCHES:
s = "matches";
break;
case TEST_OP_IN:
s = "in";
break;
case TEST_OP_UNINITIALIZED:
s = "<uninitialized>";
break;
}
return s;
}
static const char *
test_todebug(test_op_t op)
{
const char *s = "<notset>";
switch(op) {
case TEST_OP_EXISTS:
s = "TEST_EXISTS";
break;
case TEST_OP_NOT:
s = "TEST_NOT";
break;
case TEST_OP_AND:
s = "TEST_AND";
break;
case TEST_OP_OR:
s = "TEST_OR";
break;
case TEST_OP_ALL_EQ:
s = "TEST_ALL_EQ";
break;
dfilter: Fix "!=" relation to be free of contradictions Wireshark defines the relation of equality A == B as A any_eq B <=> An == Bn for at least one An, Bn. More accurately I think this is (formally) an equivalence relation, not true equality. Whichever definition for "==" we choose we must keep the definition of "!=" as !(A == B), otherwise it will lead to logical contradictions like (A == B) AND (A != B) being true. Fix the '!=' relation to match the definition of equality: A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for every n. This has been the recomended way to write "not equal" for a long time in the documentation, even to the point where != was deprecated, but it just wasn't implemented consistently in the language, which has understandably been a persistent source of confusion. Even a field that is normally well-behaved with "!=" like "ip.src" or "ip.dst" will produce unexpected results with encapsulations like IP-over-IP. The opcode ALL_NE could have been implemented in the compiler instead using NOT and ANY_EQ but I chose to implement it in bytecode. It just seemed more elegant and efficient but the difference was not very significant. Keep around "~=" for any_ne relation, in case someone depends on that, and because we don't have an operator for true equality: A strict_equal B <=> A all_eq B <=> !(A any_ne B). If there is only one value then any_ne and all_ne are the same comparison operation. Implementing this change did not require fixing any tests so it is unlikely the relation "~=" (any_ne) will be very useful. Note that the behaviour of the '<' (less than) comparison relation is a separate, more subtle issue. In the general case the definition of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
case TEST_OP_ANY_EQ:
s = "TEST_ANY_EQ";
break;
dfilter: Fix "!=" relation to be free of contradictions Wireshark defines the relation of equality A == B as A any_eq B <=> An == Bn for at least one An, Bn. More accurately I think this is (formally) an equivalence relation, not true equality. Whichever definition for "==" we choose we must keep the definition of "!=" as !(A == B), otherwise it will lead to logical contradictions like (A == B) AND (A != B) being true. Fix the '!=' relation to match the definition of equality: A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for every n. This has been the recomended way to write "not equal" for a long time in the documentation, even to the point where != was deprecated, but it just wasn't implemented consistently in the language, which has understandably been a persistent source of confusion. Even a field that is normally well-behaved with "!=" like "ip.src" or "ip.dst" will produce unexpected results with encapsulations like IP-over-IP. The opcode ALL_NE could have been implemented in the compiler instead using NOT and ANY_EQ but I chose to implement it in bytecode. It just seemed more elegant and efficient but the difference was not very significant. Keep around "~=" for any_ne relation, in case someone depends on that, and because we don't have an operator for true equality: A strict_equal B <=> A all_eq B <=> !(A any_ne B). If there is only one value then any_ne and all_ne are the same comparison operation. Implementing this change did not require fixing any tests so it is unlikely the relation "~=" (any_ne) will be very useful. Note that the behaviour of the '<' (less than) comparison relation is a separate, more subtle issue. In the general case the definition of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
case TEST_OP_ALL_NE:
s = "TEST_ALL_NE";
break;
case TEST_OP_ANY_NE:
s = "TEST_ANY_NE";
break;
case TEST_OP_GT:
s = "TEST_GT";
break;
case TEST_OP_GE:
s = "TEST_GE";
break;
case TEST_OP_LT:
s = "TEST_LT";
break;
case TEST_OP_LE:
s = "TEST_LE";
break;
case OP_BITWISE_AND:
s = "OP_BITWISE_AND";
break;
case OP_UNARY_MINUS:
s = "OP_UNARY_MINUS";
break;
case OP_ADD:
s = "OP_ADD";
break;
case OP_SUBTRACT:
s = "OP_SUBTRACT";
break;
case OP_MULTIPLY:
s = "OP_MULTIPLY";
break;
case OP_DIVIDE:
s = "OP_DIVIDE";
break;
case OP_MODULO:
s = "OP_MODULO";
break;
case TEST_OP_NOTZERO:
s = "TEST_NOTZERO";
break;
case TEST_OP_CONTAINS:
s = "TEST_CONTAINS";
break;
case TEST_OP_MATCHES:
s = "TEST_MATCHES";
break;
case TEST_OP_IN:
s = "TEST_IN";
break;
case TEST_OP_UNINITIALIZED:
s = "<uninitialized>";
break;
}
return s;
}
static char *
test_tostr(const void *value, gboolean pretty)
{
const test_t *test = value;
ws_assert_magic(test, TEST_MAGIC);
const char *s;
if (pretty)
s = test_todisplay(test->op);
else
s = test_todebug(test->op);
return g_strdup(s);
}
static int
num_operands(test_op_t op)
{
switch(op) {
case TEST_OP_UNINITIALIZED:
break;
case TEST_OP_EXISTS:
case TEST_OP_NOT:
case TEST_OP_NOTZERO:
case OP_UNARY_MINUS:
return 1;
case TEST_OP_AND:
case TEST_OP_OR:
case TEST_OP_ALL_EQ:
dfilter: Fix "!=" relation to be free of contradictions Wireshark defines the relation of equality A == B as A any_eq B <=> An == Bn for at least one An, Bn. More accurately I think this is (formally) an equivalence relation, not true equality. Whichever definition for "==" we choose we must keep the definition of "!=" as !(A == B), otherwise it will lead to logical contradictions like (A == B) AND (A != B) being true. Fix the '!=' relation to match the definition of equality: A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for every n. This has been the recomended way to write "not equal" for a long time in the documentation, even to the point where != was deprecated, but it just wasn't implemented consistently in the language, which has understandably been a persistent source of confusion. Even a field that is normally well-behaved with "!=" like "ip.src" or "ip.dst" will produce unexpected results with encapsulations like IP-over-IP. The opcode ALL_NE could have been implemented in the compiler instead using NOT and ANY_EQ but I chose to implement it in bytecode. It just seemed more elegant and efficient but the difference was not very significant. Keep around "~=" for any_ne relation, in case someone depends on that, and because we don't have an operator for true equality: A strict_equal B <=> A all_eq B <=> !(A any_ne B). If there is only one value then any_ne and all_ne are the same comparison operation. Implementing this change did not require fixing any tests so it is unlikely the relation "~=" (any_ne) will be very useful. Note that the behaviour of the '<' (less than) comparison relation is a separate, more subtle issue. In the general case the definition of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
case TEST_OP_ANY_EQ:
case TEST_OP_ALL_NE:
case TEST_OP_ANY_NE:
case TEST_OP_GT:
case TEST_OP_GE:
case TEST_OP_LT:
case TEST_OP_LE:
case OP_BITWISE_AND:
case OP_ADD:
case OP_SUBTRACT:
case OP_MULTIPLY:
case OP_DIVIDE:
case OP_MODULO:
case TEST_OP_CONTAINS:
case TEST_OP_MATCHES:
case TEST_OP_IN:
return 2;
}
ws_assert_not_reached();
return -1;
}
void
sttype_test_set1(stnode_t *node, test_op_t op, stnode_t *val1)
{
test_t *test = stnode_data(node);
ws_assert_magic(test, TEST_MAGIC);
ws_assert(num_operands(op) == 1);
test->op = op;
test->val1 = val1;
test->val2 = NULL;
}
void
sttype_test_set2(stnode_t *node, test_op_t op, stnode_t *val1, stnode_t *val2)
{
test_t *test = stnode_data(node);
ws_assert_magic(test, TEST_MAGIC);
ws_assert(num_operands(op) == 2);
test->op = op;
test->val1 = val1;
test->val2 = val2;
}
void
sttype_test_set1_args(stnode_t *node, stnode_t *val1)
{
test_t *test;
test = (test_t*)stnode_data(node);
ws_assert_magic(test, TEST_MAGIC);
ws_assert(num_operands(test->op) == 1);
test->val1 = val1;
test->val2 = NULL;
}
void
sttype_test_set2_args(stnode_t *node, stnode_t *val1, stnode_t *val2)
{
test_t *test;
test = (test_t*)stnode_data(node);
ws_assert_magic(test, TEST_MAGIC);
ws_assert(num_operands(test->op) == 2);
test->val1 = val1;
test->val2 = val2;
}
void
sttype_test_set_op(stnode_t *node, test_op_t op)
{
test_t *test = stnode_data(node);
ws_assert_magic(test, TEST_MAGIC);
ws_assert(test->op == TEST_OP_UNINITIALIZED);
test->op = op;
}
test_op_t
sttype_test_get_op(stnode_t *node)
{
ws_assert_magic(node, TEST_MAGIC);
return ((test_t *)node)->op;
}
void
sttype_test_get(stnode_t *node, test_op_t *p_op, stnode_t **p_val1, stnode_t **p_val2)
{
test_t *test = stnode_data(node);
ws_assert_magic(test, TEST_MAGIC);
if (p_op)
*p_op = test->op;
if (p_val1)
*p_val1 = test->val1;
if (p_val2)
*p_val2 = test->val2;
}
void
sttype_register_test(void)
{
static sttype_t test_type = {
STTYPE_TEST,
"TEST",
test_new,
test_free,
test_dup,
test_tostr
};
/* XXX Bitwise ops are not "tests". */
static sttype_t bitwise_type = {
STTYPE_BITWISE,
"BITWISE",
test_new,
test_free,
test_dup,
test_tostr
};
static sttype_t arithmetic_type = {
STTYPE_ARITHMETIC,
"ARITHMETIC",
test_new,
test_free,
test_dup,
test_tostr
};
sttype_register(&test_type);
sttype_register(&bitwise_type);
sttype_register(&arithmetic_type);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/