On Wed, Aug 02, 2017 at 12:36:46PM +0700, Nikolay Marchuk wrote:
> * filter.h (parse_filter_action, parse_filter_expression): Add new
>  declarations.
> * filter_action.c (parse_filter_action): Add new parsing function.
> (filtering_parse_function): Use filtering_parse instead of
> parse_qualify_filter.
> * filter_expression.c (parse_filter_expression): Implement parsing of filter
>  expression.
> (add_variable_token, add_operator_token, parse_operator, unescape_argument): 
> Add
>  helper functions.
> * filter_parse.c: New file.
> * filter_qualify.c (parse_read, parse_write, qualify_signals, parse_trace,
>  parse_abbrev, parse_verbose, parse_raw, parse_inject_common, parse_fault,
>  parse_inject): Use new parsing API.
> * strace.c (init): Use filtering_parse instead of parse_qualify_filter.
> * Makefile.am (strace_SOURCES): Add filter_parse.c.
> * defs.h (filtering_parse): Use common parsing function.
> ---
>  Makefile.am         |   1 +
>  defs.h              |   2 +-
>  filter.h            |   5 ++
>  filter_action.c     |  13 +++-
>  filter_expression.c | 218 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  filter_parse.c      | 188 ++++++++++++++++++++++++++++++++++++++++++++
>  filter_qualify.c    |  94 ++++++++++++----------
>  strace.c            |   6 +-
>  8 files changed, 480 insertions(+), 47 deletions(-)
>  create mode 100644 filter_parse.c
> 
> diff --git a/Makefile.am b/Makefile.am
> index 0cc698a..ab4fdf6 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -134,6 +134,7 @@ strace_SOURCES =  \
>       file_ioctl.c    \
>       filter_action.c \
>       filter_expression.c \
> +     filter_parse.c  \
>       filter_qualify.c \
>       filter.c        \
>       filter.h        \
> diff --git a/defs.h b/defs.h
> index 491664a..a2a1c9f 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -682,7 +682,7 @@ extern struct number_set signal_set;
>  extern bool is_number_in_set(unsigned int number, const struct number_set *);
>  extern void filtering_parsing_finish(void);
>  extern void filter_syscall(struct tcb *);
> -extern void parse_qualify_filter(const char *);
> +extern void filtering_parse(const char *);
>  
>  #define DECL_IOCTL(name)                                             \
>  extern int                                                           \
> diff --git a/filter.h b/filter.h
> index ead8387..933c301 100644
> --- a/filter.h
> +++ b/filter.h
> @@ -55,6 +55,7 @@ void set_filters_qualify_mode(struct filter **, unsigned 
> int *nfilters);
>  /* filter action api */
>  struct filter *create_filter(struct filter_action *, const char *name);
>  struct filter_action *find_or_add_action(const char *);
> +void parse_filter_action(const char *, const char *, const char *);
>  void *get_filter_action_priv_data(struct filter_action *);
>  void set_filter_action_priv_data(struct filter_action *, void *);
>  void set_qualify_mode(struct filter_action *);
> @@ -63,5 +64,9 @@ void set_qualify_mode(struct filter_action *);
>  struct bool_expression *create_expression();
>  bool run_expression(struct bool_expression *, bool *, unsigned int);
>  void set_expression_qualify_mode(struct bool_expression *);
> +void parse_filter_expression(struct bool_expression *, const char *,
> +                          struct filter_action *, unsigned int);
> +
> +void parse_qualify_action(const char *, const char *, const char *);
>  
>  #endif
> diff --git a/filter_action.c b/filter_action.c
> index 74a2d29..5143bf3 100644
> --- a/filter_action.c
> +++ b/filter_action.c
> @@ -120,7 +120,7 @@ filtering_parsing_finish(void)
>  
>       /* Init trace action if pathtracing is enabled */
>       if (tracing_paths && (default_flags & QUAL_TRACE)) {
> -             parse_qualify_filter("trace=all");
> +             filtering_parse("trace=all");
>       }
>  
>       /* Sort actions by priority */
> @@ -200,6 +200,17 @@ find_or_add_action(const char *name)
>       return add_action(type);
>  }
>  
> +void
> +parse_filter_action(const char *action_name, const char *expr, const char 
> *args)
> +{
> +     struct filter_action *action = find_or_add_action(action_name);
> +     parse_filter_expression(action->expr, expr, action, action->nfilters);
> +     if (args && action->type->parse_args == &parse_null)
> +             error_msg("%s action takes no arguments: '%s'",
> +                       action->type->name, args);
> +     action->_priv_data = action->type->parse_args(args);
> +}
> +
>  static void
>  run_filter_action(struct tcb *tcp, struct filter_action *action)
>  {
> diff --git a/filter_expression.c b/filter_expression.c
> index 5dc5e41..115cab7 100644
> --- a/filter_expression.c
> +++ b/filter_expression.c
> @@ -26,6 +26,16 @@
>   */
>  
>  #include "defs.h"
> +#include "filter.h"
> +
> +extern bool is_space_ascii(char);
> +
> +static bool
> +is_allowed_in_name(char c)
> +{
> +     return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
> +            || (c >= '0' && c <= '9') || (c == '_');
> +}
>  
>  struct expression_token {
>       enum token_type {
> @@ -41,6 +51,8 @@ struct expression_token {
>               } operator_id;
>       } data;
>  };
> +/* Pseudo-operator for parsing */
> +#define OP_PARENTHESIS 3
>  
>  struct bool_expression {
>       unsigned int ntokens;
> @@ -69,6 +81,25 @@ reallocate_expression(struct bool_expression *const expr,
>       expr->ntokens = new_ntokens;
>  }
>  
> +static void
> +add_variable_token(struct bool_expression *expr, unsigned int id)
> +{
> +     struct expression_token token;
> +     token.type = TOK_VARIABLE;
> +     token.data.variable_id = id;
> +     reallocate_expression(expr, expr->ntokens + 1);
> +     expr->tokens[expr->ntokens - 1] = token;
> +}
> +
> +static void
> +add_operator_token(struct bool_expression *expr, int op) {
> +     struct expression_token token;
> +     token.type = TOK_OPERATOR;
> +     token.data.operator_id = op;
> +     reallocate_expression(expr, expr->ntokens + 1);
> +     expr->tokens[expr->ntokens - 1] = token;
> +}
> +
>  void
>  set_expression_qualify_mode(struct bool_expression *expr)
>  {
> @@ -212,3 +243,190 @@ run_expression(struct bool_expression *expr, bool 
> *variables,
>                                           variables, variables_num);
>       return stack[0];
>  }
> +
> +/*
> + * Parse operator and add operator length to str and pos.
> + * Return -1 if no operator found.
> + */
> +static int
> +parse_operator(char **str, unsigned int *pos)
> +{
> +#define _OP(s, op) { s, sizeof(s) - 1, op }
> +     struct {
> +             const char *str;
> +             int len;
> +             enum operator_type op;
> +     } ops[] = {
> +             _OP("!",        OP_NOT),
> +             _OP("not",      OP_NOT),
> +             _OP("&&",       OP_AND),
> +             _OP("and",      OP_AND),
> +             _OP("||",       OP_OR),
> +             _OP("or",       OP_OR)
> +     };
> +#undef _OP
> +     char *p = *str;
> +     unsigned int i;
> +
> +     for (i = 0; i < ARRAY_SIZE(ops); i++) {
> +             if (!strncmp(p, ops[i].str, ops[i].len) &&
> +                 (!is_allowed_in_name(ops[i].str[0]) ||
> +                 !is_allowed_in_name(p[ops[i].len]))){
Missing space before opening curly brace.

> +                     *str += ops[i].len - 1;
> +                     *pos += ops[i].len - 1;
> +                     return ops[i].op;
> +             }
> +     }
> +     return -1;
> +}
> +
> +static char *
> +unescape_argument(char **str)
> +{
> +     char *p;
> +     char *p_new;
> +     bool escaped = false;
> +     unsigned int size = 1;
> +     char *new_str = xcalloc(strlen(*str) + 1, sizeof(char));
Missing empty line after declarations.

> +     for (p = *str, p_new = new_str; *p; ++p) {
> +             if (!escaped) {
> +                     if (*p == '\\') {
> +                             escaped = true;
> +                             continue;
> +                     } else if (is_space_ascii(*p) || *p == ')' || *p == '|'
> +                                || *p == '&') {
> +                             break;
> +                     }
> +             }
> +             escaped = false;
> +             *(p_new++) = *p;
> +             size++;
> +     }
> +     *str = p - 1;
> +     xreallocarray(new_str, size, sizeof(char));
Looks like you forgot to assign the return value of xreallocarray to new_str.

> +     return new_str;
Or just return xreallocarray(...).

> +}
> +
> +static void
> +push_operator(int *stack, unsigned int *stack_size, int op) {
Opening curly brace should be on a separate line.

> +     if (*stack_size == MAX_STACK_SIZE)
> +             error_msg_and_die("stack overflow");
> +     stack[*stack_size] = op;
> +     (*stack_size)++;
> +}
> +
> +static bool
> +is_higher_priority(int op_a, int op_b)
> +{
> +     bool op_priority[] = {
> +             [OP_NOT] = 2,
> +             [OP_AND] = 1,
> +             [OP_OR]  = 0,
> +     };
> +     return op_priority[op_a] > op_priority[op_b];
> +}
> +
> +void
> +parse_filter_expression(struct bool_expression *expr, const char *str,
> +                     struct filter_action *action, unsigned int start_id)
> +{
> +     enum {
> +             WAIT_FILTER,
> +             FILTER_NAME,
> +             FILTER_ARG,
> +             WAIT_OPERATOR
It's better to have trailing comma here.

> +     } state = WAIT_FILTER;
> +     unsigned int variable_id = start_id;
> +     /* Current stack stack_size */
> +     unsigned int st_size = 0;
> +     int stack[MAX_STACK_SIZE];
> +     char *buf = xstrdup(str);
> +     struct filter *cur_filter = NULL;
> +     char *filter_name = NULL;
> +     char *filter_arg = NULL;
> +     int op;
> +     char *p;
> +     unsigned int pos = 0;
> +
> +     for (p = buf; *p; ++p, ++pos) {
> +             switch (state) {
> +             case WAIT_FILTER:
> +                     if (*p == '(') {
> +                             push_operator(stack, &st_size, OP_PARENTHESIS);
> +                     } else if ((op = parse_operator(&p, &pos)) >= 0) {
> +                             if (op == OP_NOT) {
> +                                     push_operator(stack, &st_size, op);
> +                             } else {
> +                                     error_msg_and_die("invalid operator "
> +                                                       "at '%s':%u",
> +                                                       str, pos);
> +                             }
> +                     } else if (!is_space_ascii(*p)) {
> +                             filter_name = p;
> +                             state = FILTER_NAME;
> +                     }
> +                     break;
> +
> +             case FILTER_NAME:
> +                     if (is_space_ascii(*p)) {
> +                             *p = '\0';
> +                             cur_filter = create_filter(action, filter_name);
> +                             filter_arg = NULL;
> +                             state = FILTER_ARG;
> +                     }
> +                     break;
> +
> +             case FILTER_ARG:
> +                     if (!filter_arg && is_space_ascii(*p))
> +                             break;
> +                     filter_arg = unescape_argument(&p);
> +                     parse_filter(cur_filter, filter_arg);
> +                     free(filter_arg);
> +                     add_variable_token(expr, variable_id++);
> +                     state = WAIT_OPERATOR;
> +                     break;
> +
> +             case WAIT_OPERATOR:
> +                     if (is_space_ascii(*p))
> +                             break;
> +                     if (*p == ')') {
> +                             while ((st_size > 0) &&
> +                                    (stack[st_size - 1] != OP_PARENTHESIS)) {
> +                                             op = stack[--st_size];
> +                                             add_operator_token(expr, op);
Parentheses are discarded form RPN.

> +                                     }
> +                             if (st_size == 0)
> +                                     error_msg_and_die("unexpected ')' at "
> +                                                     "'%s':%u", str, pos);
> +                             --st_size;
> +                             break;
> +                     }
> +                     op = parse_operator(&p, &pos);
> +                     if (op < 0 || op == OP_NOT)
> +                             error_msg_and_die("invalid operator at '%s':%u",
> +                                               str, pos);
> +
> +                     /* Pop operators with higher priority. */
> +                     while ((st_size > 0) &&
> +                            is_higher_priority(stack[st_size - 1], op))
What if parenthesis is on stack? op_priority there doesn't have priority for it.

> +                             add_operator_token(expr, stack[--st_size]);
> +
> +                     push_operator(stack, &st_size, op);
> +                     state = WAIT_FILTER;
> +                     continue;
Why continue and not break?  This discrepancy will bite once some code after
switch is added.

> +             }
> +     }
> +
> +     free(buf);
> +     if (state != WAIT_OPERATOR)
> +             error_msg_and_die("unfinished filter expression '%s'", str);
> +
> +     while (st_size > 0) {
> +             if (stack[--st_size] == '(')
> +                     error_msg_and_die("missing ')' in expression '%s'",
> +                                       str);
> +             add_operator_token(expr, stack[st_size]);
Parentheses are discarded form RPN.

> +     }
> +     if (start_id > 0)
> +             add_operator_token(expr, OP_OR);
> +}
> diff --git a/filter_parse.c b/filter_parse.c
> new file mode 100644
> index 0000000..29d6861
> --- /dev/null
> +++ b/filter_parse.c
> @@ -0,0 +1,188 @@
> +/*
> + * Copyright (c) 2017 Nikolay Marchuk <marchuk.nikola...@gmail.com>
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. The name of the author may not be used to endorse or promote products
> + *    derived from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
> + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
> + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include "defs.h"
> +#include "filter.h"
> +
> +bool
> +is_space_ascii(char c)
> +{
> +     return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') ||
> +            (c == '\v') || (c == '\f');
> +}
It's quite funny that one character filter is in one file and another one in
another.

> +
> +/*
> + * Split expression into action name, filter expression or qualify set
> + * and action arguments.
> + */
> +void
> +filtering_parse(const char *str)
> +{
> +     enum parsing_states {
> +             F_EMPTY,
> +             F_BEGIN,
> +             F_QUAL_SET,
> +             F_FILT_EXPR,
> +             F_QUAL_ARGS,
> +             F_FILT_ARGS,
> +             F_END
> +     } state = F_EMPTY;
> +     const char *begin = NULL;
> +     const char *action_name = NULL;
> +     const char *main_part = NULL;
> +     const char *args = NULL;
> +     int parentheses_count = 0;
> +     /* Used to store position of last terminating parenthesis. */
> +     char *expression_end = NULL;
> +     /* Used to provide diagnostics. */
> +     unsigned int pos = 0;
> +     char *buf = xstrdup(str);
> +     char *p;
> +
> +     for (p = buf; *p; ++p, ++pos) {
> +             switch (state) {
> +             case F_EMPTY:
> +                     switch (*p) {
> +                     /* trace(), action name omitted */
> +                     case '(':
> +                             parentheses_count++;
> +                             action_name = "trace";
> +                             main_part = buf;
> +                             state = F_FILT_EXPR;
> +                             break;
> +                     case '=':
> +                             error_msg_and_die("invalid filter action ''");
> +                     default:
> +                             if (!is_space_ascii(*p)) {
> +                                     begin = p;
> +                                     state = F_BEGIN;
> +                             }
> +                     }
> +                     break;
> +
> +             case F_BEGIN:
> +                     switch (*p) {
> +                     /* action(...) */
> +                     case '(':
> +                             parentheses_count++;
> +                             action_name = begin;
> +                             *p = '\0';
> +                             main_part = p + 1;
> +                             state = F_FILT_EXPR;
> +                             break;
> +                     /* action=... */
> +                     case '=':
> +                             action_name = begin;
> +                             *p = '\0';
> +                             main_part = p + 1;
> +                             state = F_QUAL_SET;
> +                             break;
> +                     /* qualify set without action. */
> +                     case ',':
> +                     case '?':
> +                     case '!':
> +                     case '/':
> +                     case '%':
> +                     case '-':
> +                             action_name = "trace";
> +                             main_part = begin;
> +                             state = F_QUAL_SET;
> +                             break;
> +                     default:
> +                             /* new expression without action. */
> +                             if (is_space_ascii(*p)) {
> +                                     action_name = "trace";
> +                                     main_part = begin;
> +                                     state = F_FILT_EXPR;
> +                             }
> +                     }
> +                     break;
% ./strace -e '! read,mmap,mprotect' ./strace
./strace: unfinished filter expression '! read,mmap,mprotect'
% ./strace -e '/ read,mmap,mprotect' ./strace
./strace: invalid filter '/'
% ./strace -e '!! read,mmap,mprotect' ./strace 
./strace: invalid system call ' read'


> +
> +             case F_QUAL_SET:
> +                     if (*p == ':') {
> +                             *p = '\0';
> +                             args = p + 1;
> +                             state = F_QUAL_ARGS;
> +                     }
> +                     break;

> +
> +             case F_FILT_EXPR:
> +                     switch (*p) {
> +                     case ';':
> +                             *p = '\0';
> +                             args = p + 1;
> +                             state = F_FILT_ARGS;
> +                             break;
% ./strace -e 'trace(path \)\;\;)' ./strace 
./strace: trace action takes no arguments: '\;'

> +                     case '(':
> +                             parentheses_count++;
> +                             break;
% ./strace -e 'trace(path \()' ./strace 
./strace: missing ')' in 'trace(path \()'

> +                     case ')':
> +                             parentheses_count--;
> +                             expression_end = p;
> +                             break;
% ./strace -e 'trace(path \))' ./strace 
./strace: missing '(' in 'trace(path \))'

> +                     }
> +
> +             case F_QUAL_ARGS:
> +                     break;
> +             case F_FILT_ARGS:
> +                     if (*p == ')') {
> +                             expression_end = p;
> +                             state = F_END;
> +                     }
> +                     break;
> +             case F_END:
> +                     if (!is_space_ascii(*p))
> +                             error_msg_and_die("illegal character '%c' in "
> +                                               "'%s':%u", *p, str, pos);
> +             }
> +     }
> +
> +     switch (state) {
> +     case F_EMPTY:
> +             error_msg_and_die("invalid filter expression '%s'", str);
> +     case F_BEGIN:
> +             action_name = "trace";
> +             main_part = begin;
> +             /* Fallthrough */
> +     case F_QUAL_SET:
> +     case F_QUAL_ARGS:
> +             parse_qualify_action(action_name, main_part, args);
> +             break;
> +     case F_FILT_EXPR:
> +     case F_FILT_ARGS:
> +     case F_END:
> +             if (parentheses_count != 0) {
> +                     error_msg_and_die("missing '%c' in '%s'",
> +                                       parentheses_count > 0 ? ')' : '(',
> +                                       str);
> +             }
> +             if (expression_end)
> +                     *expression_end = '\0';
> +             parse_filter_action(action_name, main_part, args);
> +             break;
> +     }
> +}
> diff --git a/filter_qualify.c b/filter_qualify.c
> index 105afdf..3518d98 100644
> --- a/filter_qualify.c
> +++ b/filter_qualify.c
> @@ -181,111 +181,123 @@ parse_inject_common_args(char *str, struct 
> inject_opts *const opts,
>  }
>  
>  static void
> -parse_read(const char *const str)
> +parse_read(const char *const main_part, const char *const args)
>  {
>       struct filter_action *action = find_or_add_action("read");
>       struct filter *filter = create_filter(action, "fd");
>  
> -     parse_filter(filter, str);
> +     parse_filter(filter, main_part);
> +     if (args)
> +             error_msg("read action takes no arguments: '%s'", args);
>       set_qualify_mode(action);
>  }
>  
>  static void
> -parse_write(const char *const str)
> +parse_write(const char *const main_part, const char *const args)
>  {
>       struct filter_action *action = find_or_add_action("write");
>       struct filter *filter = create_filter(action, "fd");
>  
> -     parse_filter(filter, str);
> +     parse_filter(filter, main_part);
> +     if (args)
> +             error_msg("write action takes no arguments: '%s'", args);
>       set_qualify_mode(action);
>  }
>  
>  static void
> -qualify_signals(const char *const str)
> +qualify_signals(const char *const main_part, const char *const args)
>  {
> -     parse_set(str, &signal_set, sigstr_to_uint, "signal");
> +     parse_set(main_part, &signal_set, sigstr_to_uint, "signal");
> +     if (args)
> +             error_msg("signal action takes no arguments: '%s'", args);
>  }
>  
>  static void
> -parse_trace(const char *const str)
> +parse_trace(const char *const main_part, const char *const args)
>  {
>       struct filter_action *action = find_or_add_action("trace");
>       struct filter *filter = create_filter(action, "syscall");
>  
> -     parse_filter(filter, str);
> +     parse_filter(filter, main_part);
> +     if (args)
> +             error_msg("trace action takes no arguments: '%s'", args);
>       set_qualify_mode(action);
>  }
>  
>  static void
> -parse_abbrev(const char *const str)
> +parse_abbrev(const char *const main_part, const char *const args)
>  {
>       struct filter_action *action = find_or_add_action("abbrev");
>       struct filter *filter = create_filter(action, "syscall");
>  
> -     parse_filter(filter, str);
> +     parse_filter(filter, main_part);
> +     if (args)
> +             error_msg("abbrev action takes no arguments: '%s'", args);
>       set_qualify_mode(action);
>  }
>  
>  static void
> -parse_verbose(const char *const str)
> +parse_verbose(const char *const main_part, const char *const args)
>  {
>       struct filter_action *action = find_or_add_action("verbose");
>       struct filter *filter = create_filter(action, "syscall");
>  
> -     parse_filter(filter, str);
> +     parse_filter(filter, main_part);
> +     if (args)
> +             error_msg("verbose action takes no arguments: '%s'", args);
>       set_qualify_mode(action);
>  }
>  
>  static void
> -parse_raw(const char *const str)
> +parse_raw(const char *const main_part, const char *const args)
>  {
>       struct filter_action *action = find_or_add_action("raw");
>       struct filter *filter = create_filter(action, "syscall");
>  
> -     parse_filter(filter, str);
> +     parse_filter(filter, main_part);
> +     if (args)
> +             error_msg("raw action takes no arguments: '%s'", args);
>       set_qualify_mode(action);
>  }
>  
>  static void
> -parse_inject_common(const char *const str, const bool fault_tokens_only,
> -                 const char *const description)
> +parse_inject_common(const char *const main_part, const char *const args,
> +                 const bool fault_tokens_only, const char *const description)
>  {
>       struct inject_opts *opts = xmalloc(sizeof(struct inject_opts));
> -     char *buf = xstrdup(str);
> +     char *buf = args ? xstrdup(args) : NULL;
>       struct filter_action *action;
>       struct filter *filter;
> -     char *args = strchr(buf, ':');
> -
> -     if (args)
> -             *(args++) = '\0';
>  
>       action = find_or_add_action(fault_tokens_only ? "fault" : "inject");
>       filter = create_filter(action, "syscall");
> -     parse_filter(filter, buf);
> +     parse_filter(filter, main_part);
>       set_qualify_mode(action);
> -     parse_inject_common_args(args, opts, ":", fault_tokens_only);
> -     if (!opts->init)
> +     parse_inject_common_args(buf, opts, ":", fault_tokens_only);
> +     if (!opts->init) {
>               error_msg_and_die("invalid %s '%s'", description,
>                                 args ? args : "");
> -     free(buf);
> +     }
> +     if (buf)
> +             free(buf);
>       set_filter_action_priv_data(action, opts);
>  }
>  
>  static void
> -parse_fault(const char *const str)
> +parse_fault(const char *const main_part, const char *const args)
>  {
> -     parse_inject_common(str, true, "fault argument");
> +     parse_inject_common(main_part, args, true, "fault argument");
>  }
>  
>  static void
> -parse_inject(const char *const str)
> +parse_inject(const char *const main_part, const char *const args)
>  {
> -     parse_inject_common(str, false, "inject argument");
> +     parse_inject_common(main_part, args, false, "inject argument");
>  }
>  
>  static const struct qual_options {
>       const char *name;
> -     void (*qualify)(const char *);
> +     void (*qualify)(const char *, const char *);
>  } qual_options[] = {
>       { "trace",      parse_trace     },
>       { "t",          parse_trace     },
> @@ -309,22 +321,20 @@ static const struct qual_options {
>  };
>  
>  void
> -parse_qualify_filter(const char *str)
> +parse_qualify_action(const char *action_name, const char *main_part,
> +                  const char *args)
>  {
> -     const struct qual_options *opt = qual_options;
> +     const struct qual_options *opt = NULL;
>       unsigned int i;
>  
>       for (i = 0; i < ARRAY_SIZE(qual_options); ++i) {
> -             const char *name = qual_options[i].name;
> -             const size_t len = strlen(name);
> -             const char *val = str_strip_prefix_len(str, name, len);
> -
> -             if (val == str || *val != '=')
> -                     continue;
> -             str = val + 1;
> -             opt = &qual_options[i];
> -             break;
> +             if (!strcmp(action_name, qual_options[i].name)) {
> +                     opt = &qual_options[i];
> +                     break;
> +             }
>       }
>  
> -     opt->qualify(str);
> +     if (!opt)
> +             error_msg_and_die("invalid filter action '%s'", action_name);
> +     opt->qualify(main_part, args);
>  }
> diff --git a/strace.c b/strace.c
> index 137559c..560beea 100644
> --- a/strace.c
> +++ b/strace.c
> @@ -1648,7 +1648,7 @@ init(int argc, char *argv[])
>  #if DEFAULT_QUAL_FLAGS != (QUAL_TRACE | QUAL_ABBREV | QUAL_VERBOSE)
>  # error Bug in DEFAULT_QUAL_FLAGS
>  #endif
> -     parse_qualify_filter("signal=all");
> +     filtering_parse("signal=all");
>       while ((c = getopt(argc, argv,
>               "+b:cCdfFhiqrtTvVwxyz"
>  #ifdef USE_LIBUNWIND
> @@ -1715,7 +1715,7 @@ init(int argc, char *argv[])
>                       show_fd_path++;
>                       break;
>               case 'v':
> -                     parse_qualify_filter("abbrev=none");
> +                     filtering_parse("abbrev=none");
>                       break;
>               case 'V':
>                       print_version();
> @@ -1730,7 +1730,7 @@ init(int argc, char *argv[])
>                               error_opt_arg(c, optarg);
>                       break;
>               case 'e':
> -                     parse_qualify_filter(optarg);
> +                     filtering_parse(optarg);
>                       break;
>               case 'o':
>                       outfname = optarg;
> -- 
> 2.1.4

% ./strace -e 'fault(syscall read || syscall write;error=1)' ./strace 
./strace: missing ')' in 'fault(syscall read || syscall write;error=1)'

% ./strace -e 'fault(syscall read || syscall write);error=1' ./strace
execve("./strace", ["./strace"], 0x7ffefd028140 /* 32 vars */) = 0
...

% ./strace -e 'trace(syscall read || syscall write); stacktrace(not fd 1 or' 
./strace 
./strace: trace action takes no arguments: ' stacktrace(not fd 1 or'
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 \f\0\0\0\0\0\0"..., 
832) = 832


% valgrind --track-origins=yes ./strace -e 'trace(syscall read || 
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((syscall 
read))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))' 
./strace 
==23657== Memcheck, a memory error detector
==23657== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==23657== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==23657== Command: ./strace -e trace(syscall\ read\ ||\ 
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((syscall\ 
read)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) 
./strace
==23657== 
==23657== Invalid read of size 1
==23657==    at 0x403E90: parse_syscall_set (basic_filters.c:272)
==23657==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==23657==    by 0x40F0BC: parse_filter (filter.c:97)
==23657==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657==  Address 0x63c9380 is 0 bytes inside a block of size 155 free'd
==23657==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==23657==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==23657==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==23657==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657== 
==23657== Invalid read of size 1
==23657==    at 0x403EA1: parse_syscall_set (basic_filters.c:279)
==23657==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==23657==    by 0x40F0BC: parse_filter (filter.c:97)
==23657==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657==  Address 0x63c9380 is 0 bytes inside a block of size 155 free'd
==23657==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==23657==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==23657==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==23657==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657== 
==23657== Invalid read of size 1
==23657==    at 0x4C2C1A2: strlen (vg_replace_strmem.c:412)
==23657==    by 0x576197D: strdup (strdup.c:41)
==23657==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==23657==    by 0x403EEF: parse_syscall_set (basic_filters.c:298)
==23657==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==23657==    by 0x40F0BC: parse_filter (filter.c:97)
==23657==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657==  Address 0x63c9380 is 0 bytes inside a block of size 155 free'd
==23657==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==23657==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==23657==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==23657==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657== 
==23657== Invalid read of size 1
==23657==    at 0x4C2C1B4: strlen (vg_replace_strmem.c:412)
==23657==    by 0x576197D: strdup (strdup.c:41)
==23657==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==23657==    by 0x403EEF: parse_syscall_set (basic_filters.c:298)
==23657==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==23657==    by 0x40F0BC: parse_filter (filter.c:97)
==23657==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657==  Address 0x63c9381 is 1 bytes inside a block of size 155 free'd
==23657==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==23657==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==23657==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==23657==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657== 
==23657== Invalid read of size 2
==23657==    at 0x4C2DFA8: __GI_memcpy (vg_replace_strmem.c:917)
==23657==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==23657==    by 0x403EEF: parse_syscall_set (basic_filters.c:298)
==23657==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==23657==    by 0x40F0BC: parse_filter (filter.c:97)
==23657==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657==  Address 0x63c9380 is 0 bytes inside a block of size 155 free'd
==23657==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==23657==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==23657==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==23657==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657== 
==23657== Invalid read of size 1
==23657==    at 0x4C2DFE0: __GI_memcpy (vg_replace_strmem.c:917)
==23657==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==23657==    by 0x403EEF: parse_syscall_set (basic_filters.c:298)
==23657==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==23657==    by 0x40F0BC: parse_filter (filter.c:97)
==23657==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657==  Address 0x63c9384 is 4 bytes inside a block of size 155 free'd
==23657==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==23657==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==23657==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==23657==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657== 
==23657== Invalid free() / delete / delete[] / realloc()
==23657==    at 0x4C29E90: free (vg_replace_malloc.c:473)
==23657==    by 0x40E480: parse_filter_expression (filter_expression.c:384)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657==  Address 0x63c9380 is 0 bytes inside a block of size 155 free'd
==23657==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==23657==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==23657==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==23657==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==23657==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==23657==    by 0x42519D: init (strace.c:1688)
==23657==    by 0x40319B: main (strace.c:2622)
==23657== 
./strace: stack overflow
==23657== 
==23657== HEAP SUMMARY:
==23657==     in use at exit: 497 bytes in 12 blocks
==23657==   total heap usage: 16 allocs, 5 frees, 772 bytes allocated
==23657== 
==23657== LEAK SUMMARY:
==23657==    definitely lost: 16 bytes in 2 blocks
==23657==    indirectly lost: 0 bytes in 0 blocks
==23657==      possibly lost: 170 bytes in 1 blocks
==23657==    still reachable: 311 bytes in 9 blocks
==23657==         suppressed: 0 bytes in 0 blocks
==23657== Rerun with --leak-check=full to see details of leaked memory
==23657== 
==23657== For counts of detected and suppressed errors, rerun with: -v
==23657== ERROR SUMMARY: 11 errors from 7 contexts (suppressed: 0 from 0)



% valgrind --track-origins=yes ./strace -e 'trace(syscall read || syscall 
write)' -e 'stacktrace(not fd 1,5,3 or)' ./strace
==25664== Memcheck, a memory error detector                      
==25664== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==25664== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==25664== Command: ./strace -e trace(syscall\ read\ ||\ syscall\ write) -e 
stacktrace(not\ fd\ 1,5,3\ or) ./strace
==25664== 
==25664== Invalid read of size 1
==25664==    at 0x403E90: parse_syscall_set (basic_filters.c:272)
==25664==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9270 is 0 bytes inside a block of size 22 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid read of size 1
==25664==    at 0x403EA1: parse_syscall_set (basic_filters.c:279)
==25664==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9270 is 0 bytes inside a block of size 22 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid read of size 1
==25664==    at 0x4C2C1A2: strlen (vg_replace_strmem.c:412)
==25664==    by 0x576197D: strdup (strdup.c:41)
==25664==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==25664==    by 0x403EEF: parse_syscall_set (basic_filters.c:298)
==25664==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9270 is 0 bytes inside a block of size 22 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid read of size 1
==25664==    at 0x4C2C1B4: strlen (vg_replace_strmem.c:412)
==25664==    by 0x576197D: strdup (strdup.c:41)
==25664==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==25664==    by 0x403EEF: parse_syscall_set (basic_filters.c:298)
==25664==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9271 is 1 bytes inside a block of size 22 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid read of size 2
==25664==    at 0x4C2DFA8: __GI_memcpy (vg_replace_strmem.c:917)
==25664==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==25664==    by 0x403EEF: parse_syscall_set (basic_filters.c:298)
==25664==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9270 is 0 bytes inside a block of size 22 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid read of size 1
==25664==    at 0x4C2DFE0: __GI_memcpy (vg_replace_strmem.c:917)
==25664==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==25664==    by 0x403EEF: parse_syscall_set (basic_filters.c:298)
==25664==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9274 is 4 bytes inside a block of size 22 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid free() / delete / delete[] / realloc()
==25664==    at 0x4C29E90: free (vg_replace_malloc.c:473)
==25664==    by 0x40E480: parse_filter_expression (filter_expression.c:384)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9270 is 0 bytes inside a block of size 22 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid read of size 2
==25664==    at 0x4C2DFB6: __GI_memcpy (vg_replace_strmem.c:917)
==25664==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==25664==    by 0x403EEF: parse_syscall_set (basic_filters.c:298)
==25664==    by 0x404395: parse_syscall_filter (basic_filters.c:324)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9584 is 4 bytes inside a block of size 6 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid read of size 1
==25664==    at 0x404450: parse_set (basic_filters.c:366)
==25664==    by 0x404619: parse_fd_filter (basic_filters.c:417)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9a70 is 0 bytes inside a block of size 9 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid read of size 1
==25664==    at 0x404461: parse_set (basic_filters.c:371)
==25664==    by 0x404619: parse_fd_filter (basic_filters.c:417)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9a70 is 0 bytes inside a block of size 9 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid read of size 1
==25664==    at 0x4C2C1A2: strlen (vg_replace_strmem.c:412)
==25664==    by 0x576197D: strdup (strdup.c:41)
==25664==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==25664==    by 0x4044A7: parse_set (basic_filters.c:389)
==25664==    by 0x404619: parse_fd_filter (basic_filters.c:417)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9a70 is 0 bytes inside a block of size 9 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid read of size 1
==25664==    at 0x4C2C1B4: strlen (vg_replace_strmem.c:412)
==25664==    by 0x576197D: strdup (strdup.c:41)
==25664==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==25664==    by 0x4044A7: parse_set (basic_filters.c:389)
==25664==    by 0x404619: parse_fd_filter (basic_filters.c:417)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9a71 is 1 bytes inside a block of size 9 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid read of size 2
==25664==    at 0x4C2DFA8: __GI_memcpy (vg_replace_strmem.c:917)
==25664==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==25664==    by 0x4044A7: parse_set (basic_filters.c:389)
==25664==    by 0x404619: parse_fd_filter (basic_filters.c:417)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9a70 is 0 bytes inside a block of size 9 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
==25664== Invalid read of size 2
==25664==    at 0x4C2DFB6: __GI_memcpy (vg_replace_strmem.c:917)
==25664==    by 0x42EFA8: xstrdup (xmalloc.c:92)
==25664==    by 0x4044A7: parse_set (basic_filters.c:389)
==25664==    by 0x404619: parse_fd_filter (basic_filters.c:417)
==25664==    by 0x40F0BC: parse_filter (filter.c:97)
==25664==    by 0x40E478: parse_filter_expression (filter_expression.c:383)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664==  Address 0x63c9a74 is 4 bytes inside a block of size 9 free'd
==25664==    at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==25664==    by 0x42EF84: xreallocarray (xmalloc.c:81)
==25664==    by 0x40E46C: unescape_argument (filter_expression.c:306)
==25664==    by 0x40E46C: parse_filter_expression (filter_expression.c:382)
==25664==    by 0x40D9E3: parse_filter_action (filter_action.c:225)
==25664==    by 0x42519D: init (strace.c:1688)
==25664==    by 0x40319B: main (strace.c:2622)
==25664== 
./strace: unfinished filter expression 'not fd 1,5,3 or'
==25664== 
==25664== HEAP SUMMARY:
==25664==     in use at exit: 449 bytes in 23 blocks
==25664==   total heap usage: 38 allocs, 18 frees, 792 bytes allocated
==25664== 
==25664== LEAK SUMMARY:
==25664==    definitely lost: 65 bytes in 5 blocks
==25664==    indirectly lost: 0 bytes in 0 blocks
==25664==      possibly lost: 28 bytes in 1 blocks
==25664==    still reachable: 356 bytes in 17 blocks
==25664==         suppressed: 0 bytes in 0 blocks
==25664== Rerun with --leak-check=full to see details of leaked memory
==25664== 
==25664== For counts of detected and suppressed errors, rerun with: -v
==25664== ERROR SUMMARY: 35 errors from 14 contexts (suppressed: 0 from 0)


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Strace-devel mailing list
Strace-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/strace-devel

Reply via email to