diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2021-11-16 19:49:25 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2021-11-16 19:49:25 +0200 |
commit | 203601fb06c13472b9069cc139329174b2d4d253 (patch) | |
tree | 4c23b29a96ef3536b03047b6f97895c22f2462ec | |
parent | 6331d5d6818db7923636f63d0e78c22ce6e0c15f (diff) | |
download | gdbm-203601fb06c13472b9069cc139329174b2d4d253.tar.gz |
Fix memory leaks in gdbmshell
* configure.ac: Don't use $YACC and $LEX (undefined since f4c143fbdf).
* src/gdbmshell.c (run_command): Free arglist if not saved to last_args.
* src/gdbmtool.c (gdbmtool_init): Correctly report unrecognized long
options.
* src/gdbmtool.h (YY_LOCATION_PRINT): Define to locus_print.
(locus_print): New proto.
* src/gram.y: Define destructors for various symbols.
* src/lex.l: Save source file names in a linked list. Don't free
source name in input_context_pop, because yypush might refer to it
via yyloc stack even after readinf eof (e.g. when printing location).
The collected list is freed at program exit.
(locus_print): New function.
* src/parseopt.c (parseopt_free): New function.
(parseopt_first): Call parseopt_free.
(parseopt_next): Call parseopt_free, depending on the result.
* src/var.c (variable) <freehook>: New member.
(errormask_freehook): New function. Set it as freehook for errorexit
and errormask.
(variables_free): Call freehook, if defined.
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | src/gdbmshell.c | 2 | ||||
-rw-r--r-- | src/gdbmtool.c | 8 | ||||
-rw-r--r-- | src/gdbmtool.h | 32 | ||||
-rw-r--r-- | src/gram.y | 9 | ||||
-rw-r--r-- | src/lex.l | 70 | ||||
-rw-r--r-- | src/parseopt.c | 16 | ||||
-rw-r--r-- | src/var.c | 16 |
8 files changed, 112 insertions, 47 deletions
diff --git a/configure.ac b/configure.ac index 035bb38..8648ad0 100644 --- a/configure.ac +++ b/configure.ac @@ -228,12 +228,6 @@ AM_CONDITIONAL([GDBM_COND_DEBUG_ENABLE], [test "$status_debug" = "yes"]) AC_SUBST(YFLAGS_DEBUG) AC_SUBST(LFLAGS_DEBUG) if test "$want_gdbmtool_debug" = yes; then - if ! $LEX --version 2>/dev/null | grep -q flex; then - AC_MSG_ERROR([--enable-gdbmtool-debug requires flex, which is not available]) - fi - if ! $YACC --version 2>/dev/null | grep -q bison; then - AC_MSG_ERROR([--enable-gdbmtool-debug requires bison, which is not available]) - fi YFLAGS_DEBUG=-t LFLAGS_DEBUG=-d fi diff --git a/src/gdbmshell.c b/src/gdbmshell.c index 0b3b7f0..45e3f9f 100644 --- a/src/gdbmshell.c +++ b/src/gdbmshell.c @@ -3084,6 +3084,7 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) break; case GDBMSHELL_GDBM_ERR: + gdbmarglist_free (arglist); if (variable_has_errno ("errorexit", gdbm_errno)) rc = 1; else @@ -3091,6 +3092,7 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) break; default: + gdbmarglist_free (arglist); rc = 0; } diff --git a/src/gdbmtool.c b/src/gdbmtool.c index 512dd88..dfe7094 100644 --- a/src/gdbmtool.c +++ b/src/gdbmtool.c @@ -222,8 +222,12 @@ gdbmtool_init (void *data, instream_t *pinstr) break; default: - terror (_("unknown option %c; try `%s -h' for more info"), - optopt, progname); + if (optopt == 0) + terror (_("unknown option %s; try `%s -h' for more info"), + argv[optind-1], progname); + else + terror (_("unknown option %c; try `%s -h' for more info"), + optopt, progname); exit (EXIT_USAGE); } diff --git a/src/gdbmtool.h b/src/gdbmtool.h index 7462f8e..432e9a6 100644 --- a/src/gdbmtool.h +++ b/src/gdbmtool.h @@ -68,37 +68,9 @@ typedef struct locus gdbm_yyltype_t; } \ while (0) -#define YY_LOCATION_PRINT(File, Loc) \ - do \ - { \ - if ((Loc).beg.col == 0) \ - fprintf (File, "%s:%u", \ - (Loc).beg.file, \ - (Loc).beg.line); \ - else if (strcmp ((Loc).beg.file, (Loc).end.file)) \ - fprintf (File, "%s:%u.%u-%s:%u.%u", \ - (Loc).beg.file, \ - (Loc).beg.line, (Loc).beg.col, \ - (Loc).end.file, \ - (Loc).end.line, (Loc).end.col); \ - else if ((Loc).beg.line != (Loc).end.line) \ - fprintf (File, "%s:%u.%u-%u.%u", \ - (Loc).beg.file, \ - (Loc).beg.line, (Loc).beg.col, \ - (Loc).end.line, (Loc).end.col); \ - else if ((Loc).beg.col != (Loc).end.col) \ - fprintf (File, "%s:%u.%u-%u", \ - (Loc).beg.file, \ - (Loc).beg.line, (Loc).beg.col, \ - (Loc).end.col); \ - else \ - fprintf (File, "%s:%u.%u", \ - (Loc).beg.file, \ - (Loc).beg.line, \ - (Loc).beg.col); \ - } \ - while (0) +#define YY_LOCATION_PRINT(File, Loc) locus_print (File, &(Loc)) +void locus_print (FILE *fp, struct locus const *loc); void vlerror (struct locus *loc, const char *fmt, va_list ap); void lerror (struct locus *loc, const char *fmt, ...) GDBM_PRINTFLIKE (2, 3); @@ -62,6 +62,15 @@ struct dsegm *dsdef[DS_MAX]; struct command *cmd; } +%destructor { gdbmarglist_free (&$$); } <arglist> +%destructor { gdbmarg_free ($$); } <arg> +%destructor { kvlist_free ($$.head); } <kvlist> +%destructor { kvlist_free ($$); } <kvpair> +%destructor { slist_free ($$.head); } <slist> +%destructor { free ($$); } <string> +%destructor { dsegm_list_free ($$); } <dsegm> +%destructor { dsegm_list_free ($$.head); } <dsegmlist> + %% input : /* empty */ @@ -67,6 +67,37 @@ void string_addc (int c); char *string_end (void); int unescape (int c); +struct file_name +{ + struct file_name *next; + char str[1]; +}; + +static struct file_name *file_head; + +static void +file_names_free (void) +{ + while (file_head) + { + struct file_name *next = file_head->next; + free (file_head); + file_head = next; + } +} + +char * +file_name_alloc (char const *s) +{ + struct file_name *f = emalloc (sizeof (*f) + strlen (s)); + strcpy (f->str, s); + f->next = file_head; + if (!file_head) + atexit (file_names_free); + file_head = f; + return f->str; +} + int interactive (void) { @@ -123,7 +154,7 @@ input_context_push (instream_t input) cp = ecalloc (1, sizeof (*cp)); cp->locus = yylloc; - cp->point.file = estrdup (instream_name (input)); + cp->point.file = file_name_alloc (instream_name (input)); cp->point.line = 1; cp->point.col = 0; @@ -149,8 +180,6 @@ input_context_pop (void) if (!context_tos) return 1; instream_close (context_tos->input); - free (context_tos->point.file); - memset (&yylloc, 0, sizeof (yylloc)); cp = context_tos->parent; free (context_tos); context_tos = cp; @@ -499,6 +528,39 @@ escape (int c) } return 0; } + +void +locus_print (FILE *fp, struct locus const *loc) +{ + if (loc->beg.file) + { + if (loc->beg.col == 0) + fprintf (fp, "%s:%u", + loc->beg.file, + loc->beg.line); + else if (strcmp (loc->beg.file, loc->end.file)) + fprintf (fp, "%s:%u.%u-%s:%u.%u", + loc->beg.file, + loc->beg.line, loc->beg.col, + loc->end.file, + loc->end.line, loc->end.col); + else if (loc->beg.line != loc->end.line) + fprintf (fp, "%s:%u.%u-%u.%u", + loc->beg.file, + loc->beg.line, loc->beg.col, + loc->end.line, loc->end.col); + else if (loc->beg.col != loc->end.col) + fprintf (fp, "%s:%u.%u-%u", + loc->beg.file, + loc->beg.line, loc->beg.col, + loc->end.col); + else + fprintf (fp, "%s:%u.%u", + loc->beg.file, + loc->beg.line, + loc->beg.col); + } +} void vlerror (struct locus *loc, const char *fmt, va_list ap) @@ -679,4 +741,4 @@ make_prompt (void) return ret; } - + diff --git a/src/parseopt.c b/src/parseopt.c index efa12c8..42cef26 100644 --- a/src/parseopt.c +++ b/src/parseopt.c @@ -189,8 +189,8 @@ add_options (struct gdbm_option *options) #endif } -int -parseopt_first (int pc, char **pv, struct gdbm_option *opts) +void +parseopt_free (void) { free (option_tab); option_tab = NULL; @@ -202,6 +202,12 @@ parseopt_first (int pc, char **pv, struct gdbm_option *opts) long_options = NULL; long_option_count = long_option_max = 0; #endif +} + +int +parseopt_first (int pc, char **pv, struct gdbm_option *opts) +{ + parseopt_free (); add_options (opts); add_options (parseopt_default_options); opterr = 0; @@ -570,7 +576,7 @@ handle_option (int c) } int -parseopt_next () +parseopt_next (void) { int rc; @@ -583,5 +589,9 @@ parseopt_next () #endif } while (handle_option (rc)); + + if (rc == EOF || rc == '?') + parseopt_free (); + return rc; } @@ -41,6 +41,7 @@ struct variable void *data; int (*sethook) (struct variable *, union value *); int (*typeconv) (struct variable *, int, void **); + void (*freehook) (void *); }; static int open_sethook (struct variable *, union value *); @@ -53,6 +54,7 @@ static int coalesce_sethook (struct variable *var, union value *v); static int cachesize_sethook (struct variable *var, union value *v); static int errormask_sethook (struct variable *var, union value *v); static int errormask_typeconv (struct variable *var, int type, void **retptr); +static void errormask_freehook (void *); static int errorexit_sethook (struct variable *var, union value *v); static struct variable vartab[] = { @@ -180,13 +182,15 @@ static struct variable vartab[] = { .name = "errorexit", .type = VART_STRING, .sethook = errorexit_sethook, - .typeconv = errormask_typeconv + .typeconv = errormask_typeconv, + .freehook = errormask_freehook }, { .name = "errormask", .type = VART_STRING, .sethook = errormask_sethook, - .typeconv = errormask_typeconv + .typeconv = errormask_typeconv, + .freehook = errormask_freehook }, { .name = "timing", @@ -510,6 +514,8 @@ variables_free (void) if (vp->type == VART_STRING && (vp->flags & VARF_SET)) free (vp->v.string); vp->v.string = NULL; + if (vp->freehook && vp->data) + vp->freehook (vp->data); vp->flags &= ~VARF_SET; } } @@ -809,6 +815,12 @@ errormask_typeconv (struct variable *var, int type, void **retptr) return VAR_ERR_BADTYPE; } +static void +errormask_freehook (void *data) +{ + free (data); +} + static int errorexit_sethook (struct variable *var, union value *v) { |