diff options
author | Guy Harris <guy@alum.mit.edu> | 2015-01-18 02:22:19 -0800 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2015-01-18 10:22:59 +0000 |
commit | cfcbb286712ae392689e7cd1a640b57b611dd277 (patch) | |
tree | c41ab4705bb0b790da02bc8b29768b5879543474 /epan/dfilter | |
parent | c60fb3038e4a449c5488a32574d838a6599cb33f (diff) |
Clean up ftype-conversion and dfilter error message string handling.
Have dfilter_compile() take an additional gchar ** argument, pointing to
a gchar * item that, on error, gets set to point to a g_malloc()ed error
string. That removes one bit of global state from the display filter
parser, and doesn't impose a fixed limit on the error message strings.
Have fvalue_from_string() and fvalue_from_unparsed() take a gchar **
argument, pointer to a gchar * item, rather than an error-reporting
function, and set the gchar * item to point to a g_malloc()ed error
string on an error.
Allow either gchar ** argument to be null; if the argument is null, no
error message is allocated or provided.
Change-Id: Ibd36b8aaa9bf4234aa6efa1e7fb95f7037493b4c
Reviewed-on: https://code.wireshark.org/review/6608
Reviewed-by: Guy Harris <guy@alum.mit.edu>
Diffstat (limited to 'epan/dfilter')
-rw-r--r-- | epan/dfilter/dfilter-int.h | 11 | ||||
-rw-r--r-- | epan/dfilter/dfilter-macro.c | 47 | ||||
-rw-r--r-- | epan/dfilter/dfilter.c | 63 | ||||
-rw-r--r-- | epan/dfilter/dfilter.h | 20 | ||||
-rw-r--r-- | epan/dfilter/dfunctions.c | 12 | ||||
-rw-r--r-- | epan/dfilter/dfunctions.h | 2 | ||||
-rw-r--r-- | epan/dfilter/grammar.lemon | 16 | ||||
-rw-r--r-- | epan/dfilter/scanner.l | 34 | ||||
-rw-r--r-- | epan/dfilter/semcheck.c | 268 | ||||
-rw-r--r-- | epan/dfilter/sttype-function.h | 1 |
10 files changed, 267 insertions, 207 deletions
diff --git a/epan/dfilter/dfilter-int.h b/epan/dfilter/dfilter-int.h index 8a7511de05..40e55488b5 100644 --- a/epan/dfilter/dfilter-int.h +++ b/epan/dfilter/dfilter-int.h @@ -44,6 +44,7 @@ typedef struct { /* Syntax Tree stuff */ stnode_t *st_root; gboolean syntax_error; + gchar *error_message; GPtrArray *insns; GPtrArray *consts; GHashTable *loaded_fields; @@ -54,6 +55,12 @@ typedef struct { int first_constant; /* first register used as a constant */ } dfwork_t; +/* + * XXX - if we're using a version of Flex that supports reentrant lexical + * analyzers, we should put this into the lexical analyzer's state. + */ +extern dfwork_t *global_dfw; + /* Constructor/Destructor prototypes for Lemon Parser */ void *DfilterAlloc(void* (*)(gsize)); @@ -66,9 +73,9 @@ extern stnode_t *df_lval; /* Return value for error in scanner. */ #define SCAN_FAILED -1 /* not 0, as that means end-of-input */ -/* Set dfilter_error_msg_buf and dfilter_error_msg */ +/* Set dfw->error_message */ void -dfilter_fail(const char *format, ...) G_GNUC_PRINTF(1, 2); +dfilter_fail(dfwork_t *dfw, const char *format, ...) G_GNUC_PRINTF(2, 3); void DfilterTrace(FILE *TraceFILE, char *zTracePrompt); diff --git a/epan/dfilter/dfilter-macro.c b/epan/dfilter/dfilter-macro.c index 578bac60c6..132c9fe5a0 100644 --- a/epan/dfilter/dfilter-macro.c +++ b/epan/dfilter/dfilter-macro.c @@ -30,7 +30,6 @@ #include "dfilter.h" #include "dfilter-macro.h" #include <ftypes/ftypes-int.h> -#include <epan/emem.h> #include <epan/uat-int.h> #include <epan/proto.h> #include <wsutil/file_util.h> @@ -110,7 +109,8 @@ void dfilter_macro_save(const gchar* filename, gchar** error) { FILE* f = ws_fopen(filename,"w"); if (!f) { - *error = wmem_strdup_printf(NULL, "Could not open file: '%s', error: %s\n", filename, g_strerror(errno) ); + if (error != NULL) + *error = g_strdup_printf("Could not open file: '%s', error: %s\n", filename, g_strerror(errno) ); return; } @@ -170,11 +170,13 @@ static gchar* dfilter_macro_resolve(gchar* name, gchar** args, gchar** error) { if(e->usable) { return wmem_strdup(NULL, e->repr); } else { - *error = wmem_strdup_printf(NULL, "macro '%s' is unusable", name); + if (error != NULL) + *error = g_strdup_printf("macro '%s' is unusable", name); return NULL; } } else { - *error = wmem_strdup_printf(NULL, "macro '%s' does not exist", name); + if (error != NULL) + *error = g_strdup_printf("macro '%s' does not exist", name); return NULL; } } @@ -186,8 +188,10 @@ static gchar* dfilter_macro_resolve(gchar* name, gchar** args, gchar** error) { } if (argc != m->argc) { - *error = wmem_strdup_printf(NULL, "wrong number of arguments for macro '%s', expecting %d instead of %d", - name, m->argc, argc); + if (error != NULL) { + *error = g_strdup_printf("wrong number of arguments for macro '%s', expecting %d instead of %d", + name, m->argc, argc); + } return NULL; } @@ -223,7 +227,8 @@ static const gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, gboolean changed = FALSE; if ( depth > 31) { - *error = wmem_strdup(NULL, "too much nesting in macros"); + if (error != NULL) + *error = g_strdup("too much nesting in macros"); return NULL; } @@ -240,7 +245,8 @@ static const gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, } \ } while(0) - *error = NULL; + if (error != NULL) + *error = NULL; out = g_string_sized_new(64); while(1) { @@ -295,7 +301,8 @@ static const gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, g_ptr_array_add(args,NULL); resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error); - if (*error) goto on_error; + if (resolved == NULL) + goto on_error; changed = TRUE; @@ -306,17 +313,20 @@ static const gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, state = OUTSIDE; } else if ( c == '\0') { - *error = wmem_strdup(NULL, "end of filter in the middle of a macro expression"); + if (error != NULL) + *error = g_strdup("end of filter in the middle of a macro expression"); goto on_error; } else { - *error = wmem_strdup(NULL, "invalid char in macro name"); + if (error != NULL) + *error = g_strdup("invalid character in macro name"); goto on_error; } break; } case ARGS: { switch(c) { case '\0': { - *error = wmem_strdup(NULL, "end of filter in the middle of a macro expression"); + if (error != NULL) + *error = g_strdup("end of filter in the middle of a macro expression"); goto on_error; } case ';': { g_ptr_array_add(args,g_string_free(arg,FALSE)); @@ -329,7 +339,8 @@ static const gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, g_string_append_c(arg,c); break; } else { - *error = wmem_strdup(NULL, "end of filter in the middle of a macro expression"); + if (error != NULL) + *error = g_strdup("end of filter in the middle of a macro expression"); goto on_error; } } default: { @@ -343,7 +354,8 @@ static const gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, arg = NULL; resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error); - if (*error) goto on_error; + if (resolved == NULL) + goto on_error; changed = TRUE; @@ -368,7 +380,7 @@ finish: if (changed) { const gchar* resolved = dfilter_macro_apply_recurse(out->str, depth + 1, error); g_string_free(out,TRUE); - return (*error) ? NULL : resolved; + return resolved; } else { const gchar* out_str = wmem_strdup(NULL, out->str); g_string_free(out,TRUE); @@ -378,7 +390,10 @@ finish: on_error: { FREE_ALL(); - if (! *error) *error = wmem_strdup(NULL, "unknown error in macro expression"); + if (error != NULL) { + if (*error == NULL) + *error = g_strdup("unknown error in macro expression"); + } g_string_free(out,TRUE); return NULL; } diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c index 8e21d30853..903ec33868 100644 --- a/epan/dfilter/dfilter.c +++ b/epan/dfilter/dfilter.c @@ -34,10 +34,6 @@ #define DFILTER_TOKEN_ID_OFFSET 1 -/* Global error message space for dfilter_compile errors */ -static gchar dfilter_error_msg_buf[1024]; -const gchar *dfilter_error_msg; /* NULL when no error resulted */ - /* From scanner.c */ void df_scanner_text(const char *text); void df_scanner_cleanup(void); @@ -46,24 +42,26 @@ int df_lex(void); /* Holds the singular instance of our Lemon parser object */ static void* ParserObj = NULL; +/* + * XXX - if we're using a version of Flex that supports reentrant lexical + * analyzers, we should put this into the lexical analyzer's state. + */ +dfwork_t *global_dfw; + void -dfilter_fail(const char *format, ...) +dfilter_fail(dfwork_t *dfw, const char *format, ...) { va_list args; /* If we've already reported one error, don't overwite it */ - if (dfilter_error_msg != NULL) + if (dfw->error_message != NULL) return; va_start(args, format); - - g_vsnprintf(dfilter_error_msg_buf, sizeof(dfilter_error_msg_buf), - format, args); - dfilter_error_msg = dfilter_error_msg_buf; + dfw->error_message = g_strdup_vprintf(format, args); va_end(args); } - /* Initialize the dfilter module */ void dfilter_init(void) @@ -110,7 +108,7 @@ dfilter_new(void) df = g_new0(dfilter_t, 1); df->insns = NULL; - df->deprecated = NULL; + df->deprecated = NULL; return df; } @@ -202,11 +200,15 @@ dfwork_free(dfwork_t *dfw) free_insns(dfw->consts); } + /* + * We don't free the error message string; our caller will return + * it to its caller. + */ g_free(dfw); } gboolean -dfilter_compile(const gchar *text, dfilter_t **dfp) +dfilter_compile(const gchar *text, dfilter_t **dfp, gchar **err_msg) { int token; dfilter_t *dfilter; @@ -216,26 +218,28 @@ dfilter_compile(const gchar *text, dfilter_t **dfp) guint i; /* XXX, GHashTable */ GPtrArray *deprecated; - gchar *temp_error_msg; g_assert(dfp); if (!text) { *dfp = NULL; + if (err_msg != NULL) + *err_msg = g_strdup("BUG: NULL text pointer passed to dfilter_compile()"); return FALSE; } - dfilter_error_msg = NULL; - - if ( !( text = dfilter_macro_apply(text, &temp_error_msg) ) ) { - /* Move the ep_ allocation up a layer */ - dfilter_error_msg = ep_strdup(temp_error_msg); - wmem_free(NULL, temp_error_msg); + if ( !( text = dfilter_macro_apply(text, err_msg) ) ) { return FALSE; } dfw = dfwork_new(); + /* + * XXX - if we're using a version of Flex that supports reentrant lexical + * analyzers, we should put this into the lexical analyzer's state. + */ + global_dfw = dfw; + df_scanner_text(text); deprecated = g_ptr_array_new(); @@ -353,12 +357,18 @@ dfilter_compile(const gchar *text, dfilter_t **dfp) *dfp = dfilter; } /* SUCCESS */ + global_dfw = NULL; dfwork_free(dfw); wmem_free(NULL, (char*)text); return TRUE; FAILURE: if (dfw) { + if (err_msg != NULL) + *err_msg = dfw->error_message; + else + g_free(dfw->error_message); + global_dfw = NULL; dfwork_free(dfw); } for (i = 0; i < deprecated->len; ++i) { @@ -366,11 +376,18 @@ FAILURE: g_free(depr); } g_ptr_array_free(deprecated, TRUE); - dfilter_fail("Unable to parse filter string \"%s\".", text); - wmem_free(NULL, (char*)text); + if (err_msg != NULL) { + /* + * Default error message. + * + * XXX - we should really make sure that this is never the + * case for any error. + */ + if (*err_msg == NULL) + *err_msg = g_strdup_printf("Unable to parse filter string \"%s\".", text); + } *dfp = NULL; return FALSE; - } diff --git a/epan/dfilter/dfilter.h b/epan/dfilter/dfilter.h index b408dc7757..1bbf907ec4 100644 --- a/epan/dfilter/dfilter.h +++ b/epan/dfilter/dfilter.h @@ -50,17 +50,16 @@ dfilter_cleanup(void); * a pointer to the newly-allocated dfilter_t * structure. * - * On failure, dfilter_error_msg points to an - * appropriate error message. This error message is - * a global string, so another invocation of - * dfilter_compile() will clear it. The dfilter* - * will be set to NULL after a failure. + * On failure, *err_msg is set to point to the error + * message. This error message is allocated with + * g_malloc(), and must be freed with g_free(). + * The dfilter* will be set to NULL after a failure. * * Returns TRUE on success, FALSE on failure. */ WS_DLL_PUBLIC gboolean -dfilter_compile(const gchar *text, dfilter_t **dfp); +dfilter_compile(const gchar *text, dfilter_t **dfp, gchar **err_msg); /* Frees all memory used by dfilter, and frees * the dfilter itself. */ @@ -68,15 +67,6 @@ WS_DLL_PUBLIC void dfilter_free(dfilter_t *df); - -/* dfilter_error_msg is NULL if there was no error during dfilter_compile, - * otherwise it points to a displayable error message. With MSVC and a - * libwireshark.dll, we need a special declaration. - */ - -WS_DLL_PUBLIC const gchar *dfilter_error_msg; - - /* Apply compiled dfilter */ WS_DLL_PUBLIC gboolean diff --git a/epan/dfilter/dfunctions.c b/epan/dfilter/dfunctions.c index 6394a1e482..204e6f712b 100644 --- a/epan/dfilter/dfunctions.c +++ b/epan/dfilter/dfunctions.c @@ -22,8 +22,8 @@ #include <glib.h> -#include "dfunctions.h" #include "dfilter-int.h" +#include "dfunctions.h" #include <string.h> @@ -142,7 +142,7 @@ df_func_count(GList* arg1list, GList *arg2junk _U_, GList **retval) /* For upper(), lower() and len(), checks that the parameter passed to * it is an FT_STRING */ static void -ul_semcheck_params(int param_num, stnode_t *st_node) +ul_semcheck_params(dfwork_t *dfw, int param_num, stnode_t *st_node) { sttype_id_t type; ftenum_t ftype; @@ -156,12 +156,12 @@ ul_semcheck_params(int param_num, stnode_t *st_node) hfinfo = (header_field_info *)stnode_data(st_node); ftype = hfinfo->type; if (!IS_FT_STRING(ftype)) { - dfilter_fail("Only strings can be used in upper() or lower() or len()"); + dfilter_fail(dfw, "Only strings can be used in upper() or lower() or len()"); THROW(TypeError); } break; default: - dfilter_fail("Only string-type fields can be used in upper() or lower() or len()"); + dfilter_fail(dfw, "Only string-type fields can be used in upper() or lower() or len()"); THROW(TypeError); } } @@ -171,7 +171,7 @@ ul_semcheck_params(int param_num, stnode_t *st_node) } static void -ul_semcheck_field_param(int param_num, stnode_t *st_node) +ul_semcheck_field_param(dfwork_t *dfw, int param_num, stnode_t *st_node) { sttype_id_t type; @@ -182,7 +182,7 @@ ul_semcheck_field_param(int param_num, stnode_t *st_node) case STTYPE_FIELD: break; default: - dfilter_fail("Only type fields can be used as parameter " + dfilter_fail(dfw, "Only type fields can be used as parameter " "for size() or count()"); THROW(TypeError); } diff --git a/epan/dfilter/dfunctions.h b/epan/dfilter/dfunctions.h index 2b7957ec2c..96aed53bc6 100644 --- a/epan/dfilter/dfunctions.h +++ b/epan/dfilter/dfunctions.h @@ -29,7 +29,7 @@ typedef gboolean (*DFFuncType)(GList *arg1list, GList *arg2list, GList **retval); /* The semantic check for the dfilter function */ -typedef void (*DFSemCheckType)(int param_num, stnode_t *st_node); +typedef void (*DFSemCheckType)(dfwork_t *dfw, int param_num, stnode_t *st_node); /* If a function needs more args than this, increase * this macro and add more arg members to the dfvm_insn_t diff --git a/epan/dfilter/grammar.lemon b/epan/dfilter/grammar.lemon index c52fe7ad40..abd6e9a1cd 100644 --- a/epan/dfilter/grammar.lemon +++ b/epan/dfilter/grammar.lemon @@ -68,35 +68,35 @@ any "error" symbols are shifted, if possible. */ header_field_info *hfinfo; if (!TOKEN) { - dfilter_fail("Unexpected end of filter string."); + dfilter_fail(dfw, "Unexpected end of filter string."); return; } switch(stnode_type_id(TOKEN)) { case STTYPE_UNINITIALIZED: - dfilter_fail("Syntax error."); + dfilter_fail(dfw, "Syntax error."); break; case STTYPE_TEST: - dfilter_fail("Syntax error, TEST."); + dfilter_fail(dfw, "Syntax error, TEST."); break; case STTYPE_STRING: - dfilter_fail("The string \"%s\" was unexpected in this context.", + dfilter_fail(dfw, "The string \"%s\" was unexpected in this context.", (char *)stnode_data(TOKEN)); break; case STTYPE_UNPARSED: - dfilter_fail("\"%s\" was unexpected in this context.", + dfilter_fail(dfw, "\"%s\" was unexpected in this context.", (char *)stnode_data(TOKEN)); break; case STTYPE_INTEGER: - dfilter_fail("The integer %d was unexpected in this context.", + dfilter_fail(dfw, "The integer %d was unexpected in this context.", stnode_value(TOKEN)); break; case STTYPE_FIELD: hfinfo = (header_field_info *)stnode_data(TOKEN); - dfilter_fail("Syntax error near \"%s\".", hfinfo->abbrev); + dfilter_fail(dfw, "Syntax error near \"%s\".", hfinfo->abbrev); break; case STTYPE_FUNCTION: - dfilter_fail("The function s was unexpected in this context."); + dfilter_fail(dfw, "The function s was unexpected in this context."); break; /* These aren't handed to use as terminal tokens from diff --git a/epan/dfilter/scanner.l b/epan/dfilter/scanner.l index f09f30b40c..d3b71a39f9 100644 --- a/epan/dfilter/scanner.l +++ b/epan/dfilter/scanner.l @@ -68,9 +68,9 @@ /*#undef YY_NO_UNPUT*/ static int set_lval(int token, gpointer data); -static int set_lval_int(int token, char *s); +static int set_lval_int(dfwork_t *dfw, int token, char *s); static int simple(int token); -static gboolean str_to_gint32(char *s, gint32* pint); +static gboolean str_to_gint32(dfwork_t *dfw, char *s, gint32* pint); GString* quoted_string = NULL; static void mark_lval_deprecated(const char *s); @@ -128,12 +128,12 @@ static void mark_lval_deprecated(const char *s); <RANGE_INT>[+-]?[[:digit:]]+ { BEGIN(RANGE_PUNCT); - return set_lval_int(TOKEN_INTEGER, yytext); + return set_lval_int(global_dfw, TOKEN_INTEGER, yytext); } <RANGE_INT>[+-]?0x[[:xdigit:]]+ { BEGIN(RANGE_PUNCT); - return set_lval_int(TOKEN_INTEGER, yytext); + return set_lval_int(global_dfw, TOKEN_INTEGER, yytext); } <RANGE_INT,RANGE_PUNCT>":" { @@ -159,7 +159,7 @@ static void mark_lval_deprecated(const char *s); /* Error if none of the above while scanning a range (slice) */ <RANGE_PUNCT>[^:\-,\]]+ { - dfilter_fail("Invalid string \"%s\" found while scanning slice.", yytext); + dfilter_fail(global_dfw, "Invalid string \"%s\" found while scanning slice.", yytext); return SCAN_FAILED; } @@ -168,7 +168,7 @@ static void mark_lval_deprecated(const char *s); */ <RANGE_INT>. { - dfilter_fail("Invalid character \"%s\" found while scanning slice; expected integer.", yytext); + dfilter_fail(global_dfw, "Invalid character \"%s\" found while scanning slice; expected integer.", yytext); return SCAN_FAILED; } @@ -200,7 +200,7 @@ static void mark_lval_deprecated(const char *s); See: http://www.gnu.org/software/flex/manual/html_node/flex_13.html */ - dfilter_fail("The final quote was missing from a quoted string."); + dfilter_fail(global_dfw, "The final quote was missing from a quoted string."); return SCAN_FAILED; } @@ -221,7 +221,7 @@ static void mark_lval_deprecated(const char *s); if (result > 0xff) { g_string_free(quoted_string, TRUE); quoted_string = NULL; - dfilter_fail("%s is larger than 255.", yytext); + dfilter_fail(global_dfw, "%s is larger than 255.", yytext); return SCAN_FAILED; } g_string_append_c(quoted_string, (gchar) result); @@ -340,12 +340,12 @@ set_lval(int token, gpointer data) } static int -set_lval_int(int token, char *s) +set_lval_int(dfwork_t *dfw, int token, char *s) { sttype_id_t type_id = STTYPE_UNINITIALIZED; gint32 val; - if (!str_to_gint32(s, &val)) { + if (!str_to_gint32(dfw, s, &val)) { return SCAN_FAILED; } @@ -363,7 +363,7 @@ set_lval_int(int token, char *s) static gboolean -str_to_gint32(char *s, gint32* pint) +str_to_gint32(dfwork_t *dfw, char *s, gint32* pint) { char *endptr; long integer; @@ -373,22 +373,22 @@ str_to_gint32(char *s, gint32* pint) if (errno == EINVAL || endptr == s || *endptr != '\0') { /* This isn't a valid number. */ - dfilter_fail("\"%s\" is not a valid number.", s); + dfilter_fail(dfw, "\"%s\" is not a valid number.", s); return FALSE; } if (errno == ERANGE) { if (integer == LONG_MAX) { - dfilter_fail("\"%s\" causes an integer overflow.", s); + dfilter_fail(dfw, "\"%s\" causes an integer overflow.", s); } else if (integer == LONG_MIN) { - dfilter_fail("\"%s\" causes an integer underflow.", s); + dfilter_fail(dfw, "\"%s\" causes an integer underflow.", s); } else { /* * XXX - can "strtol()" set errno to ERANGE without * returning LONG_MAX or LONG_MIN? */ - dfilter_fail("\"%s\" is not an integer.", s); + dfilter_fail(dfw, "\"%s\" is not an integer.", s); } return FALSE; } @@ -397,7 +397,7 @@ str_to_gint32(char *s, gint32* pint) * Fits in a long, but not in a gint32 (a long might be * 64 bits). */ - dfilter_fail("\"%s\" causes an integer overflow.", s); + dfilter_fail(dfw, "\"%s\" causes an integer overflow.", s); return FALSE; } if (integer < G_MININT32) { @@ -405,7 +405,7 @@ str_to_gint32(char *s, gint32* pint) * Fits in a long, but not in a gint32 (a long might be * 64 bits). */ - dfilter_fail("\"%s\" causes an integer underflow.", s); + dfilter_fail(dfw, "\"%s\" causes an integer underflow.", s); return FALSE; } diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c index bda8f49c4b..cc1a5df4bb 100644 --- a/epan/dfilter/semcheck.c +++ b/epan/dfilter/semcheck.c @@ -48,10 +48,10 @@ #endif static void -semcheck(stnode_t *st_node, GPtrArray *deprecated); +semcheck(dfwork_t *dfw, stnode_t *st_node, GPtrArray *deprecated); static stnode_t* -check_param_entity(stnode_t *st_node); +check_param_entity(dfwork_t *dfw, stnode_t *st_node); typedef gboolean (*FtypeCanFunc)(enum ftenum); @@ -137,6 +137,25 @@ compatible_ftypes(ftenum_t a, ftenum_t b) return FALSE; } +/* Gets an fvalue from a string, and sets the error message on failure. */ +static fvalue_t* +dfilter_fvalue_from_unparsed(dfwork_t *dfw, ftenum_t ftype, const char *s, gboolean allow_partial_value) +{ + /* + * Don't set the error message if it's already set. + */ + return fvalue_from_unparsed(ftype, s, allow_partial_value, + dfw->error_message == NULL ? &dfw->error_message : NULL); +} + +/* Gets an fvalue from a string, and sets the error message on failure. */ +static fvalue_t* +dfilter_fvalue_from_string(dfwork_t *dfw, ftenum_t ftype, const char *s) +{ + return fvalue_from_string(ftype, s, + dfw->error_message == NULL ? &dfw->error_message : NULL); +} + /* Creates a FT_UINT32 fvalue with a given value. */ static fvalue_t* mk_uint32_fvalue(guint32 val) @@ -165,7 +184,7 @@ mk_uint64_fvalue(guint64 val) * This works only for ftypes that are integers. Returns the created fvalue_t* * or NULL if impossible. */ static fvalue_t* -mk_fvalue_from_val_string(header_field_info *hfinfo, char *s) +mk_fvalue_from_val_string(dfwork_t *dfw, header_field_info *hfinfo, char *s) { static const true_false_string default_tf = { "True", "False" }; const true_false_string *tf = &default_tf; @@ -230,8 +249,13 @@ mk_fvalue_from_val_string(header_field_info *hfinfo, char *s) return mk_uint32_fvalue(FALSE); } else { - dfilter_error_msg = NULL; /* Prefer this error message */ - dfilter_fail("\"%s\" cannot be found among the possible values for %s.", + /* + * Prefer this error message to whatever error message + * has already been set. + */ + g_free(dfw->error_message); + dfw->error_message = NULL; + dfilter_fail(dfw, "\"%s\" cannot be found among the possible values for %s.", s, hfinfo->abbrev); return NULL; } @@ -239,18 +263,19 @@ mk_fvalue_from_val_string(header_field_info *hfinfo, char *s) /* Do val_strings exist? */ if (!hfinfo->strings) { - dfilter_fail("%s cannot accept strings as values.", + dfilter_fail(dfw, "%s cannot accept strings as values.", hfinfo->abbrev); return NULL; } - /* Reset the dfilter error message, since *something* interesting - * will happen, and the error message will be more interesting than - * any error message I happen to have now. */ - dfilter_error_msg = NULL; + /* Reset the error message, since *something* interesting will happen, + * and the error message will be more interesting than any error message + * I happen to have now. */ + g_free(dfw->error_message); + dfw->error_message = NULL; if (hfinfo->display & BASE_RANGE_STRING) { - dfilter_fail("\"%s\" cannot accept [range] strings as values.", + dfilter_fail(dfw, "\"%s\" cannot accept [range] strings as values.", hfinfo->abbrev); } else if (hfinfo->display & BASE_VAL64_STRING) { @@ -262,7 +287,7 @@ mk_fvalue_from_val_string(header_field_info *hfinfo, char *s) } vals++; } - dfilter_fail("\"%s\" cannot be found among the possible values for %s.", + dfilter_fail(dfw, "\"%s\" cannot be found among the possible values for %s.", s, hfinfo->abbrev); } else if (hfinfo->display == BASE_CUSTOM) { @@ -272,7 +297,7 @@ mk_fvalue_from_val_string(header_field_info *hfinfo, char *s) * integer, we have the string they're trying to match. * -><- */ - dfilter_fail("\"%s\" cannot accept [custom] strings as values.", + dfilter_fail(dfw, "\"%s\" cannot accept [custom] strings as values.", hfinfo->abbrev); } else { @@ -286,7 +311,7 @@ mk_fvalue_from_val_string(header_field_info *hfinfo, char *s) } vals++; } - dfilter_fail("\"%s\" cannot be found among the possible values for %s.", + dfilter_fail(dfw, "\"%s\" cannot be found among the possible values for %s.", s, hfinfo->abbrev); } return NULL; @@ -347,7 +372,7 @@ is_bytes_type(enum ftenum type) /* Check the semantics of an existence test. */ static void -check_exists(stnode_t *st_arg1) +check_exists(dfwork_t *dfw, stnode_t *st_arg1) { #ifdef DEBUG_dfilter static guint i = 0; @@ -360,7 +385,7 @@ check_exists(stnode_t *st_arg1) break; case STTYPE_STRING: case STTYPE_UNPARSED: - dfilter_fail("\"%s\" is neither a field nor a protocol name.", + dfilter_fail(dfw, "\"%s\" is neither a field nor a protocol name.", (char *)stnode_data(st_arg1)); THROW(TypeError); break; @@ -372,14 +397,14 @@ check_exists(stnode_t *st_arg1) * has at least 2 bytes starting at an offset of * 3"? */ - dfilter_fail("You cannot test whether a range is present."); + dfilter_fail(dfw, "You cannot test whether a range is present."); THROW(TypeError); break; case STTYPE_FUNCTION: /* XXX - Maybe we should change functions so they can return fields, * in which case the 'exist' should be fine. */ - dfilter_fail("You cannot test whether a function is present."); + dfilter_fail(dfw, "You cannot test whether a function is present."); THROW(TypeError); break; @@ -393,6 +418,7 @@ check_exists(stnode_t *st_arg1) } struct check_drange_sanity_args { + dfwork_t *dfw; stnode_t *st; gboolean err; }; @@ -428,13 +454,13 @@ check_drange_node_sanity(gpointer data, gpointer user_data) if (entity && stnode_type_id(entity) == STTYPE_FIELD) { hfinfo = (header_field_info *)stnode_data(entity); - dfilter_fail("Range %d:%d specified for \"%s\" isn't valid, " + dfilter_fail(args->dfw, "Range %d:%d specified for \"%s\" isn't valid, " "as length %d isn't positive", start_offset, length, hfinfo->abbrev, length); } else - dfilter_fail("Range %d:%d isn't valid, " + dfilter_fail(args->dfw, "Range %d:%d isn't valid, " "as length %d isn't positive", start_offset, length, length); @@ -462,14 +488,14 @@ check_drange_node_sanity(gpointer data, gpointer user_data) if (entity && stnode_type_id(entity) == STTYPE_FIELD) { hfinfo = (header_field_info *)stnode_data(entity); - dfilter_fail("Range %d-%d specified for \"%s\" isn't valid, " + dfilter_fail(args->dfw, "Range %d-%d specified for \"%s\" isn't valid, " "as %d is greater than %d", start_offset, end_offset, hfinfo->abbrev, start_offset, end_offset); } else - dfilter_fail("Range %d-%d isn't valid, " + dfilter_fail(args->dfw, "Range %d-%d isn't valid, " "as %d is greater than %d", start_offset, end_offset, start_offset, end_offset); @@ -487,10 +513,11 @@ check_drange_node_sanity(gpointer data, gpointer user_data) } static void -check_drange_sanity(stnode_t *st) +check_drange_sanity(dfwork_t *dfw, stnode_t *st) { struct check_drange_sanity_args args; + args.dfw = dfw; args.st = st; args.err = FALSE; @@ -520,7 +547,7 @@ convert_to_bytes(stnode_t *arg) } static void -check_function(stnode_t *st_node) +check_function(dfwork_t *dfw, stnode_t *st_node) { df_func_def_t *funcdef; GSList *params; @@ -532,19 +559,19 @@ check_function(stnode_t *st_node) nparams = g_slist_length(params); if (nparams < funcdef->min_nargs) { - dfilter_fail("Function %s needs at least %u arguments.", + dfilter_fail(dfw, "Function %s needs at least %u arguments.", funcdef->name, funcdef->min_nargs); THROW(TypeError); } else if (nparams > funcdef->max_nargs) { - dfilter_fail("Function %s can only accept %u arguments.", + dfilter_fail(dfw, "Function %s can only accept %u arguments.", funcdef->name, funcdef->max_nargs); THROW(TypeError); } iparam = 0; while (params) { - params->data = check_param_entity((stnode_t *)params->data); - funcdef->semcheck_param_function(iparam, (stnode_t *)params->data); + params->data = check_param_entity(dfw, (stnode_t *)params->data); + funcdef->semcheck_param_function(dfw, iparam, (stnode_t *)params->data); params = params->next; iparam++; } @@ -553,8 +580,8 @@ check_function(stnode_t *st_node) /* If the LHS of a relation test is a FIELD, run some checks * and possibly some modifications of syntax tree nodes. */ static void -check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func, - gboolean allow_partial_value, +check_relation_LHS_FIELD(dfwork_t *dfw, const char *relation_string, + FtypeCanFunc can_func, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; @@ -573,7 +600,7 @@ check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func, DebugLog((" 5 check_relation_LHS_FIELD(%s)\n", relation_string)); if (!can_func(ftype1)) { - dfilter_fail("%s (type=%s) cannot participate in '%s' comparison.", + dfilter_fail(dfw, "%s (type=%s) cannot participate in '%s' comparison.", hfinfo1->abbrev, ftype_pretty_name(ftype1), relation_string); THROW(TypeError); @@ -584,14 +611,14 @@ check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func, ftype2 = hfinfo2->type; if (!compatible_ftypes(ftype1, ftype2)) { - dfilter_fail("%s and %s are not of compatible types.", + dfilter_fail(dfw, "%s and %s are not of compatible types.", hfinfo1->abbrev, hfinfo2->abbrev); THROW(TypeError); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { - dfilter_fail("%s (type=%s) cannot participate in specified comparison.", + dfilter_fail(dfw, "%s (type=%s) cannot participate in specified comparison.", hfinfo2->abbrev, ftype_pretty_name(ftype2)); THROW(TypeError); } @@ -601,9 +628,9 @@ check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func, if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ if (type2 == STTYPE_STRING) - fvalue = fvalue_from_string(FT_PCRE, s, dfilter_fail); + fvalue = dfilter_fvalue_from_string(dfw, FT_PCRE, s); else - fvalue = fvalue_from_unparsed(FT_PCRE, s, FALSE, dfilter_fail); + fvalue = dfilter_fvalue_from_unparsed(dfw, FT_PCRE, s, FALSE); } else { /* Skip incompatible fields */ while (hfinfo1->same_name_prev_id != -1 && @@ -614,13 +641,13 @@ check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func, } if (type2 == STTYPE_STRING) - fvalue = fvalue_from_string(ftype1, s, dfilter_fail); + fvalue = dfilter_fvalue_from_string(dfw, ftype1, s); else - fvalue = fvalue_from_unparsed(ftype1, s, allow_partial_value, dfilter_fail); + fvalue = dfilter_fvalue_from_unparsed(dfw, ftype1, s, allow_partial_value); if (!fvalue) { /* check value_string */ - fvalue = mk_fvalue_from_val_string(hfinfo1, s); + fvalue = mk_fvalue_from_val_string(dfw, hfinfo1, s); } } @@ -633,10 +660,10 @@ check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func, stnode_free(st_arg2); } else if (type2 == STTYPE_RANGE) { - check_drange_sanity(st_arg2); + check_drange_sanity(dfw, st_arg2); if (!is_bytes_type(ftype1)) { if (!ftype_can_slice(ftype1)) { - dfilter_fail("\"%s\" is a %s and cannot be converted into a sequence of bytes.", + dfilter_fail(dfw, "\"%s\" is a %s and cannot be converted into a sequence of bytes.", hfinfo1->abbrev, ftype_pretty_name(ftype1)); THROW(TypeError); @@ -653,19 +680,19 @@ check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func, ftype2 = funcdef->retval_ftype; if (!compatible_ftypes(ftype1, ftype2)) { - dfilter_fail("%s (type=%s) and return value of %s() (type=%s) are not of compatible types.", + dfilter_fail(dfw, "%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)); THROW(TypeError); } if (!can_func(ftype2)) { - dfilter_fail("return value of %s() (type=%s) cannot participate in specified comparison.", + dfilter_fail(dfw, "return value of %s() (type=%s) cannot participate in specified comparison.", funcdef->name, ftype_pretty_name(ftype2)); THROW(TypeError); } - check_function(st_arg2); + check_function(dfw, st_arg2); } else { g_assert_not_reached(); @@ -673,7 +700,7 @@ check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func, } static void -check_relation_LHS_STRING(const char* relation_string, +check_relation_LHS_STRING(dfwork_t *dfw, const char* relation_string, FtypeCanFunc can_func, gboolean allow_partial_value _U_, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) @@ -695,17 +722,17 @@ check_relation_LHS_STRING(const char* relation_string, ftype2 = hfinfo2->type; if (!can_func(ftype2)) { - dfilter_fail("%s (type=%s) cannot participate in '%s' comparison.", + dfilter_fail(dfw, "%s (type=%s) cannot participate in '%s' comparison.", hfinfo2->abbrev, ftype_pretty_name(ftype2), relation_string); THROW(TypeError); } s = (char*)stnode_data(st_arg1); - fvalue = fvalue_from_string(ftype2, s, dfilter_fail); + fvalue = dfilter_fvalue_from_string(dfw, ftype2, s); if (!fvalue) { /* check value_string */ - fvalue = mk_fvalue_from_val_string(hfinfo2, s); + fvalue = mk_fvalue_from_val_string(dfw, hfinfo2, s); if (!fvalue) { THROW(TypeError); } @@ -717,15 +744,15 @@ check_relation_LHS_STRING(const char* relation_string, } else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED) { /* Well now that's silly... */ - dfilter_fail("Neither \"%s\" nor \"%s\" are field or protocol names.", + dfilter_fail(dfw, "Neither \"%s\" nor \"%s\" are field or protocol names.", (char *)stnode_data(st_arg1), (char *)stnode_data(st_arg2)); THROW(TypeError); } else if (type2 == STTYPE_RANGE) { - check_drange_sanity(st_arg2); + check_drange_sanity(dfw, st_arg2); s = (char*)stnode_data(st_arg1); - fvalue = fvalue_from_string(FT_BYTES, s, dfilter_fail); + fvalue = dfilter_fvalue_from_string(dfw, FT_BYTES, s); if (!fvalue) { THROW(TypeError); } @@ -738,19 +765,19 @@ check_relation_LHS_STRING(const char* relation_string, ftype2 = funcdef->retval_ftype; if (!can_func(ftype2)) { - dfilter_fail("Return value of function %s (type=%s) cannot participate in '%s' comparison.", + dfilter_fail(dfw, "Return value of function %s (type=%s) cannot participate in '%s' comparison.", funcdef->name, ftype_pretty_name(ftype2), relation_string); THROW(TypeError); } s = (char*)stnode_data(st_arg1); - fvalue = fvalue_from_string(ftype2, s, dfilter_fail); + fvalue = dfilter_fvalue_from_string(dfw, ftype2, s); if (!fvalue) { THROW(TypeError); } - check_function(st_arg2); + check_function(dfw, st_arg2); new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, new_st, st_arg2); @@ -762,7 +789,7 @@ check_relation_LHS_STRING(const char* relation_string, } static void -check_relation_LHS_UNPARSED(const char* relation_string, +check_relation_LHS_UNPARSED(dfwork_t *dfw, const char* relation_string, FtypeCanFunc can_func, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) @@ -784,17 +811,17 @@ check_relation_LHS_UNPARSED(const char* relation_string, ftype2 = hfinfo2->type; if (!can_func(ftype2)) { - dfilter_fail("%s (type=%s) cannot participate in '%s' comparison.", + dfilter_fail(dfw, "%s (type=%s) cannot participate in '%s' comparison.", hfinfo2->abbrev, ftype_pretty_name(ftype2), relation_string); THROW(TypeError); } s = (char*)stnode_data(st_arg1); - fvalue = fvalue_from_unparsed(ftype2, s, allow_partial_value, dfilter_fail); + fvalue = dfilter_fvalue_from_unparsed(dfw, ftype2, s, allow_partial_value); if (!fvalue) { /* check value_string */ - fvalue = mk_fvalue_from_val_string(hfinfo2, s); + fvalue = mk_fvalue_from_val_string(dfw, hfinfo2, s); if (!fvalue) { THROW(TypeError); } @@ -806,15 +833,15 @@ check_relation_LHS_UNPARSED(const char* relation_string, } else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED) { /* Well now that's silly... */ - dfilter_fail("Neither \"%s\" nor \"%s\" are field or protocol names.", + dfilter_fail(dfw, "Neither \"%s\" nor \"%s\" are field or protocol names.", (char *)stnode_data(st_arg1), (char *)stnode_data(st_arg2)); THROW(TypeError); } else if (type2 == STTYPE_RANGE) { - check_drange_sanity(st_arg2); + check_drange_sanity(dfw, st_arg2); s = (char*)stnode_data(st_arg1); - fvalue = fvalue_from_unparsed(FT_BYTES, s, allow_partial_value, dfilter_fail); + fvalue = dfilter_fvalue_from_unparsed(dfw, FT_BYTES, s, allow_partial_value); if (!fvalue) { THROW(TypeError); } @@ -827,19 +854,19 @@ check_relation_LHS_UNPARSED(const char* relation_string, ftype2 = funcdef->retval_ftype; if (!can_func(ftype2)) { - dfilter_fail("return value of function %s() (type=%s) cannot participate in '%s' comparison.", + dfilter_fail(dfw, "return value of function %s() (type=%s) cannot participate in '%s' comparison.", funcdef->name, ftype_pretty_name(ftype2), relation_string); THROW(TypeError); } s = (char*)stnode_data(st_arg1); - fvalue = fvalue_from_unparsed(ftype2, s, allow_partial_value, dfilter_fail); + fvalue = dfilter_fvalue_from_unparsed(dfw, ftype2, s, allow_partial_value); if (!fvalue) { THROW(TypeError); } - check_function(st_arg2); + check_function(dfw, st_arg2); new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, new_st, st_arg2); @@ -851,7 +878,8 @@ check_relation_LHS_UNPARSED(const char* relation_string, } static void -check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, +check_relation_LHS_RANGE(dfwork_t *dfw, const char *relation_string, + FtypeCanFunc can_func _U_, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) @@ -874,7 +902,7 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, ftype1 = hfinfo1->type; if (!ftype_can_slice(ftype1)) { - dfilter_fail("\"%s\" is a %s and cannot be sliced into a sequence of bytes.", + dfilter_fail(dfw, "\"%s\" is a %s and cannot be sliced into a sequence of bytes.", hfinfo1->abbrev, ftype_pretty_name(ftype1)); THROW(TypeError); } @@ -883,20 +911,20 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, ftype1 = funcdef->retval_ftype; if (!ftype_can_slice(ftype1)) { - dfilter_fail("Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.", + dfilter_fail(dfw, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.", funcdef->name, ftype_pretty_name(ftype1)); THROW(TypeError); } - check_function(entity1); + check_function(dfw, entity1); } else { - dfilter_fail("Range is not supported, details: " G_STRLOC " entity: %p of type %d", + dfilter_fail(dfw, "Range is not supported, details: " G_STRLOC " entity: %p of type %d", entity1, entity1 ? (int) stnode_type_id(entity1) : -1); THROW(TypeError); } - check_drange_sanity(st_arg1); + check_drange_sanity(dfw, st_arg1); if (type2 == STTYPE_FIELD) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_FIELD)\n")); @@ -905,7 +933,7 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, if (!is_bytes_type(ftype2)) { if (!ftype_can_slice(ftype2)) { - dfilter_fail("\"%s\" is a %s and cannot be converted into a sequence of bytes.", + dfilter_fail(dfw, "\"%s\" is a %s and cannot be converted into a sequence of bytes.", hfinfo2->abbrev, ftype_pretty_name(ftype2)); THROW(TypeError); @@ -922,9 +950,9 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, s = (char*)stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ - fvalue = fvalue_from_string(FT_PCRE, s, dfilter_fail); + fvalue = dfilter_fvalue_from_string(dfw, FT_PCRE, s); } else { - fvalue = fvalue_from_string(FT_BYTES, s, dfilter_fail); + fvalue = dfilter_fvalue_from_string(dfw, FT_BYTES, s); } if (!fvalue) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_STRING): Could not convert from string!\n")); @@ -940,7 +968,7 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, len_range = drange_get_total_length(sttype_range_drange(st_arg1)); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ - fvalue = fvalue_from_unparsed(FT_PCRE, s, FALSE, dfilter_fail); + fvalue = dfilter_fvalue_from_unparsed(dfw, FT_PCRE, s, FALSE); } /* The RHS should be FT_BYTES. However, there is a special case where @@ -952,17 +980,17 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, else if (len_range == 1 && strlen(s) == 4 && strncmp(s, "0x", 2) == 0) { /* Even if the RHS string starts with "0x", it still could fail to * be an integer. Try converting it here. */ - fvalue = fvalue_from_unparsed(FT_UINT8, s, allow_partial_value, dfilter_fail); + fvalue = dfilter_fvalue_from_unparsed(dfw, FT_UINT8, s, allow_partial_value); if (fvalue) { FVALUE_FREE(fvalue); /* The value doees indeed fit into 8 bits. Create a BYTE_STRING * from it. Since we know that the last 2 characters are a valid * hex string, just use those directly. */ - fvalue = fvalue_from_unparsed(FT_BYTES, s+2, allow_partial_value, dfilter_fail); + fvalue = dfilter_fvalue_from_unparsed(dfw, FT_BYTES, s+2, allow_partial_value); } } else { - fvalue = fvalue_from_unparsed(FT_BYTES, s, allow_partial_value, dfilter_fail); + fvalue = dfilter_fvalue_from_unparsed(dfw, FT_BYTES, s, allow_partial_value); } if (!fvalue) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_UNPARSED): Could not convert from string!\n")); @@ -974,7 +1002,7 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, } else if (type2 == STTYPE_RANGE) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_RANGE)\n")); - check_drange_sanity(st_arg2); + check_drange_sanity(dfw, st_arg2); } else if (type2 == STTYPE_FUNCTION) { df_func_def_t *funcdef = sttype_function_funcdef(st_arg2); @@ -982,7 +1010,7 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, if (!is_bytes_type(ftype2)) { if (!ftype_can_slice(ftype2)) { - dfilter_fail("Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.", + dfilter_fail(dfw, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.", funcdef->name, ftype_pretty_name(ftype2)); THROW(TypeError); @@ -994,7 +1022,7 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, sttype_test_set2_args(st_node, st_arg1, new_st); } - check_function(st_arg2); + check_function(dfw, st_arg2); } else { g_assert_not_reached(); @@ -1002,7 +1030,7 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, } static stnode_t* -check_param_entity(stnode_t *st_node) +check_param_entity(dfwork_t *dfw, stnode_t *st_node) { sttype_id_t e_type; stnode_t *new_st; @@ -1013,7 +1041,7 @@ check_param_entity(stnode_t *st_node) /* If there's an unparsed string, change it to an FT_STRING */ if (e_type == STTYPE_UNPARSED) { s = (char*)stnode_data(st_node); - fvalue = fvalue_from_unparsed(FT_STRING, s, FALSE, dfilter_fail); + fvalue = dfilter_fvalue_from_unparsed(dfw, FT_STRING, s, FALSE); if (!fvalue) { THROW(TypeError); } @@ -1029,7 +1057,8 @@ check_param_entity(stnode_t *st_node) /* If the LHS of a relation test is a FUNCTION, run some checks * and possibly some modifications of syntax tree nodes. */ static void -check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func, +check_relation_LHS_FUNCTION(dfwork_t *dfw, const char *relation_string, + FtypeCanFunc can_func, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { @@ -1043,7 +1072,7 @@ check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func, df_func_def_t *funcdef2; /* GSList *params; */ - check_function(st_arg1); + check_function(dfw, st_arg1); type2 = stnode_type_id(st_arg2); funcdef = sttype_function_funcdef(st_arg1); @@ -1054,7 +1083,7 @@ check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func, DebugLog((" 5 check_relation_LHS_FUNCTION(%s)\n", relation_string)); if (!can_func(ftype1)) { - dfilter_fail("Function %s (type=%s) cannot participate in '%s' comparison.", + dfilter_fail(dfw, "Function %s (type=%s) cannot participate in '%s' comparison.", funcdef->name, ftype_pretty_name(ftype1), relation_string); THROW(TypeError); @@ -1065,14 +1094,14 @@ check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func, ftype2 = hfinfo2->type; if (!compatible_ftypes(ftype1, ftype2)) { - dfilter_fail("Function %s and %s are not of compatible types.", + dfilter_fail(dfw, "Function %s and %s are not of compatible types.", funcdef->name, hfinfo2->abbrev); THROW(TypeError); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { - dfilter_fail("%s (type=%s) cannot participate in specified comparison.", + dfilter_fail(dfw, "%s (type=%s) cannot participate in specified comparison.", hfinfo2->abbrev, ftype_pretty_name(ftype2)); THROW(TypeError); } @@ -1081,9 +1110,9 @@ check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func, s = (char*)stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ - fvalue = fvalue_from_string(FT_PCRE, s, dfilter_fail); + fvalue = dfilter_fvalue_from_string(dfw, FT_PCRE, s); } else { - fvalue = fvalue_from_string(ftype1, s, dfilter_fail); + fvalue = dfilter_fvalue_from_string(dfw, ftype1, s); } if (!fvalue) { THROW(TypeError); @@ -1097,9 +1126,9 @@ check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func, s = (char*)stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ - fvalue = fvalue_from_unparsed(FT_PCRE, s, FALSE, dfilter_fail); + fvalue = dfilter_fvalue_from_unparsed(dfw, FT_PCRE, s, FALSE); } else { - fvalue = fvalue_from_unparsed(ftype1, s, allow_partial_value, dfilter_fail); + fvalue = dfilter_fvalue_from_unparsed(dfw, ftype1, s, allow_partial_value); } if (!fvalue) { THROW(TypeError); @@ -1110,10 +1139,10 @@ check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func, stnode_free(st_arg2); } else if (type2 == STTYPE_RANGE) { - check_drange_sanity(st_arg2); + check_drange_sanity(dfw, st_arg2); if (!is_bytes_type(ftype1)) { if (!ftype_can_slice(ftype1)) { - dfilter_fail("Function \"%s\" is a %s and cannot be converted into a sequence of bytes.", + dfilter_fail(dfw, "Function \"%s\" is a %s and cannot be converted into a sequence of bytes.", funcdef->name, ftype_pretty_name(ftype1)); THROW(TypeError); @@ -1130,7 +1159,7 @@ check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func, ftype2 = funcdef2->retval_ftype; if (!compatible_ftypes(ftype1, ftype2)) { - dfilter_fail("Return values of function %s (type=%s) and function %s (type=%s) are not of compatible types.", + dfilter_fail(dfw, "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)); THROW(TypeError); } @@ -1138,12 +1167,12 @@ check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func, /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { - dfilter_fail("Return value of %s (type=%s) cannot participate in specified comparison.", + dfilter_fail(dfw, "Return value of %s (type=%s) cannot participate in specified comparison.", funcdef2->name, ftype_pretty_name(ftype2)); THROW(TypeError); } - check_function(st_arg2); + check_function(dfw, st_arg2); } else { g_assert_not_reached(); @@ -1153,7 +1182,8 @@ check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func, /* Check the semantics of any relational test. */ static void -check_relation(const char *relation_string, gboolean allow_partial_value, +check_relation(dfwork_t *dfw, const char *relation_string, + gboolean allow_partial_value, FtypeCanFunc can_func, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { @@ -1173,30 +1203,30 @@ header_field_info *hfinfo; if (stnode_type_id(st_arg2) == STTYPE_FIELD) { hfinfo = (header_field_info*)stnode_data(st_arg2); if (hfinfo->type == FT_PROTOCOL) { - dfilter_fail("Protocol (\"%s\") cannot appear on right-hand side of comparison.", hfinfo->abbrev); + dfilter_fail(dfw, "Protocol (\"%s\") cannot appear on right-hand side of comparison.", hfinfo->abbrev); THROW(TypeError); } } switch (stnode_type_id(st_arg1)) { case STTYPE_FIELD: - check_relation_LHS_FIELD(relation_string, can_func, + check_relation_LHS_FIELD(dfw, relation_string, can_func, allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_STRING: - check_relation_LHS_STRING(relation_string, can_func, + check_relation_LHS_STRING(dfw, relation_string, can_func, allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_RANGE: - check_relation_LHS_RANGE(relation_string, can_func, + check_relation_LHS_RANGE(dfw, relation_string, can_func, allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_UNPARSED: - check_relation_LHS_UNPARSED(relation_string, can_func, + check_relation_LHS_UNPARSED(dfw, relation_string, can_func, allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_FUNCTION: - check_relation_LHS_FUNCTION(relation_string, can_func, + check_relation_LHS_FUNCTION(dfw, relation_string, can_func, allow_partial_value, st_node, st_arg1, st_arg2); break; @@ -1211,7 +1241,7 @@ header_field_info *hfinfo; /* Check the semantics of any type of TEST */ static void -check_test(stnode_t *st_node, GPtrArray *deprecated) +check_test(dfwork_t *dfw, stnode_t *st_node, GPtrArray *deprecated) { test_op_t st_op, st_arg_op; stnode_t *st_arg1, *st_arg2; @@ -1229,11 +1259,11 @@ check_test(stnode_t *st_node, GPtrArray *deprecated) break; case TEST_OP_EXISTS: - check_exists(st_arg1); + check_exists(dfw, st_arg1); break; case TEST_OP_NOT: - semcheck(st_arg1, deprecated); + semcheck(dfw, st_arg1, deprecated); break; case TEST_OP_AND: @@ -1254,36 +1284,36 @@ check_test(stnode_t *st_node, GPtrArray *deprecated) } } - semcheck(st_arg1, deprecated); - semcheck(st_arg2, deprecated); + semcheck(dfw, st_arg1, deprecated); + semcheck(dfw, st_arg2, deprecated); break; case TEST_OP_EQ: - check_relation("==", FALSE, ftype_can_eq, st_node, st_arg1, st_arg2); + check_relation(dfw, "==", FALSE, ftype_can_eq, st_node, st_arg1, st_arg2); break; case TEST_OP_NE: - check_relation("!=", FALSE, ftype_can_ne, st_node, st_arg1, st_arg2); + check_relation(dfw, "!=", FALSE, ftype_can_ne, st_node, st_arg1, st_arg2); break; case TEST_OP_GT: - check_relation(">", FALSE, ftype_can_gt, st_node, st_arg1, st_arg2); + check_relation(dfw, ">", FALSE, ftype_can_gt, st_node, st_arg1, st_arg2); break; case TEST_OP_GE: - check_relation(">=", FALSE, ftype_can_ge, st_node, st_arg1, st_arg2); + check_relation(dfw, ">=", FALSE, ftype_can_ge, st_node, st_arg1, st_arg2); break; case TEST_OP_LT: - check_relation("<", FALSE, ftype_can_lt, st_node, st_arg1, st_arg2); + check_relation(dfw, "<", FALSE, ftype_can_lt, st_node, st_arg1, st_arg2); break; case TEST_OP_LE: - check_relation("<=", FALSE, ftype_can_le, st_node, st_arg1, st_arg2); + check_relation(dfw, "<=", FALSE, ftype_can_le, st_node, st_arg1, st_arg2); break; case TEST_OP_BITWISE_AND: - check_relation("&", FALSE, ftype_can_bitwise_and, st_node, st_arg1, st_arg2); + check_relation(dfw, "&", FALSE, ftype_can_bitwise_and, st_node, st_arg1, st_arg2); break; case TEST_OP_CONTAINS: - check_relation("contains", TRUE, ftype_can_contains, st_node, st_arg1, st_arg2); + check_relation(dfw, "contains", TRUE, ftype_can_contains, st_node, st_arg1, st_arg2); break; case TEST_OP_MATCHES: - check_relation("matches", TRUE, ftype_can_matches, st_node, st_arg1, st_arg2); break; + check_relation(dfw, "matches", TRUE, ftype_can_matches, st_node, st_arg1, st_arg2); break; default: g_assert_not_reached(); @@ -1294,7 +1324,7 @@ check_test(stnode_t *st_node, GPtrArray *deprecated) /* Check the entire syntax tree. */ static void -semcheck(stnode_t *st_node, GPtrArray *deprecated) +semcheck(dfwork_t *dfw, stnode_t *st_node, GPtrArray *deprecated) { #ifdef DEBUG_dfilter static guint i = 0; @@ -1304,7 +1334,7 @@ semcheck(stnode_t *st_node, GPtrArray *deprecated) * node will be a TEST node, no matter what. So assert that. */ switch (stnode_type_id(st_node)) { case STTYPE_TEST: - check_test(st_node, deprecated); + check_test(dfw, st_node, deprecated); break; default: g_assert_not_reached(); @@ -1328,7 +1358,7 @@ dfw_semcheck(dfwork_t *dfw, GPtrArray *deprecated) * the semantic-checking, the semantic-checking code will * throw an exception if a problem is found. */ TRY { - semcheck(dfw->st_root, deprecated); + semcheck(dfw, dfw->st_root, deprecated); } CATCH(TypeError) { ok_filter = FALSE; diff --git a/epan/dfilter/sttype-function.h b/epan/dfilter/sttype-function.h index 4cd8ca43db..256fd9526a 100644 --- a/epan/dfilter/sttype-function.h +++ b/epan/dfilter/sttype-function.h @@ -22,6 +22,7 @@ #ifndef STTYPE_FUNCTION_H #define STTYPE_FUNCTION_H +#include "dfilter-int.h" #include "dfunctions.h" /* Set the parameters for a function stnode_t. */ |