dfilter: Add location tracking to scanner and use it to report errors

Add location tracking as a column offset and length from offset
to the scanner. Our input is a single line only so we don't need
to track line offset.

Record that information in the syntax tree. Return the error location
in dfilter_compile(). Use it in dftest to mark the location of the
error in the filter string. Later it would be nice to use the location
in the GUI as well.

$ dftest "ip.proto == aaaaaa and tcp.port == 123"
Filter: ip.proto == aaaaaa and tcp.port == 123
dftest: "aaaaaa" cannot be found among the possible values for ip.proto.
	ip.proto == aaaaaa and tcp.port == 123
	            ^~~~~~
This commit is contained in:
João Valverde 2022-04-07 13:57:39 +01:00
parent da19379eb5
commit 4d9470e7dd
11 changed files with 362 additions and 237 deletions

View File

@ -40,6 +40,23 @@
static void dftest_cmdarg_err(const char *fmt, va_list ap);
static void dftest_cmdarg_err_cont(const char *fmt, va_list ap);
static void
putloc(FILE *fp, int start, size_t len)
{
if (start < 0)
return;
for (int i = 0; i < start; i++) {
fputc(' ', fp);
}
fputc('^', fp);
for (size_t l = len; l > 1; l--) {
fputc('~', fp);
}
fputc('\n', fp);
}
int
main(int argc, char **argv)
{
@ -57,8 +74,10 @@ main(int argc, char **argv)
cfile_close_failure_message
};
char *text;
char *expanded_text;
dfilter_t *df;
gchar *err_msg;
dfilter_loc_t err_loc;
cmdarg_err_init(dftest_cmdarg_err, dftest_cmdarg_err_cont);
@ -130,27 +149,44 @@ main(int argc, char **argv)
/* Get filter text */
text = get_args_as_string(argc, argv, 1);
/* Compile it */
if (!dfilter_compile2(text, &df, &err_msg, TRUE)) {
/* Expand macros. */
expanded_text = dfilter_expand(text, &err_msg);
if (expanded_text == NULL) {
fprintf(stderr, "dftest: %s\n", err_msg);
g_free(err_msg);
epan_cleanup();
g_free(text);
epan_cleanup();
exit(2);
}
g_free(text);
text = NULL;
printf("Filter: %s\n", expanded_text);
/* Compile it */
if (!dfilter_compile_real(expanded_text, &df, &err_msg, &err_loc,
"dftest", TRUE, FALSE)) {
fprintf(stderr, "dftest: %s\n", err_msg);
fprintf(stderr, "\t%s\n", expanded_text);
fputc('\t', stderr);
putloc(stderr, err_loc.col_start, err_loc.col_len);
g_free(err_msg);
g_free(expanded_text);
epan_cleanup();
exit(2);
}
if (df == NULL) {
printf("Filter is empty\n");
printf("Filter is empty.\n");
}
else {
printf("Filter text:\n%s\n\n", dfilter_text(df));
printf("Syntax tree:\n%s\n\n", dfilter_syntax_tree(df));
printf("\nSyntax tree:\n%s\n\n", dfilter_syntax_tree(df));
dfilter_dump(df);
}
dfilter_free(df);
epan_cleanup();
g_free(text);
g_free(expanded_text);
exit(0);
}

View File

@ -44,6 +44,8 @@ typedef struct {
GPtrArray *deprecated;
GHashTable *references; /* hfinfo -> pointer to GSList of fvalues */
GHashTable *loaded_references;
char *expanded_text;
stloc_t err_loc;
} dfwork_t;
/*
@ -53,6 +55,8 @@ typedef struct {
dfwork_t *dfw;
GString* quoted_string;
gboolean raw_string;
stloc_t string_loc;
stloc_t location;
} df_scanner_state_t;
/* Constructor/Destructor prototypes for Lemon Parser */
@ -66,14 +70,20 @@ void Dfilter(void*, int, stnode_t*, dfwork_t*);
#define SCAN_FAILED -1 /* not 0, as that means end-of-input */
void
dfilter_vfail(dfwork_t *dfw, const char *format, va_list args);
dfilter_vfail(dfwork_t *dfw, stloc_t *err_loc,
const char *format, va_list args);
void
dfilter_fail(dfwork_t *dfw, const char *format, ...) G_GNUC_PRINTF(2, 3);
dfilter_fail(dfwork_t *dfw, stloc_t *err_loc,
const char *format, ...) G_GNUC_PRINTF(3, 4);
WS_NORETURN
void
dfilter_fail_throw(dfwork_t *dfw, long code, const char *format, ...) G_GNUC_PRINTF(3, 4);
dfilter_fail_throw(dfwork_t *dfw, stloc_t *err_loc,
long code, const char *format, ...) G_GNUC_PRINTF(4, 5);
void
dfw_set_error_location(dfwork_t *dfw, stloc_t *err_loc);
void
add_deprecated_token(dfwork_t *dfw, const char *token);

View File

@ -42,7 +42,8 @@ static void* ParserObj = NULL;
dfwork_t *global_dfw;
void
dfilter_vfail(dfwork_t *dfw, const char *format, va_list args)
dfilter_vfail(dfwork_t *dfw, stloc_t *loc,
const char *format, va_list args)
{
/* Flag a syntax error. This is currently only used in
* the grammar parsing stage to terminate the parsing
@ -54,29 +55,42 @@ dfilter_vfail(dfwork_t *dfw, const char *format, va_list args)
return;
dfw->error_message = ws_strdup_vprintf(format, args);
if (loc) {
dfw->err_loc = *loc;
}
}
void
dfilter_fail(dfwork_t *dfw, const char *format, ...)
dfilter_fail(dfwork_t *dfw, stloc_t *loc,
const char *format, ...)
{
va_list args;
va_start(args, format);
dfilter_vfail(dfw, format, args);
dfilter_vfail(dfw, loc, format, args);
va_end(args);
}
void
dfilter_fail_throw(dfwork_t *dfw, long code, const char *format, ...)
dfilter_fail_throw(dfwork_t *dfw, stloc_t *loc,
long code, const char *format, ...)
{
va_list args;
va_start(args, format);
dfilter_vfail(dfw, format, args);
dfilter_vfail(dfw, loc, format, args);
va_end(args);
THROW(code);
}
void
dfw_set_error_location(dfwork_t *dfw, stloc_t *loc)
{
/* Set new location. */
ws_assert(loc);
dfw->err_loc = *loc;
}
/*
* Tries to convert an STTYPE_UNPARSED to a STTYPE_FIELD. If it's not registered as
* a field pass UNPARSED to the semantic check.
@ -254,6 +268,8 @@ dfwork_free(dfwork_t *dfw)
if (dfw->deprecated)
g_ptr_array_unref(dfw->deprecated);
g_free(dfw->expanded_text);
/*
* We don't free the error message string; our caller will return
* it to its caller.
@ -321,12 +337,18 @@ add_deprecated_token(dfwork_t *dfw, const char *token)
g_ptr_array_add(deprecated, g_strdup(token));
}
char *
dfilter_expand(const char *expr, char **err_ret)
{
return dfilter_macro_apply(expr, err_ret);
}
gboolean
dfilter_compile_real(const gchar *text, dfilter_t **dfp,
gchar **error_ret, const char *caller,
gboolean save_tree)
gchar **error_ret, dfilter_loc_t *loc_ptr,
const char *caller, gboolean save_tree,
gboolean apply_macros)
{
gchar *expanded_text;
int token;
dfilter_t *dfilter;
dfwork_t *dfw;
@ -364,28 +386,32 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp,
dfw = dfwork_new();
expanded_text = dfilter_macro_apply(text, &dfw->error_message);
if (expanded_text == NULL) {
goto FAILURE;
if (apply_macros) {
dfw->expanded_text = dfilter_macro_apply(text, &dfw->error_message);
if (dfw->expanded_text == NULL) {
goto FAILURE;
}
ws_noisy("Expanded text: %s", dfw->expanded_text);
}
else {
dfw->expanded_text = g_strdup(text);
ws_noisy("Verbatim text: %s", dfw->expanded_text);
}
ws_noisy("Expanded text: %s", expanded_text);
if (df_lex_init(&scanner) != 0) {
dfw->error_message = ws_strdup_printf("Can't initialize scanner: %s", g_strerror(errno));
goto FAILURE;
}
in_buffer = df__scan_string(expanded_text, scanner);
in_buffer = df__scan_string(dfw->expanded_text, scanner);
memset(&state, 0, sizeof(state));
state.dfw = dfw;
state.quoted_string = NULL;
state.raw_string = FALSE;
df_set_extra(&state, scanner);
while (1) {
df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL, NULL);
df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL, NULL, NULL);
token = df_lex(scanner);
/* Check for scanner failure */
@ -473,7 +499,8 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp,
dfw->insns = NULL;
dfilter->interesting_fields = dfw_interesting_fields(dfw,
&dfilter->num_interesting_fields);
dfilter->expanded_text = ws_strdup(expanded_text);
dfilter->expanded_text = dfw->expanded_text;
dfw->expanded_text = NULL;
dfilter->references = dfw->references;
dfw->references = NULL;
@ -504,7 +531,6 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp,
ws_log(WS_LOG_DOMAIN, LOG_LEVEL_INFO, "Compiled display filter: %s", text);
else
ws_debug("Compiled empty filter (successfully).");
wmem_free(NULL, expanded_text);
return TRUE;
FAILURE:
@ -521,11 +547,14 @@ FAILURE:
else {
g_free(dfw->error_message);
}
if (loc_ptr != NULL) {
loc_ptr->col_start = dfw->err_loc.col_start;
loc_ptr->col_len = dfw->err_loc.col_len;
}
}
global_dfw = NULL;
dfwork_free(dfw);
wmem_free(NULL, expanded_text);
*dfp = NULL;
return FALSE;
}

View File

@ -32,6 +32,11 @@ dfilter_init(void);
void
dfilter_cleanup(void);
/* Perform macro expansion. */
WS_DLL_PUBLIC
char *
dfilter_expand(const char *expr, char **err_ret);
/* Compiles a string to a dfilter_t.
* On success, sets the dfilter* pointed to by dfp
* to either a NULL pointer (if the filter is a null
@ -46,17 +51,21 @@ dfilter_cleanup(void);
*
* Returns TRUE on success, FALSE on failure.
*/
typedef struct _dfilter_loc {
int col_start;
size_t col_len;
} dfilter_loc_t;
WS_DLL_PUBLIC
gboolean
dfilter_compile_real(const gchar *text, dfilter_t **dfp,
gchar **err_msg, const char *caller,
gboolean save_tree);
gchar **err_msg, dfilter_loc_t *loc_ptr,
const char *caller, gboolean save_tree,
gboolean apply_macros);
#define dfilter_compile(text, dfp, err_msg) \
dfilter_compile_real(text, dfp, err_msg, __func__, FALSE)
#define dfilter_compile2(text, dfp, err_msg, save_tree) \
dfilter_compile_real(text, dfp, err_msg, __func__, save_tree)
dfilter_compile_real(text, dfp, err_msg, NULL, __func__, FALSE, TRUE)
/* Frees all memory used by dfilter, and frees
* the dfilter itself. */

View File

@ -19,8 +19,8 @@
#include <epan/exceptions.h>
#include <wsutil/ws_assert.h>
#define FAIL(dfw, ...) \
dfilter_fail_throw(dfw, TypeError, __VA_ARGS__)
#define FAIL(dfw, node, ...) \
dfilter_fail_throw(dfw, stnode_location(node), TypeError, __VA_ARGS__)
/* Convert an FT_STRING using a callback function */
static gboolean
@ -183,7 +183,7 @@ ul_semcheck_is_field_string(dfwork_t *dfw, const char *func_name,
return;
}
}
FAIL(dfw, "Only string type fields can be used as parameter for %s()", func_name);
FAIL(dfw, st_node, "Only string type fields can be used as parameter for %s()", func_name);
}
static void
@ -195,7 +195,7 @@ ul_semcheck_is_field(dfwork_t *dfw, const char *func_name,
if (stnode_type_id(st_node) == STTYPE_FIELD)
return;
FAIL(dfw, "Only fields can be used as parameter for %s()", func_name);
FAIL(dfw, st_node, "Only fields can be used as parameter for %s()", func_name);
}
static void
@ -245,9 +245,9 @@ ul_semcheck_string_param(dfwork_t *dfw, const char *func_name,
default:
break;
}
FAIL(dfw, "String conversion for field \"%s\" is not supported", hfinfo->abbrev);
FAIL(dfw, st_node, "String conversion for field \"%s\" is not supported", hfinfo->abbrev);
}
FAIL(dfw, "Only fields can be used as parameter for %s()", func_name);
FAIL(dfw, st_node, "Only fields can be used as parameter for %s()", func_name);
}
/* The table of all display-filter functions */

View File

@ -21,6 +21,8 @@
static stnode_t *
new_function(dfwork_t *dfw, stnode_t *node);
#define FAIL(dfw, node, ...) dfilter_fail(dfw, stnode_location(node), __VA_ARGS__)
/* End of C code */
}
@ -55,10 +57,10 @@ new_function(dfwork_t *dfw, stnode_t *node);
any "error" symbols are shifted, if possible. */
%syntax_error {
if (!TOKEN) {
dfilter_fail(dfw, "Unexpected end of filter expression.");
dfilter_fail(dfw, NULL, "Unexpected end of filter expression.");
return;
}
dfilter_fail(dfw, "\"%s\" was unexpected in this context.", stnode_token(TOKEN));
FAIL(dfw, TOKEN, "\"%s\" was unexpected in this context.", stnode_token(TOKEN));
}
/* When a parse fails, mark an error. This occurs after
@ -213,8 +215,8 @@ comparison_test(T) ::= arithmetic_expr(E) cmp_op(O) comparison_test(R).
L = O;
sttype_test_set2_args(L, E, stnode_dup(F));
T = stnode_new_test(TEST_OP_AND, NULL);
sttype_test_set2_args(T, L, R);
T = stnode_new(STTYPE_TEST, NULL, NULL, NULL);
sttype_test_set2(T, TEST_OP_AND, L, R);
}
relation_test(T) ::= comparison_test(C). { T = C; }
@ -246,7 +248,7 @@ relation_test(T) ::= entity(E) TEST_NOT(P) TEST_IN(O) set(S).
set(S) ::= LBRACE set_list(L) RBRACE.
{
S = stnode_new(STTYPE_SET, L, NULL);
S = stnode_new(STTYPE_SET, L, NULL, NULL);
}
set_list(L) ::= set_element(N).
@ -291,7 +293,7 @@ set_element(N) ::= set_entity(X) DOTDOT set_entity(Y).
range(R) ::= entity(E) LBRACKET range_node_list(L) RBRACKET.
{
R = stnode_new(STTYPE_RANGE, NULL, NULL);
R = stnode_new(STTYPE_RANGE, NULL, NULL, NULL);
sttype_range_set(R, E, L);
/* Delete the list, but not the drange_nodes that
@ -321,7 +323,7 @@ range_node_list(L) ::= range_node_list(P) COMMA RANGE_NODE(N).
df_func_def_t *def = df_func_lookup(name);
if (!def) {
dfilter_fail(dfw, "Function '%s' does not exist", name);
FAIL(dfw, node, "Function '%s' does not exist", name);
}
stnode_replace(node, STTYPE_FUNCTION, def);
return node;

View File

@ -79,20 +79,25 @@ DIAG_OFF_FLEX
stnode_t *df_lval;
static int set_lval_simple(int token, const char *token_value, sttype_id_t type_id);
static int set_lval_str(int token, const char *token_value);
static int set_lval_simple(df_scanner_state_t *state, int token, const char *token_value, sttype_id_t type_id);
static int set_lval_str(df_scanner_state_t *state, int token, const char *token_value);
static int set_lval_quoted_string(dfwork_t *dfw, int token, GString *quoted_string);
static int set_lval_charconst(dfwork_t *dfw, int token, GString *quoted_string);
static int set_lval_range_node(dfwork_t *dfw, int token, const char *token_value);
static int set_lval_field(dfwork_t *dfw, int token, const char *token_value);
static int set_lval_quoted_string(df_scanner_state_t *state, int token, GString *quoted_string);
static int set_lval_charconst(df_scanner_state_t *state, int token, GString *quoted_string);
static int set_lval_range_node(df_scanner_state_t *state, int token, const char *token_value);
static int set_lval_field(df_scanner_state_t *state, int token, const char *token_value);
#define simple(token) set_lval_simple(token, yytext, STTYPE_UNINITIALIZED)
#define test(token) set_lval_simple(token, yytext, STTYPE_TEST)
#define math(token) set_lval_simple(token, yytext, STTYPE_ARITHMETIC)
#define simple(token) (update_location(yyextra, yytext), set_lval_simple(yyextra, token, yytext, STTYPE_UNINITIALIZED))
#define test(token) (update_location(yyextra, yytext), set_lval_simple(yyextra, token, yytext, STTYPE_TEST))
#define math(token) (update_location(yyextra, yytext), set_lval_simple(yyextra, token, yytext, STTYPE_ARITHMETIC))
static gboolean append_escaped_char(dfwork_t *dfw, GString *str, char c);
static gboolean parse_charconst(dfwork_t *dfw, const char *s, unsigned long *valuep);
static gboolean append_escaped_char(df_scanner_state_t *state, GString *str, char c);
static gboolean parse_charconst(df_scanner_state_t *state, const char *s, unsigned long *valuep);
static void update_location(df_scanner_state_t *state, const char *text);
static void update_string_loc(df_scanner_state_t *state, const char *text);
#define FAIL(...) dfilter_fail(yyextra->dfw, &yyextra->location, __VA_ARGS__)
/*
* Sleazy hack to suppress compiler warnings in yy_fatal_error().
@ -137,7 +142,9 @@ hyphen-bytes {hex2}(-{hex2})+
%%
[[:blank:]\n]+
[[:blank:]\n]+ {
update_location(yyextra, yytext);
}
"(" return simple(TOKEN_LPAREN);
")" return simple(TOKEN_RPAREN);
@ -193,7 +200,8 @@ hyphen-bytes {hex2}(-{hex2})+
}
<RANGE>[^],]+ {
return set_lval_range_node(yyextra->dfw, TOKEN_RANGE_NODE, yytext);
update_location(yyextra, yytext);
return set_lval_range_node(yyextra, TOKEN_RANGE_NODE, yytext);
}
<RANGE>"," {
@ -206,7 +214,8 @@ hyphen-bytes {hex2}(-{hex2})+
}
<RANGE><<EOF>> {
dfilter_fail(yyextra->dfw, "The right bracket was missing from a slice.");
update_location(yyextra, yytext);
FAIL("The right bracket was missing from a slice.");
return SCAN_FAILED;
}
@ -218,7 +227,10 @@ hyphen-bytes {hex2}(-{hex2})+
* See: https://westes.github.io/flex/manual/Start-Conditions.html
*/
BEGIN(DQUOTE);
yyextra->quoted_string = g_string_new("");
update_location(yyextra, yytext);
yyextra->string_loc = yyextra->location;
yyextra->quoted_string = g_string_new("\"");
if (yytext[0] == 'r' || yytext[0] == 'R') {
/*
@ -239,22 +251,27 @@ hyphen-bytes {hex2}(-{hex2})+
<DQUOTE><<EOF>> {
/* unterminated string */
update_string_loc(yyextra, yytext);
g_string_free(yyextra->quoted_string, TRUE);
yyextra->quoted_string = NULL;
dfilter_fail(yyextra->dfw, "The final quote was missing from a quoted string.");
FAIL("The final quote was missing from a quoted string.");
return SCAN_FAILED;
}
<DQUOTE>\042 {
/* end quote */
BEGIN(INITIAL);
set_lval_quoted_string(yyextra->dfw, TOKEN_STRING, yyextra->quoted_string);
update_string_loc(yyextra, yytext);
g_string_append_c(yyextra->quoted_string, '"');
set_lval_quoted_string(yyextra, TOKEN_STRING, yyextra->quoted_string);
yyextra->quoted_string = NULL;
yyextra->string_loc.col_start = -1;
return TOKEN_STRING;
}
<DQUOTE>\\[0-7]{1,3} {
/* octal sequence */
update_string_loc(yyextra, yytext);
if (yyextra->raw_string) {
g_string_append(yyextra->quoted_string, yytext);
}
@ -264,13 +281,13 @@ hyphen-bytes {hex2}(-{hex2})+
if (result == 0) {
g_string_free(yyextra->quoted_string, TRUE);
yyextra->quoted_string = NULL;
dfilter_fail(yyextra->dfw, "%s (NUL byte) cannot be used with a regular string.", yytext);
FAIL("%s (NUL byte) cannot be used with a regular string.", yytext);
return SCAN_FAILED;
}
if (result > 0xff) {
g_string_free(yyextra->quoted_string, TRUE);
yyextra->quoted_string = NULL;
dfilter_fail(yyextra->dfw, "%s is larger than 255.", yytext);
FAIL("%s is larger than 255.", yytext);
return SCAN_FAILED;
}
g_string_append_c(yyextra->quoted_string, (gchar) result);
@ -283,6 +300,7 @@ hyphen-bytes {hex2}(-{hex2})+
* C standard does not place a limit on the number of hex
* digits after \x... but we do. \xNN can have 1 or two Ns, not more.
*/
update_string_loc(yyextra, yytext);
if (yyextra->raw_string) {
g_string_append(yyextra->quoted_string, yytext);
}
@ -292,7 +310,7 @@ hyphen-bytes {hex2}(-{hex2})+
if (result == 0) {
g_string_free(yyextra->quoted_string, TRUE);
yyextra->quoted_string = NULL;
dfilter_fail(yyextra->dfw, "%s (NUL byte) cannot be used with a regular string.", yytext);
FAIL("%s (NUL byte) cannot be used with a regular string.", yytext);
return SCAN_FAILED;
}
g_string_append_c(yyextra->quoted_string, (gchar) result);
@ -302,10 +320,11 @@ hyphen-bytes {hex2}(-{hex2})+
<DQUOTE>\\. {
/* escaped character */
update_string_loc(yyextra, yytext);
if (yyextra->raw_string) {
g_string_append(yyextra->quoted_string, yytext);
}
else if (!append_escaped_char(yyextra->dfw, yyextra->quoted_string, yytext[1])) {
else if (!append_escaped_char(yyextra, yyextra->quoted_string, yytext[1])) {
g_string_free(yyextra->quoted_string, TRUE);
yyextra->quoted_string = NULL;
return SCAN_FAILED;
@ -314,6 +333,7 @@ hyphen-bytes {hex2}(-{hex2})+
<DQUOTE>[^\\\042]+ {
/* non-escaped string */
update_string_loc(yyextra, yytext);
g_string_append(yyextra->quoted_string, yytext);
}
@ -321,33 +341,41 @@ hyphen-bytes {hex2}(-{hex2})+
\047 {
/* start quote of a quoted character value */
BEGIN(SQUOTE);
update_location(yyextra, yytext);
yyextra->string_loc = yyextra->location;
yyextra->quoted_string = g_string_new("'");
}
<SQUOTE><<EOF>> {
/* unterminated character value */
update_string_loc(yyextra, yytext);
g_string_free(yyextra->quoted_string, TRUE);
yyextra->quoted_string = NULL;
dfilter_fail(yyextra->dfw, "The final quote was missing from a character constant.");
FAIL("The final quote was missing from a character constant.");
return SCAN_FAILED;
}
<SQUOTE>\047 {
/* end quote */
BEGIN(INITIAL);
update_string_loc(yyextra, yytext);
g_string_append_c(yyextra->quoted_string, '\'');
set_lval_charconst(yyextra->dfw, TOKEN_CHARCONST, yyextra->quoted_string);
set_lval_charconst(yyextra, TOKEN_CHARCONST, yyextra->quoted_string);
yyextra->quoted_string = NULL;
yyextra->string_loc.col_start = -1;
return TOKEN_CHARCONST;
}
<SQUOTE>\\. {
/* escaped character */
update_string_loc(yyextra, yytext);
g_string_append(yyextra->quoted_string, yytext);
}
<SQUOTE>[^\\\047]+ {
/* non-escaped string */
update_string_loc(yyextra, yytext);
g_string_append(yyextra->quoted_string, yytext);
}
@ -356,60 +384,68 @@ hyphen-bytes {hex2}(-{hex2})+
{MacAddress}|{QuadMacAddress} {
/* MAC Address. */
return set_lval_str(TOKEN_UNPARSED, yytext);
update_location(yyextra, yytext);
return set_lval_str(yyextra, TOKEN_UNPARSED, yytext);
}
{IPv4address}{v4-cidr-prefix}? {
/* IPv4 with or without prefix. */
return set_lval_str(TOKEN_UNPARSED, yytext);
update_location(yyextra, yytext);
return set_lval_str(yyextra, TOKEN_UNPARSED, yytext);
}
{IPv6address}{v6-cidr-prefix}? {
/* IPv6 with or without prefix. */
return set_lval_str(TOKEN_UNPARSED, yytext);
update_location(yyextra, yytext);
return set_lval_str(yyextra, TOKEN_UNPARSED, yytext);
}
:?({colon-bytes}|{dot-bytes}|{hyphen-bytes}) {
/* Bytes. */
update_location(yyextra, yytext);
if (yytext[0] == ':')
return set_lval_str(TOKEN_LITERAL, yytext); /* Keep leading colon. */
return set_lval_str(TOKEN_UNPARSED, yytext);
return set_lval_str(yyextra, TOKEN_LITERAL, yytext); /* Keep leading colon. */
return set_lval_str(yyextra, TOKEN_UNPARSED, yytext);
}
:[[:xdigit:]]+ {
/* Numeric. */
return set_lval_str(TOKEN_LITERAL, yytext + 1); /* Skip leading colon. */
update_location(yyextra, yytext);
return set_lval_str(yyextra, TOKEN_LITERAL, yytext + 1); /* Skip leading colon. */
}
"<"[^>=]+">" {
/* Literal in-between angle brackets (cannot be parsed as a protocol field). */
/* Strip brackets. */
update_location(yyextra, yytext);
char *end = strchr(yytext, '>');
*end = '\0';
return set_lval_str(TOKEN_LITERAL, yytext + 1);
return set_lval_str(yyextra, TOKEN_LITERAL, yytext + 1);
}
\.?{Identifier} {
/* Identifier or unparsed. */
update_location(yyextra, yytext);
if (yytext[0] == '.') {
/* Skip leading dot. */
return set_lval_field(yyextra->dfw, TOKEN_FIELD, yytext + 1);
return set_lval_field(yyextra, TOKEN_FIELD, yytext + 1);
}
return set_lval_str(TOKEN_UNPARSED, yytext);
return set_lval_str(yyextra, TOKEN_UNPARSED, yytext);
}
"${"{Identifier}"}" {
char *end = strchr(yytext, '}');
*end = '\0';
return set_lval_field(yyextra->dfw, TOKEN_REFERENCE, yytext + 2);
return set_lval_field(yyextra, TOKEN_REFERENCE, yytext + 2);
}
. {
/* Default */
update_location(yyextra, yytext);
if (isprint_string(yytext))
dfilter_fail(yyextra->dfw, "\"%s\" was unexpected in this context.", yytext);
FAIL("\"%s\" was unexpected in this context.", yytext);
else
dfilter_fail(yyextra->dfw, "Non-printable ASCII characters may only appear inside double-quotes.");
FAIL("Non-printable ASCII characters may only appear inside double-quotes.");
return SCAN_FAILED;
}
@ -421,15 +457,36 @@ hyphen-bytes {hex2}(-{hex2})+
*/
DIAG_ON_FLEX
static int
set_lval_simple(int token, const char *token_value, sttype_id_t type_id)
static void
_update_location(df_scanner_state_t *state, size_t len)
{
stnode_init(df_lval, type_id, NULL, g_strdup(token_value));
state->location.col_start += state->location.col_len;
state->location.col_len = len;
}
static void
update_location(df_scanner_state_t *state, const char *text)
{
_update_location(state, strlen(text));
}
static void
update_string_loc(df_scanner_state_t *state, const char *text)
{
size_t len = strlen(text);
state->string_loc.col_len += len;
_update_location(state, len);
}
static int
set_lval_simple(df_scanner_state_t *state, int token, const char *token_value, sttype_id_t type_id)
{
stnode_init(df_lval, type_id, NULL, g_strdup(token_value), &state->location);
return token;
}
static int
set_lval_str(int token, const char *token_value)
set_lval_str(df_scanner_state_t *state, int token, const char *token_value)
{
sttype_id_t type_id;
@ -443,37 +500,42 @@ set_lval_str(int token, const char *token_value)
default:
ws_assert_not_reached();
}
stnode_init(df_lval, type_id, g_strdup(token_value), g_strdup(token_value));
stnode_init(df_lval, type_id, g_strdup(token_value), g_strdup(token_value), &state->location);
return token;
}
static int
set_lval_quoted_string(dfwork_t *dfw _U_, int token, GString *quoted_string)
set_lval_quoted_string(df_scanner_state_t *state, int token, GString *quoted_string)
{
ws_assert(token == TOKEN_STRING);
char *token_value = g_string_free(quoted_string, FALSE);
stnode_init(df_lval, STTYPE_STRING, g_string_free(quoted_string, FALSE), NULL);
/* Strip start and end quote. */
char *data = g_strndup(token_value + 1, strlen(token_value + 1) - 1);
stnode_init(df_lval, STTYPE_STRING, data, token_value, &state->string_loc);
return token;
}
static int
set_lval_charconst(dfwork_t *dfw, int token, GString *quoted_string)
set_lval_charconst(df_scanner_state_t *state, int token, GString *quoted_string)
{
ws_assert(token == TOKEN_CHARCONST);
unsigned long number;
gboolean ok;
ok = parse_charconst(dfw, quoted_string->str, &number);
g_string_free(quoted_string, TRUE);
char *token_value = g_string_free(quoted_string, FALSE);
ok = parse_charconst(state, token_value, &number);
if (!ok) {
g_free(token_value);
return SCAN_FAILED;
}
stnode_init(df_lval, STTYPE_CHARCONST, g_memdup2(&number, sizeof(number)), NULL);
stnode_init(df_lval, STTYPE_CHARCONST, g_memdup2(&number, sizeof(number)), token_value, &state->string_loc);
return token;
}
static int
set_lval_field(dfwork_t *dfw, int token, const char *token_value)
set_lval_field(df_scanner_state_t *state, int token, const char *token_value)
{
sttype_id_t type_id;
header_field_info *hfinfo;
@ -489,16 +551,16 @@ set_lval_field(dfwork_t *dfw, int token, const char *token_value)
ws_assert_not_reached();
}
hfinfo = dfilter_resolve_unparsed(dfw, token_value);
hfinfo = dfilter_resolve_unparsed(state->dfw, token_value);
if (hfinfo == NULL) {
dfilter_fail(dfw, "\"%s\" is not a valid protocol or protocol field.", token_value);
dfilter_fail(state->dfw, &state->location, "\"%s\" is not a valid protocol or protocol field.", token_value);
}
stnode_init(df_lval, type_id, hfinfo, g_strdup(token_value));
stnode_init(df_lval, type_id, hfinfo, g_strdup(token_value), &state->location);
return token;
}
static int
set_lval_range_node(dfwork_t *dfw, int token, const char *token_value)
set_lval_range_node(df_scanner_state_t *state, int token, const char *token_value)
{
ws_assert(token == TOKEN_RANGE_NODE);
char *err = NULL;
@ -506,16 +568,16 @@ set_lval_range_node(dfwork_t *dfw, int token, const char *token_value)
range = drange_node_from_str(token_value, &err);
if (err != NULL) {
dfilter_fail(dfw, "%s", err);
dfilter_fail(state->dfw, &state->location, "%s", err);
g_free(err);
return SCAN_FAILED;
}
stnode_init(df_lval, STTYPE_RANGE_NODE, range, NULL);
stnode_init(df_lval, STTYPE_RANGE_NODE, range, g_strdup(token_value), &state->location);
return token;
}
static gboolean
append_escaped_char(dfwork_t *dfw, GString *str, char c)
append_escaped_char(df_scanner_state_t *state, GString *str, char c)
{
switch (c) {
case 'a':
@ -544,7 +606,8 @@ append_escaped_char(dfwork_t *dfw, GString *str, char c)
case '\"':
break;
default:
dfilter_fail(dfw, "\\%c is not a valid character escape sequence", c);
dfilter_fail(state->dfw, &state->location,
"\\%c is not a valid character escape sequence", c);
return FALSE;
}
@ -553,14 +616,14 @@ append_escaped_char(dfwork_t *dfw, GString *str, char c)
}
static gboolean
parse_charconst(dfwork_t *dfw, const char *s, unsigned long *valuep)
parse_charconst(df_scanner_state_t *state, const char *s, unsigned long *valuep)
{
const char *cp;
unsigned long value;
cp = s + 1; /* skip the leading ' */
if (*cp == '\'') {
dfilter_fail(dfw, "Empty character constant.");
dfilter_fail(state->dfw, &state->string_loc, "Empty character constant.");
return FALSE;
}
@ -576,7 +639,7 @@ parse_charconst(dfwork_t *dfw, const char *s, unsigned long *valuep)
switch (*cp) {
case '\0':
dfilter_fail(dfw, "%s isn't a valid character constant.", s);
dfilter_fail(state->dfw, &state->string_loc, "%s isn't a valid character constant.", s);
return FALSE;
case 'a':
@ -628,7 +691,7 @@ parse_charconst(dfwork_t *dfw, const char *s, unsigned long *valuep)
else if (*cp >= 'a' && *cp <= 'f')
value = 10 + (*cp - 'a');
else {
dfilter_fail(dfw, "%s isn't a valid character constant.", s);
dfilter_fail(state->dfw, &state->string_loc, "%s isn't a valid character constant.", s);
return FALSE;
}
cp++;
@ -641,7 +704,7 @@ parse_charconst(dfwork_t *dfw, const char *s, unsigned long *valuep)
else if (*cp >= 'a' && *cp <= 'f')
value |= 10 + (*cp - 'a');
else {
dfilter_fail(dfw, "%s isn't a valid character constant.", s);
dfilter_fail(state->dfw, &state->string_loc, "%s isn't a valid character constant.", s);
return FALSE;
}
}
@ -652,7 +715,7 @@ parse_charconst(dfwork_t *dfw, const char *s, unsigned long *valuep)
if (*cp >= '0' && *cp <= '7')
value = *cp - '0';
else {
dfilter_fail(dfw, "%s isn't a valid character constant.", s);
dfilter_fail(state->dfw, &state->string_loc, "%s isn't a valid character constant.", s);
return FALSE;
}
if (*(cp + 1) != '\'') {
@ -661,7 +724,7 @@ parse_charconst(dfwork_t *dfw, const char *s, unsigned long *valuep)
if (*cp >= '0' && *cp <= '7')
value |= *cp - '0';
else {
dfilter_fail(dfw, "%s isn't a valid character constant.", s);
dfilter_fail(state->dfw, &state->string_loc, "%s isn't a valid character constant.", s);
return FALSE;
}
if (*(cp + 1) != '\'') {
@ -670,26 +733,26 @@ parse_charconst(dfwork_t *dfw, const char *s, unsigned long *valuep)
if (*cp >= '0' && *cp <= '7')
value |= *cp - '0';
else {
dfilter_fail(dfw, "%s isn't a valid character constant.", s);
dfilter_fail(state->dfw, &state->string_loc, "%s isn't a valid character constant.", s);
return FALSE;
}
}
}
if (value > 0xFF) {
dfilter_fail(dfw, "%s is too large to be a valid character constant.", s);
dfilter_fail(state->dfw, &state->string_loc, "%s is too large to be a valid character constant.", s);
return FALSE;
}
}
} else {
value = *cp;
if (!g_ascii_isprint(value)) {
dfilter_fail(dfw, "Non-printable value '0x%02lx' in character constant.", value);
dfilter_fail(state->dfw, &state->string_loc, "Non-printable value '0x%02lx' in character constant.", value);
return FALSE;
}
}
cp++;
if ((*cp != '\'') || (*(cp + 1) != '\0')){
dfilter_fail(dfw, "%s is too long to be a valid character constant.", s);
dfilter_fail(state->dfw, &state->string_loc, "%s is too long to be a valid character constant.", s);
return FALSE;
}

View File

@ -29,10 +29,11 @@
#include <ftypes/ftypes.h>
#define FAIL(dfw, ...) \
#define FAIL(dfw, node, ...) \
do { \
ws_noisy("Semantic check failed here."); \
dfilter_fail_throw(dfw, TypeError, __VA_ARGS__); \
dfilter_fail_throw(dfw, stnode_location(node), \
TypeError, __VA_ARGS__); \
} while (0)
static void
@ -181,8 +182,11 @@ dfilter_fvalue_from_literal(dfwork_t *dfw, ftenum_t ftype, stnode_t *st,
dfw->error_message = NULL;
}
}
if (fv == NULL)
if (fv == NULL) {
dfw_set_error_location(dfw, stnode_location(st));
THROW(TypeError);
}
return fv;
}
@ -222,6 +226,7 @@ dfilter_fvalue_from_unparsed(dfwork_t *dfw, ftenum_t ftype, stnode_t *st,
if (hfinfo == NULL) {
/* This node is neither a valid fvalue nor a valid field. */
/* The parse failed. Error message is already set. */
dfw_set_error_location(dfw, stnode_location(st));
THROW(TypeError);
}
@ -258,8 +263,11 @@ dfilter_fvalue_from_string(dfwork_t *dfw, ftenum_t ftype, stnode_t *st,
dfw->error_message = NULL;
}
}
if (fv == NULL)
if (fv == NULL) {
dfw_set_error_location(dfw, stnode_location(st));
THROW(TypeError);
}
return fv;
}
@ -386,7 +394,7 @@ mk_fvalue_from_val_string(dfwork_t *dfw, header_field_info *hfinfo, const char *
*/
g_free(dfw->error_message);
dfw->error_message = NULL;
dfilter_fail(dfw, "\"%s\" cannot be found among the possible values for %s.",
dfilter_fail(dfw, NULL, "\"%s\" cannot be found among the possible values for %s.",
s, hfinfo->abbrev);
return NULL;
}
@ -394,7 +402,7 @@ mk_fvalue_from_val_string(dfwork_t *dfw, header_field_info *hfinfo, const char *
/* Do val_strings exist? */
if (!hfinfo->strings) {
dfilter_fail(dfw, "%s cannot accept strings as values.",
dfilter_fail(dfw, NULL, "%s cannot accept strings as values.",
hfinfo->abbrev);
return NULL;
}
@ -406,7 +414,7 @@ mk_fvalue_from_val_string(dfwork_t *dfw, header_field_info *hfinfo, const char *
dfw->error_message = NULL;
if (hfinfo->display & BASE_RANGE_STRING) {
dfilter_fail(dfw, "\"%s\" cannot accept [range] strings as values.",
dfilter_fail(dfw, NULL, "\"%s\" cannot accept [range] strings as values.",
hfinfo->abbrev);
}
else if (hfinfo->display & BASE_VAL64_STRING) {
@ -418,7 +426,7 @@ mk_fvalue_from_val_string(dfwork_t *dfw, header_field_info *hfinfo, const char *
}
vals++;
}
dfilter_fail(dfw, "\"%s\" cannot be found among the possible values for %s.",
dfilter_fail(dfw, NULL, "\"%s\" cannot be found among the possible values for %s.",
s, hfinfo->abbrev);
}
else if (hfinfo->display == BASE_CUSTOM) {
@ -428,7 +436,7 @@ mk_fvalue_from_val_string(dfwork_t *dfw, header_field_info *hfinfo, const char *
* integer, we have the string they're trying to match.
* -><-
*/
dfilter_fail(dfw, "\"%s\" cannot accept [custom] strings as values.",
dfilter_fail(dfw, NULL, "\"%s\" cannot accept [custom] strings as values.",
hfinfo->abbrev);
}
else {
@ -442,7 +450,7 @@ mk_fvalue_from_val_string(dfwork_t *dfw, header_field_info *hfinfo, const char *
}
vals++;
}
dfilter_fail(dfw, "\"%s\" cannot be found among the possible values for %s.",
dfilter_fail(dfw, NULL, "\"%s\" cannot be found among the possible values for %s.",
s, hfinfo->abbrev);
}
return NULL;
@ -527,7 +535,7 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
case STTYPE_STRING:
case STTYPE_LITERAL:
case STTYPE_CHARCONST:
FAIL(dfw, "%s is neither a field nor a protocol name.",
FAIL(dfw, st_arg1, "%s is neither a field nor a protocol name.",
stnode_todisplay(st_arg1));
break;
@ -538,13 +546,13 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
* has at least 2 bytes starting at an offset of
* 3"?
*/
FAIL(dfw, "You cannot test whether a range is present.");
FAIL(dfw, st_arg1, "You cannot test whether a range is present.");
break;
case STTYPE_FUNCTION:
/* XXX - Maybe we should change functions so they can return fields,
* in which case the 'exist' should be fine. */
FAIL(dfw, "You cannot test whether a function is present.");
FAIL(dfw, st_arg1, "You cannot test whether a function is present.");
break;
case STTYPE_SET:
@ -577,7 +585,7 @@ check_drange_sanity(dfwork_t *dfw, stnode_t *st)
ftype1 = hfinfo1->type;
if (!ftype_can_slice(ftype1)) {
FAIL(dfw, "\"%s\" is a %s and cannot be sliced into a sequence of bytes.",
FAIL(dfw, entity1, "\"%s\" is a %s and cannot be sliced into a sequence of bytes.",
hfinfo1->abbrev, ftype_pretty_name(ftype1));
}
} else if (stnode_type_id(entity1) == STTYPE_FUNCTION) {
@ -585,7 +593,7 @@ check_drange_sanity(dfwork_t *dfw, stnode_t *st)
ftype1 = funcdef->retval_ftype;
if (!ftype_can_slice(ftype1)) {
FAIL(dfw, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
FAIL(dfw, entity1, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
funcdef->name, ftype_pretty_name(ftype1));
}
@ -594,7 +602,7 @@ check_drange_sanity(dfwork_t *dfw, stnode_t *st)
/* Should this be rejected instead? */
check_drange_sanity(dfw, entity1);
} else {
FAIL(dfw, "Range is not supported for entity %s",
FAIL(dfw, entity1, "Range is not supported for entity %s",
stnode_todisplay(entity1));
}
}
@ -629,10 +637,10 @@ check_function(dfwork_t *dfw, stnode_t *st_node)
nparams = g_slist_length(params);
if (nparams < funcdef->min_nargs) {
FAIL(dfw, "Function %s needs at least %u arguments.",
FAIL(dfw, st_node, "Function %s needs at least %u arguments.",
funcdef->name, funcdef->min_nargs);
} else if (nparams > funcdef->max_nargs) {
FAIL(dfw, "Function %s can only accept %u arguments.",
FAIL(dfw, st_node, "Function %s can only accept %u arguments.",
funcdef->name, funcdef->max_nargs);
}
@ -654,8 +662,11 @@ dfilter_fvalue_from_charconst(dfwork_t *dfw, ftenum_t ftype, stnode_t *st)
fvalue = fvalue_from_charconst(ftype, *nump,
dfw->error_message == NULL ? &dfw->error_message : NULL);
if (fvalue == NULL)
if (fvalue == NULL) {
dfw_set_error_location(dfw, stnode_location(st));
THROW(TypeError);
}
return fvalue;
}
@ -683,7 +694,7 @@ again:
ftype1 = hfinfo1->type;
if (!can_func(ftype1)) {
FAIL(dfw, "%s (type=%s) cannot participate in %s comparison.",
FAIL(dfw, st_arg1, "%s (type=%s) cannot participate in %s comparison.",
hfinfo1->abbrev, ftype_pretty_name(ftype1),
stnode_todisplay(st_node));
}
@ -693,13 +704,13 @@ again:
ftype2 = hfinfo2->type;
if (!compatible_ftypes(ftype1, ftype2)) {
FAIL(dfw, "%s and %s are not of compatible types.",
FAIL(dfw, st_arg2, "%s and %s are not of compatible types.",
hfinfo1->abbrev, hfinfo2->abbrev);
}
/* Do this check even though you'd think that if
* they're compatible, then can_func() would pass. */
if (!can_func(ftype2)) {
FAIL(dfw, "%s (type=%s) cannot participate in specified comparison.",
FAIL(dfw, st_arg2, "%s (type=%s) cannot participate in specified comparison.",
hfinfo2->abbrev, ftype_pretty_name(ftype2));
}
}
@ -735,7 +746,7 @@ again:
check_drange_sanity(dfw, st_arg2);
if (!is_bytes_type(ftype1)) {
if (!ftype_can_slice(ftype1)) {
FAIL(dfw, "\"%s\" is a %s and cannot be converted into a sequence of bytes.",
FAIL(dfw, st_arg1, "\"%s\" is a %s and cannot be converted into a sequence of bytes.",
hfinfo1->abbrev,
ftype_pretty_name(ftype1));
}
@ -749,13 +760,13 @@ again:
ftype2 = funcdef->retval_ftype;
if (!compatible_ftypes(ftype1, ftype2)) {
FAIL(dfw, "%s (type=%s) and return value of %s() (type=%s) are not of compatible types.",
FAIL(dfw, st_arg2, "%s (type=%s) and return value of %s() (type=%s) are not of compatible types.",
hfinfo1->abbrev, ftype_pretty_name(ftype1),
funcdef->name, ftype_pretty_name(ftype2));
}
if (!can_func(ftype2)) {
FAIL(dfw, "return value of %s() (type=%s) cannot participate in specified comparison.",
FAIL(dfw, st_arg2, "return value of %s() (type=%s) cannot participate in specified comparison.",
funcdef->name, ftype_pretty_name(ftype2));
}
@ -768,12 +779,12 @@ again:
ftype2 = check_arithmetic_expr(dfw, st_arg2, ftype1);
if (!compatible_ftypes(ftype1, ftype2)) {
FAIL(dfw, "%s and %s are not of compatible types.",
FAIL(dfw, st_arg2, "%s and %s are not of compatible types.",
stnode_todisplay(st_arg1), stnode_todisplay(st_arg2));
}
if (!can_func(ftype2)) {
FAIL(dfw, "%s (type=%s) cannot participate in specified comparison.",
FAIL(dfw, st_arg2, "%s (type=%s) cannot participate in specified comparison.",
stnode_todisplay(st_arg2), ftype_pretty_name(ftype2));
}
}
@ -807,7 +818,7 @@ again:
if (!is_bytes_type(ftype2)) {
if (!ftype_can_slice(ftype2)) {
FAIL(dfw, "\"%s\" is a %s and cannot be converted into a sequence of bytes.",
FAIL(dfw, st_arg2, "\"%s\" is a %s and cannot be converted into a sequence of bytes.",
hfinfo2->abbrev,
ftype_pretty_name(ftype2));
}
@ -845,7 +856,7 @@ again:
if (!is_bytes_type(ftype2)) {
if (!ftype_can_slice(ftype2)) {
FAIL(dfw, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
FAIL(dfw, st_arg2, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
funcdef->name,
ftype_pretty_name(ftype2));
}
@ -863,12 +874,12 @@ again:
ftype2 = check_arithmetic_expr(dfw, st_arg2, FT_BYTES);
if (!compatible_ftypes(FT_BYTES, ftype2)) {
FAIL(dfw, "%s and %s are not of compatible types.",
FAIL(dfw, st_arg2, "%s and %s are not of compatible types.",
stnode_todisplay(st_arg1), stnode_todisplay(st_arg2));
}
if (!can_func(ftype2)) {
FAIL(dfw, "%s (type=%s) cannot participate in specified comparison.",
FAIL(dfw, st_arg2, "%s (type=%s) cannot participate in specified comparison.",
stnode_todisplay(st_arg2), ftype_pretty_name(ftype2));
}
}
@ -900,7 +911,7 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, test_op_t st_op,
ftype1 = funcdef->retval_ftype;
if (!can_func(ftype1)) {
FAIL(dfw, "Function %s (type=%s) cannot participate in %s comparison.",
FAIL(dfw, st_arg1, "Function %s (type=%s) cannot participate in %s comparison.",
funcdef->name, ftype_pretty_name(ftype1),
stnode_todisplay(st_node));
}
@ -913,13 +924,13 @@ again:
ftype2 = hfinfo2->type;
if (!compatible_ftypes(ftype1, ftype2)) {
FAIL(dfw, "Function %s and %s are not of compatible types.",
FAIL(dfw, st_arg2, "Function %s and %s are not of compatible types.",
funcdef->name, hfinfo2->abbrev);
}
/* Do this check even though you'd think that if
* they're compatible, then can_func() would pass. */
if (!can_func(ftype2)) {
FAIL(dfw, "%s (type=%s) cannot participate in specified comparison.",
FAIL(dfw, st_arg2, "%s (type=%s) cannot participate in specified comparison.",
hfinfo2->abbrev, ftype_pretty_name(ftype2));
}
}
@ -947,7 +958,7 @@ again:
check_drange_sanity(dfw, st_arg2);
if (!is_bytes_type(ftype1)) {
if (!ftype_can_slice(ftype1)) {
FAIL(dfw, "Function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
FAIL(dfw, st_arg1, "Function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
funcdef->name,
ftype_pretty_name(ftype1));
}
@ -961,14 +972,14 @@ again:
ftype2 = funcdef2->retval_ftype;
if (!compatible_ftypes(ftype1, ftype2)) {
FAIL(dfw, "Return values of function %s (type=%s) and function %s (type=%s) are not of compatible types.",
FAIL(dfw, st_arg2, "Return values of function %s (type=%s) and function %s (type=%s) are not of compatible types.",
funcdef->name, ftype_pretty_name(ftype1), funcdef2->name, ftype_pretty_name(ftype2));
}
/* Do this check even though you'd think that if
* they're compatible, then can_func() would pass. */
if (!can_func(ftype2)) {
FAIL(dfw, "Return value of %s (type=%s) cannot participate in specified comparison.",
FAIL(dfw, st_arg2, "Return value of %s (type=%s) cannot participate in specified comparison.",
funcdef2->name, ftype_pretty_name(ftype2));
}
@ -981,12 +992,12 @@ again:
ftype2 = check_arithmetic_expr(dfw, st_arg2, ftype1);
if (!compatible_ftypes(ftype1, ftype2)) {
FAIL(dfw, "%s and %s are not of compatible types.",
FAIL(dfw, st_arg2, "%s and %s are not of compatible types.",
stnode_todisplay(st_arg1), stnode_todisplay(st_arg2));
}
if (!can_func(ftype2)) {
FAIL(dfw, "%s (type=%s) cannot participate in specified comparison.",
FAIL(dfw, st_arg2, "%s (type=%s) cannot participate in specified comparison.",
stnode_todisplay(st_arg2), ftype_pretty_name(ftype2));
}
}
@ -1056,7 +1067,7 @@ check_relation(dfwork_t *dfw, test_op_t st_op,
allow_partial_value, st_node, st_arg1, st_arg2);
break;
default:
FAIL(dfw, "Left side of %s expression must be a field or function, not %s.",
FAIL(dfw, st_arg1, "Left side of %s expression must be a field or function, not %s.",
stnode_todisplay(st_node), stnode_todisplay(st_arg1));
}
}
@ -1084,7 +1095,7 @@ check_relation_contains(dfwork_t *dfw, stnode_t *st_node,
TRUE, st_node, st_arg1, st_arg2);
break;
default:
FAIL(dfw, "Left side of %s expression must be a field or function, not %s.",
FAIL(dfw, st_arg1, "Left side of %s expression must be a field or function, not %s.",
stnode_todisplay(st_node), stnode_todisplay(st_arg1));
}
}
@ -1103,7 +1114,7 @@ check_relation_matches(dfwork_t *dfw, stnode_t *st_node,
resolve_unparsed(dfw, st_arg1);
if (stnode_type_id(st_arg2) != STTYPE_STRING) {
FAIL(dfw, "Matches requires a double quoted string on the right side.");
FAIL(dfw, st_arg2, "Matches requires a double quoted string on the right side.");
}
patt = stnode_data(st_arg2);
@ -1111,7 +1122,7 @@ check_relation_matches(dfwork_t *dfw, stnode_t *st_node,
pcre = ws_regex_compile(patt, &errmsg);
if (errmsg) {
dfilter_fail(dfw, "Regex compilation error: %s.", errmsg);
dfilter_fail(dfw, NULL, "Regex compilation error: %s.", errmsg);
g_free(errmsg);
THROW(TypeError);
}
@ -1133,7 +1144,7 @@ check_relation_matches(dfwork_t *dfw, stnode_t *st_node,
TRUE, st_node, st_arg1, st_arg2);
break;
default:
FAIL(dfw, "Left side of %s expression must be a field or function, not %s.",
FAIL(dfw, st_arg1, "Left side of %s expression must be a field or function, not %s.",
stnode_todisplay(st_node), stnode_todisplay(st_arg1));
}
}
@ -1150,7 +1161,7 @@ check_relation_in(dfwork_t *dfw, stnode_t *st_node _U_,
resolve_unparsed(dfw, st_arg1);
if (stnode_type_id(st_arg1) != STTYPE_FIELD) {
FAIL(dfw, "Only a field may be tested for membership in a set.");
FAIL(dfw, st_arg1, "Only a field may be tested for membership in a set.");
}
/* Checked in the grammar parser. */
ws_assert(stnode_type_id(st_arg2) == STTYPE_SET);
@ -1165,7 +1176,7 @@ check_relation_in(dfwork_t *dfw, stnode_t *st_node _U_,
/* Don't let a range on the RHS affect the LHS field. */
if (stnode_type_id(node_left) == STTYPE_RANGE) {
FAIL(dfw, "A range may not appear inside a set.");
FAIL(dfw, node_left, "A range may not appear inside a set.");
break;
}
@ -1279,7 +1290,7 @@ check_arithmetic_entity(dfwork_t *dfw, stnode_t *st_arg, ftenum_t lhs_ftype)
ftype = fvalue_type_ftenum(stnode_data(st_arg));
}
else {
FAIL(dfw, "%s is not a valid arithmetic operand",
FAIL(dfw, st_arg, "%s is not a valid arithmetic operand.",
stnode_todisplay(st_arg));
}
@ -1305,7 +1316,7 @@ check_arithmetic_expr(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype)
/* On the LHS we require a field-like value as the first term. */
if (lhs_ftype == FT_NONE && node_is_constant(st_arg1)) {
FAIL(dfw, "Constant arithmetic expression on the LHS is invalid.");
FAIL(dfw, st_arg1, "Constant arithmetic expression on the LHS is invalid.");
}
if (st_op == OP_UNARY_MINUS) {
@ -1315,7 +1326,8 @@ check_arithmetic_expr(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype)
char *err_msg;
fvalue_t *new_fv = fvalue_unary_minus(stnode_data(st_arg1), &err_msg);
if (new_fv == NULL) {
dfilter_fail(dfw, "%s: %s", stnode_todisplay(st_arg1), err_msg);
dfilter_fail(dfw, stnode_location(st_arg1),
"%s: %s", stnode_todisplay(st_arg1), err_msg);
g_free(err_msg);
THROW(TypeError);
}
@ -1352,16 +1364,16 @@ check_arithmetic_expr(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype)
}
if (!can_func(ftype1)) {
FAIL(dfw, "%s cannot %s.",
FAIL(dfw, st_arg1, "%s cannot %s.",
ftype_name(ftype1), stnode_todisplay(st_node));
}
if (!can_func(ftype2)) {
FAIL(dfw, "%s cannot %s.",
FAIL(dfw, st_arg2, "%s cannot %s.",
ftype_name(ftype2), stnode_todisplay(st_node));
}
if (!compatible_ftypes(ftype1, ftype2)) {
FAIL(dfw, "%s and %s are not type compatible.",
FAIL(dfw, st_arg2, "%s and %s are not type compatible.",
stnode_todisplay(st_arg1), stnode_todisplay(st_arg2));
}

View File

@ -95,10 +95,12 @@ stnode_clear(stnode_t *node)
node->repr_debug = NULL;
g_free(node->repr_token);
node->repr_token = NULL;
node->location.col_start = -1;
node->location.col_len = 0;
}
void
stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data, char *token)
stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data, char *token, stloc_t *loc)
{
sttype_t *type;
@ -108,6 +110,13 @@ stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data, char *token)
node->repr_display = NULL;
node->repr_debug = NULL;
node->repr_token = token;
if (loc) {
node->location = *loc;
}
else {
node->location.col_start = -1;
node->location.col_len = 0;
}
if (type_id == STTYPE_UNINITIALIZED) {
node->type = NULL;
@ -131,69 +140,25 @@ stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data, char *token)
void
stnode_replace(stnode_t *node, sttype_id_t type_id, gpointer data)
{
char *repr_token = g_strdup(node->repr_token);
char *token = g_strdup(node->repr_token);
stloc_t loc = node->location;
stnode_clear(node);
stnode_init(node, type_id, data, NULL);
node->repr_token = repr_token;
stnode_init(node, type_id, data, token, &loc);
}
stnode_t*
stnode_new(sttype_id_t type_id, gpointer data, char *token)
stnode_new(sttype_id_t type_id, gpointer data, char *token, stloc_t *loc)
{
stnode_t *node;
node = g_new0(stnode_t, 1);
node->magic = STNODE_MAGIC;
stnode_init(node, type_id, data, token);
stnode_init(node, type_id, data, token, loc);
return node;
}
stnode_t *
stnode_new_test(test_op_t op, char *token)
{
stnode_t *node;
node = stnode_new(STTYPE_TEST, NULL, token);
sttype_test_set_op(node, op);
return node;
}
stnode_t *
stnode_new_math(test_op_t op, char *token)
{
stnode_t *node;
node = stnode_new(STTYPE_ARITHMETIC, NULL, token);
sttype_test_set_op(node, op);
return node;
}
stnode_t *
stnode_new_string(const char *str, char *token)
{
return stnode_new(STTYPE_STRING, g_strdup(str), token);
}
stnode_t *
stnode_new_unparsed(const char *str, char *token)
{
return stnode_new(STTYPE_UNPARSED, g_strdup(str), token);
}
stnode_t *
stnode_new_literal(const char *str, char *token)
{
return stnode_new(STTYPE_LITERAL, g_strdup(str), token);
}
stnode_t *
stnode_new_charconst(unsigned long number, char *token)
{
return stnode_new(STTYPE_CHARCONST, g_memdup2(&number, sizeof(number)), token);
}
stnode_t*
stnode_dup(const stnode_t *node)
{
@ -205,6 +170,7 @@ stnode_dup(const stnode_t *node)
new->repr_display = NULL;
new->repr_debug = NULL;
new->repr_token = g_strdup(node->repr_token);
new->location = node->location;
new->type = node->type;
if (node->type == NULL)
@ -268,6 +234,12 @@ stnode_token(stnode_t *node)
return node->repr_token;
}
stloc_t *
stnode_location(stnode_t *node)
{
return &node->location;
}
static char *
_node_tostr(stnode_t *node, gboolean pretty)
{

View File

@ -79,6 +79,11 @@ typedef struct {
STTypeToStrFunc func_tostr;
} sttype_t;
typedef struct {
int col_start;
size_t col_len;
} stloc_t;
/** Node (type instance) information */
typedef struct {
uint32_t magic;
@ -87,6 +92,7 @@ typedef struct {
char *repr_token;
char *repr_display;
char *repr_debug;
stloc_t location;
} stnode_t;
/* These are the sttype_t registration function prototypes. */
@ -108,25 +114,7 @@ void
sttype_register(sttype_t *type);
stnode_t*
stnode_new(sttype_id_t type_id, gpointer data, char *token);
stnode_t *
stnode_new_test(test_op_t op, char *token);
stnode_t *
stnode_new_math(test_op_t op, char *token);
stnode_t *
stnode_new_string(const char *str, char *token);
stnode_t *
stnode_new_unparsed(const char *str, char *token);
stnode_t *
stnode_new_literal(const char *str, char *token);
stnode_t *
stnode_new_charconst(unsigned long number, char *token);
stnode_new(sttype_id_t type_id, gpointer data, char *token, stloc_t *loc);
stnode_t*
stnode_dup(const stnode_t *org);
@ -135,7 +123,7 @@ void
stnode_clear(stnode_t *node);
void
stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data, char *token);
stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data, char *token, stloc_t *loc);
void
stnode_replace(stnode_t *node, sttype_id_t type_id, gpointer data);
@ -158,6 +146,9 @@ stnode_steal_data(stnode_t *node);
const char *
stnode_token(stnode_t *node);
stloc_t *
stnode_location(stnode_t *node);
const char *
stnode_tostr(stnode_t *node, gboolean pretty);

View File

@ -276,6 +276,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
dfilter_compile_real@Base 3.7.0
dfilter_deprecated_tokens@Base 1.9.1
dfilter_dump@Base 1.9.1
dfilter_expand@Base 3.7.0
dfilter_free@Base 1.9.1
dfilter_load_field_references@Base 3.7.0
dfilter_log_full@Base 3.7.0