diff --git a/dftest.c b/dftest.c index 3d6b66728e..6a495e9b82 100644 --- a/dftest.c +++ b/dftest.c @@ -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); } diff --git a/epan/dfilter/dfilter-int.h b/epan/dfilter/dfilter-int.h index 346f6f6804..dc50f6a75a 100644 --- a/epan/dfilter/dfilter-int.h +++ b/epan/dfilter/dfilter-int.h @@ -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); diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c index 266bc1c9ae..77068a1a77 100644 --- a/epan/dfilter/dfilter.c +++ b/epan/dfilter/dfilter.c @@ -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; } diff --git a/epan/dfilter/dfilter.h b/epan/dfilter/dfilter.h index b7d22f5755..7cbb4b1539 100644 --- a/epan/dfilter/dfilter.h +++ b/epan/dfilter/dfilter.h @@ -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. */ diff --git a/epan/dfilter/dfunctions.c b/epan/dfilter/dfunctions.c index a78254918a..8f05c8e477 100644 --- a/epan/dfilter/dfunctions.c +++ b/epan/dfilter/dfunctions.c @@ -19,8 +19,8 @@ #include #include -#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 */ diff --git a/epan/dfilter/grammar.lemon b/epan/dfilter/grammar.lemon index 12b23c6768..c13b640c55 100644 --- a/epan/dfilter/grammar.lemon +++ b/epan/dfilter/grammar.lemon @@ -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; diff --git a/epan/dfilter/scanner.l b/epan/dfilter/scanner.l index 228dce5b4e..37f6dba8fa 100644 --- a/epan/dfilter/scanner.l +++ b/epan/dfilter/scanner.l @@ -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})+ } [^],]+ { - 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); } "," { @@ -206,7 +214,8 @@ hyphen-bytes {hex2}(-{hex2})+ } <> { - 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})+ <> { /* 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; } \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; } \\[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})+ \\. { /* 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})+ [^\\\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("'"); } <> { /* 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; } \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; } \\. { /* escaped character */ + update_string_loc(yyextra, yytext); g_string_append(yyextra->quoted_string, yytext); } [^\\\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; } diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c index f91d08c947..7a4eb5452b 100644 --- a/epan/dfilter/semcheck.c +++ b/epan/dfilter/semcheck.c @@ -29,10 +29,11 @@ #include -#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)); } diff --git a/epan/dfilter/syntax-tree.c b/epan/dfilter/syntax-tree.c index ae9fc1a4c7..ab75dc79d9 100644 --- a/epan/dfilter/syntax-tree.c +++ b/epan/dfilter/syntax-tree.c @@ -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) { diff --git a/epan/dfilter/syntax-tree.h b/epan/dfilter/syntax-tree.h index 9e2725c427..357e789ab2 100644 --- a/epan/dfilter/syntax-tree.h +++ b/epan/dfilter/syntax-tree.h @@ -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); diff --git a/packaging/debian/libwireshark0.symbols b/packaging/debian/libwireshark0.symbols index 10628c6741..38cad5d976 100644 --- a/packaging/debian/libwireshark0.symbols +++ b/packaging/debian/libwireshark0.symbols @@ -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