diff --git a/cmd-parse.y b/cmd-parse.y index 9f415c224..95159e86c 100644 --- a/cmd-parse.y +++ b/cmd-parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-parse.y,v 1.62 2026/10/08 06:29:32 nicm Exp $ */ +/* $OpenBSD: cmd-parse.y,v 1.63 2026/10/08 06:44:16 nicm Exp $ */ /* * Copyright (c) 2019 Nicholas Marriott @@ -69,6 +69,22 @@ struct cmd_parse_command { }; TAILQ_HEAD(cmd_parse_commands, cmd_parse_command); +enum cmd_parse_value_type { + CMD_PARSE_VALUE_STRING, + CMD_PARSE_VALUE_ARGUMENT, + CMD_PARSE_VALUE_ARGUMENTS, + CMD_PARSE_VALUE_COMMAND, + CMD_PARSE_VALUE_COMMANDS +}; + +struct cmd_parse_owned_value { + enum cmd_parse_value_type type; + void *value; + + TAILQ_ENTRY(cmd_parse_owned_value) entry; +}; +TAILQ_HEAD(cmd_parse_owned_values, cmd_parse_owned_value); + struct cmd_parse_state { FILE *f; @@ -87,10 +103,16 @@ struct cmd_parse_state { struct cmd_parse_scope *scope; TAILQ_HEAD(, cmd_parse_scope) stack; + + struct cmd_parse_owned_values values; }; static struct cmd_parse_state parse_state; static char *cmd_parse_get_error(const char *, u_int, const char *); +static void *cmd_parse_own(enum cmd_parse_value_type, void *); +static struct cmd_parse_commands *cmd_parse_own_commands(void); +static void *cmd_parse_take(void *); +static void cmd_parse_drop(void *); static void cmd_parse_free_command(struct cmd_parse_command *); static struct cmd_parse_commands *cmd_parse_new_commands(void); static void cmd_parse_free_commands(struct cmd_parse_commands *); @@ -139,7 +161,7 @@ lines : /* empty */ { struct cmd_parse_state *ps = &parse_state; - ps->commands = $1; + ps->commands = cmd_parse_take($1); } statements : statement '\n' @@ -150,18 +172,16 @@ statements : statement '\n' { $$ = $1; TAILQ_CONCAT($$, $2, entry); - free($2); + cmd_parse_drop($2); } statement : /* empty */ { - $$ = xmalloc (sizeof *$$); - TAILQ_INIT($$); + $$ = cmd_parse_own_commands(); } | hidden_assignment { - $$ = xmalloc (sizeof *$$); - TAILQ_INIT($$); + $$ = cmd_parse_own_commands(); } | condition { @@ -170,8 +190,8 @@ statement : /* empty */ if (ps->scope == NULL || ps->scope->flag) $$ = $1; else { - $$ = cmd_parse_new_commands(); - cmd_parse_free_commands($1); + $$ = cmd_parse_own_commands(); + cmd_parse_drop($1); } } | commands @@ -181,8 +201,8 @@ statement : /* empty */ if (ps->scope == NULL || ps->scope->flag) $$ = $1; else { - $$ = cmd_parse_new_commands(); - cmd_parse_free_commands($1); + $$ = cmd_parse_own_commands(); + cmd_parse_drop($1); } } @@ -204,6 +224,7 @@ expanded : format struct cmd_find_state *fsp; struct cmd_find_state fs; int flags = FORMAT_NOJOBS; + char *expanded; if (cmd_find_valid_state(&pi->fs)) fsp = &pi->fs; @@ -214,9 +235,10 @@ expanded : format ft = format_create(c, pi->item, FORMAT_NONE, flags); format_defaults(ft, c, fsp->s, fsp->wl, fsp->wp); - $$ = format_expand(ft, $1); + expanded = format_expand(ft, $1); + $$ = cmd_parse_own(CMD_PARSE_VALUE_STRING, expanded); format_free(ft); - free($1); + cmd_parse_drop($1); } optional_assignment : /* empty */ @@ -241,7 +263,7 @@ assignment : EQUALS } if ((~flags & CMD_PARSE_PARSEONLY) && flag) environ_put(global_environ, $1, 0); - free($1); + cmd_parse_drop($1); } hidden_assignment : HIDDEN EQUALS @@ -263,7 +285,7 @@ hidden_assignment : HIDDEN EQUALS } if ((~flags & CMD_PARSE_PARSEONLY) && flag) environ_put(global_environ, $2, ENVIRON_HIDDEN); - free($2); + cmd_parse_drop($2); } if_open : IF expanded @@ -274,7 +296,7 @@ if_open : IF expanded scope = xmalloc(sizeof *scope); $$ = scope->flag = format_true($2); scope->taken = scope->flag; - free($2); + cmd_parse_drop($2); if (ps->scope != NULL) TAILQ_INSERT_HEAD(&ps->stack, ps->scope, entry); @@ -303,7 +325,7 @@ if_elif : ELIF expanded scope->flag = !ps->scope->taken && format_true($2); scope->taken = ps->scope->taken || scope->flag; $$ = scope->flag; - free($2); + cmd_parse_drop($2); free(ps->scope); ps->scope = scope; @@ -324,48 +346,48 @@ condition : if_open '\n' statements if_close if ($1) $$ = $3; else { - $$ = cmd_parse_new_commands(); - cmd_parse_free_commands($3); + $$ = cmd_parse_own_commands(); + cmd_parse_drop($3); } } | if_open '\n' statements if_else '\n' statements if_close { if ($1) { $$ = $3; - cmd_parse_free_commands($6); + cmd_parse_drop($6); } else { $$ = $6; - cmd_parse_free_commands($3); + cmd_parse_drop($3); } } | if_open '\n' statements elif if_close { if ($1) { $$ = $3; - cmd_parse_free_commands($4.commands); + cmd_parse_drop($4.commands); } else if ($4.flag) { $$ = $4.commands; - cmd_parse_free_commands($3); + cmd_parse_drop($3); } else { - $$ = cmd_parse_new_commands(); - cmd_parse_free_commands($3); - cmd_parse_free_commands($4.commands); + $$ = cmd_parse_own_commands(); + cmd_parse_drop($3); + cmd_parse_drop($4.commands); } } | if_open '\n' statements elif if_else '\n' statements if_close { if ($1) { $$ = $3; - cmd_parse_free_commands($4.commands); - cmd_parse_free_commands($7); + cmd_parse_drop($4.commands); + cmd_parse_drop($7); } else if ($4.flag) { $$ = $4.commands; - cmd_parse_free_commands($3); - cmd_parse_free_commands($7); + cmd_parse_drop($3); + cmd_parse_drop($7); } else { $$ = $7; - cmd_parse_free_commands($3); - cmd_parse_free_commands($4.commands); + cmd_parse_drop($3); + cmd_parse_drop($4.commands); } } @@ -376,8 +398,8 @@ elif : if_elif '\n' statements $$.commands = $3; } else { $$.flag = 0; - $$.commands = cmd_parse_new_commands(); - cmd_parse_free_commands($3); + $$.commands = cmd_parse_own_commands(); + cmd_parse_drop($3); } } | if_elif '\n' statements elif @@ -385,16 +407,16 @@ elif : if_elif '\n' statements if ($1) { $$.flag = 1; $$.commands = $3; - cmd_parse_free_commands($4.commands); + cmd_parse_drop($4.commands); } else if ($4.flag) { $$.flag = 1; $$.commands = $4.commands; - cmd_parse_free_commands($3); + cmd_parse_drop($3); } else { $$.flag = 0; - $$.commands = cmd_parse_new_commands(); - cmd_parse_free_commands($3); - cmd_parse_free_commands($4.commands); + $$.commands = cmd_parse_own_commands(); + cmd_parse_drop($3); + cmd_parse_drop($4.commands); } } @@ -402,12 +424,13 @@ commands : command { struct cmd_parse_state *ps = &parse_state; - $$ = cmd_parse_new_commands(); + $$ = cmd_parse_own_commands(); if (!TAILQ_EMPTY(&$1->arguments) && - (ps->scope == NULL || ps->scope->flag)) + (ps->scope == NULL || ps->scope->flag)) { + cmd_parse_take($1); TAILQ_INSERT_TAIL($$, $1, entry); - else - cmd_parse_free_command($1); + } else + cmd_parse_drop($1); } | commands ';' { @@ -417,7 +440,7 @@ commands : command { $$ = $1; TAILQ_CONCAT($$, $3, entry); - free($3); + cmd_parse_drop($3); } | commands ';' command { @@ -426,9 +449,10 @@ commands : command $$ = $1; if (!TAILQ_EMPTY(&$3->arguments) && (ps->scope == NULL || ps->scope->flag)) { + cmd_parse_take($3); TAILQ_INSERT_TAIL($$, $3, entry); } else - cmd_parse_free_command($3); + cmd_parse_drop($3); } | condition1 { @@ -442,6 +466,7 @@ command : assignment $$ = xcalloc(1, sizeof *$$); $$->line = ps->input->line; TAILQ_INIT(&$$->arguments); + cmd_parse_own(CMD_PARSE_VALUE_COMMAND, $$); } | optional_assignment TOKEN { @@ -454,8 +479,9 @@ command : assignment arg = xcalloc(1, sizeof *arg); arg->type = CMD_PARSE_STRING; - arg->string = $2; + arg->string = cmd_parse_take($2); TAILQ_INSERT_HEAD(&$$->arguments, arg, entry); + cmd_parse_own(CMD_PARSE_VALUE_COMMAND, $$); } | optional_assignment TOKEN arguments { @@ -467,12 +493,13 @@ command : assignment TAILQ_INIT(&$$->arguments); TAILQ_CONCAT(&$$->arguments, $3, entry); - free($3); + cmd_parse_drop($3); arg = xcalloc(1, sizeof *arg); arg->type = CMD_PARSE_STRING; - arg->string = $2; + arg->string = cmd_parse_take($2); TAILQ_INSERT_HEAD(&$$->arguments, arg, entry); + cmd_parse_own(CMD_PARSE_VALUE_COMMAND, $$); } condition1 : if_open commands if_close @@ -480,48 +507,48 @@ condition1 : if_open commands if_close if ($1) $$ = $2; else { - $$ = cmd_parse_new_commands(); - cmd_parse_free_commands($2); + $$ = cmd_parse_own_commands(); + cmd_parse_drop($2); } } | if_open commands if_else commands if_close { if ($1) { $$ = $2; - cmd_parse_free_commands($4); + cmd_parse_drop($4); } else { $$ = $4; - cmd_parse_free_commands($2); + cmd_parse_drop($2); } } | if_open commands elif1 if_close { if ($1) { $$ = $2; - cmd_parse_free_commands($3.commands); + cmd_parse_drop($3.commands); } else if ($3.flag) { $$ = $3.commands; - cmd_parse_free_commands($2); + cmd_parse_drop($2); } else { - $$ = cmd_parse_new_commands(); - cmd_parse_free_commands($2); - cmd_parse_free_commands($3.commands); + $$ = cmd_parse_own_commands(); + cmd_parse_drop($2); + cmd_parse_drop($3.commands); } } | if_open commands elif1 if_else commands if_close { if ($1) { $$ = $2; - cmd_parse_free_commands($3.commands); - cmd_parse_free_commands($5); + cmd_parse_drop($3.commands); + cmd_parse_drop($5); } else if ($3.flag) { $$ = $3.commands; - cmd_parse_free_commands($2); - cmd_parse_free_commands($5); + cmd_parse_drop($2); + cmd_parse_drop($5); } else { $$ = $5; - cmd_parse_free_commands($2); - cmd_parse_free_commands($3.commands); + cmd_parse_drop($2); + cmd_parse_drop($3.commands); } } @@ -532,8 +559,8 @@ elif1 : if_elif commands $$.commands = $2; } else { $$.flag = 0; - $$.commands = cmd_parse_new_commands(); - cmd_parse_free_commands($2); + $$.commands = cmd_parse_own_commands(); + cmd_parse_drop($2); } } | if_elif commands elif1 @@ -541,16 +568,16 @@ elif1 : if_elif commands if ($1) { $$.flag = 1; $$.commands = $2; - cmd_parse_free_commands($3.commands); + cmd_parse_drop($3.commands); } else if ($3.flag) { $$.flag = 1; $$.commands = $3.commands; - cmd_parse_free_commands($2); + cmd_parse_drop($2); } else { $$.flag = 0; - $$.commands = cmd_parse_new_commands(); - cmd_parse_free_commands($2); - cmd_parse_free_commands($3.commands); + $$.commands = cmd_parse_own_commands(); + cmd_parse_drop($2); + cmd_parse_drop($3.commands); } } @@ -559,10 +586,13 @@ arguments : argument $$ = xcalloc(1, sizeof *$$); TAILQ_INIT($$); + cmd_parse_take($1); TAILQ_INSERT_HEAD($$, $1, entry); + cmd_parse_own(CMD_PARSE_VALUE_ARGUMENTS, $$); } | argument arguments { + cmd_parse_take($1); TAILQ_INSERT_HEAD($2, $1, entry); $$ = $2; } @@ -571,19 +601,22 @@ argument : TOKEN { $$ = xcalloc(1, sizeof *$$); $$->type = CMD_PARSE_STRING; - $$->string = $1; + $$->string = cmd_parse_take($1); + cmd_parse_own(CMD_PARSE_VALUE_ARGUMENT, $$); } | EQUALS { $$ = xcalloc(1, sizeof *$$); $$->type = CMD_PARSE_STRING; - $$->string = $1; + $$->string = cmd_parse_take($1); + cmd_parse_own(CMD_PARSE_VALUE_ARGUMENT, $$); } | '{' argument_statements { $$ = xcalloc(1, sizeof *$$); $$->type = CMD_PARSE_COMMANDS; - $$->commands = $2; + $$->commands = cmd_parse_take($2); + cmd_parse_own(CMD_PARSE_VALUE_ARGUMENT, $$); } argument_statements : statement '}' @@ -594,7 +627,7 @@ argument_statements : statement '}' { $$ = $1; TAILQ_CONCAT($$, $2, entry); - free($2); + cmd_parse_drop($2); } %% @@ -683,22 +716,116 @@ cmd_parse_free_commands(struct cmd_parse_commands *cmds) free(cmds); } +static void * +cmd_parse_own(enum cmd_parse_value_type type, void *value) +{ + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_owned_value *v; + + v = xmalloc(sizeof *v); + v->type = type; + v->value = value; + TAILQ_INSERT_TAIL(&ps->values, v, entry); + return (value); +} + +static struct cmd_parse_commands * +cmd_parse_own_commands(void) +{ + struct cmd_parse_commands *cmds; + + cmds = cmd_parse_new_commands(); + return (cmd_parse_own(CMD_PARSE_VALUE_COMMANDS, cmds)); +} + +static struct cmd_parse_owned_value * +cmd_parse_find_value(void *value) +{ + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_owned_value *v; + + TAILQ_FOREACH_REVERSE(v, &ps->values, cmd_parse_owned_values, entry) { + if (v->value == value) + return (v); + } + fatalx("parser value not owned"); +} + +static void * +cmd_parse_take(void *value) +{ + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_owned_value *v; + + v = cmd_parse_find_value(value); + TAILQ_REMOVE(&ps->values, v, entry); + free(v); + return (value); +} + +static void +cmd_parse_free_value(enum cmd_parse_value_type type, void *value) +{ + switch (type) { + case CMD_PARSE_VALUE_STRING: + free(value); + break; + case CMD_PARSE_VALUE_ARGUMENT: + cmd_parse_free_argument(value); + break; + case CMD_PARSE_VALUE_ARGUMENTS: + cmd_parse_free_arguments(value); + free(value); + break; + case CMD_PARSE_VALUE_COMMAND: + cmd_parse_free_command(value); + break; + case CMD_PARSE_VALUE_COMMANDS: + cmd_parse_free_commands(value); + break; + } +} + +static void +cmd_parse_drop(void *value) +{ + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_owned_value *v; + + v = cmd_parse_find_value(value); + TAILQ_REMOVE(&ps->values, v, entry); + cmd_parse_free_value(v->type, v->value); + free(v); +} + static struct cmd_parse_commands * cmd_parse_run_parser(char **cause) { - struct cmd_parse_state *ps = &parse_state; - struct cmd_parse_scope *scope, *scope1; - int retval; + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_scope *scope, *scope1; + struct cmd_parse_owned_value *v, *v1; + int retval; ps->commands = NULL; TAILQ_INIT(&ps->stack); + TAILQ_INIT(&ps->values); retval = yyparse(); TAILQ_FOREACH_SAFE(scope, &ps->stack, entry, scope1) { TAILQ_REMOVE(&ps->stack, scope, entry); free(scope); } + free(ps->scope); + ps->scope = NULL; + + TAILQ_FOREACH_SAFE(v, &ps->values, entry, v1) { + TAILQ_REMOVE(&ps->values, v, entry); + cmd_parse_free_value(v->type, v->value); + free(v); + } if (retval != 0) { + if (ps->commands != NULL) + cmd_parse_free_commands(ps->commands); *cause = ps->error; return (NULL); } @@ -1329,9 +1456,10 @@ yylex(void) */ next = yylex_getc(); if (condition && next == '{') { - yylval.token = yylex_format(); - if (yylval.token == NULL) + token = yylval.token = yylex_format(); + if (token == NULL) return (ERROR); + cmd_parse_own(CMD_PARSE_VALUE_STRING, token); return (FORMAT); } while (next != '\n' && next != EOF) @@ -1348,35 +1476,37 @@ yylex(void) * % is a condition unless it is all % or all numbers, * then it is a token. */ - yylval.token = yylex_get_word('%'); - for (cp = yylval.token; *cp != '\0'; cp++) { + token = yylval.token = yylex_get_word('%'); + for (cp = token; *cp != '\0'; cp++) { if (*cp != '%' && !isdigit((u_char)*cp)) break; } - if (*cp == '\0') + if (*cp == '\0') { + cmd_parse_own(CMD_PARSE_VALUE_STRING, token); return (TOKEN); + } ps->condition = 1; - if (strcmp(yylval.token, "%hidden") == 0) { - free(yylval.token); + if (strcmp(token, "%hidden") == 0) { + free(token); return (HIDDEN); } - if (strcmp(yylval.token, "%if") == 0) { - free(yylval.token); + if (strcmp(token, "%if") == 0) { + free(token); return (IF); } - if (strcmp(yylval.token, "%else") == 0) { - free(yylval.token); + if (strcmp(token, "%else") == 0) { + free(token); return (ELSE); } - if (strcmp(yylval.token, "%elif") == 0) { - free(yylval.token); + if (strcmp(token, "%elif") == 0) { + free(token); return (ELIF); } - if (strcmp(yylval.token, "%endif") == 0) { - free(yylval.token); + if (strcmp(token, "%endif") == 0) { + free(token); return (ENDIF); } - free(yylval.token); + free(token); return (ERROR); } @@ -1386,7 +1516,7 @@ yylex(void) token = yylex_token(ch); if (token == NULL) return (ERROR); - yylval.token = token; + yylval.token = cmd_parse_own(CMD_PARSE_VALUE_STRING, token); if (strchr(token, '=') != NULL && yylex_is_var(*token, 1)) { for (cp = token + 1; *cp != '='; cp++) {