Found mostly by normal usage running a no-bash-malloc build with clang's LeakSanitizer enabled. So far seems to provide very accurate results with little overhead.
* arrayfunc.c - quote_compound_array_word: make sure to free VALUE - bind_assoc_var_internal: if assigning to a dynamic variable, make sure to free the key (usually assoc_insert would do it) * bashline.c - bash_command_name_stat_hook: free original *NAME if we are going to change what it points to (what the callers seem to expect) * builtins/evalstring.c - parse_and_execute: make sure to dispose of the parsed command resulting from a failed function import attempt - open_redir_file: if we did not get a pointer to pass back the expanded filename, make sure to free the name * examples/loadables/kv.c - kvsplit: bind_assoc_variable does not free its VALUE argument so do not pass a copy in the call calling * examples/loadables/stat.c - loadstat: bind_assoc_variable does not free its VALUE argument so make sure to do it * subst.c - param_expand: free temp1 value for codepaths that don't do it --- arrayfunc.c | 6 +++++- bashline.c | 1 + builtins/evalstring.c | 4 ++++ examples/loadables/kv.c | 2 +- examples/loadables/stat.c | 1 + subst.c | 2 ++ 6 files changed, 14 insertions(+), 2 deletions(-) diff --git a/arrayfunc.c b/arrayfunc.c index 28aee54b..ea7a559d 100644 --- a/arrayfunc.c +++ b/arrayfunc.c @@ -193,7 +193,10 @@ bind_assoc_var_internal (SHELL_VAR *entry, HASH_TABLE *hash, char *key, const ch newval = make_array_variable_value (entry, 0, key, value, flags); if (entry->assign_func) - (*entry->assign_func) (entry, newval, 0, key); + { + (*entry->assign_func) (entry, newval, 0, key); + FREE (key); + } else assoc_insert (hash, key, newval); @@ -945,6 +948,7 @@ quote_compound_array_word (char *w, int type) if (t != w+ind) free (t); strcpy (nword + i, value); + free (value); return nword; } diff --git a/bashline.c b/bashline.c index 6adc548e..c14d465f 100644 --- a/bashline.c +++ b/bashline.c @@ -1923,6 +1923,7 @@ bash_command_name_stat_hook (char **name) result = search_for_command (cname, 0); if (result) { + FREE (*name); *name = result; return 1; } diff --git a/builtins/evalstring.c b/builtins/evalstring.c index 11785de1..f4f62b2d 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -468,6 +468,8 @@ parse_and_execute (char *string, const char *from_file, int flags) should_jump_to_top_level = 0; last_result = last_command_exit_value = EX_BADUSAGE; set_pipestatus_from_exit (last_command_exit_value); + dispose_command(command); + global_command = (COMMAND *)NULL; reset_parser (); break; } @@ -766,6 +768,8 @@ open_redir_file (REDIRECT *r, char **fnp) if (fnp) *fnp = fn; + else + free (fn); return fd; } diff --git a/examples/loadables/kv.c b/examples/loadables/kv.c index 1dfceb6a..ee6dc7f0 100644 --- a/examples/loadables/kv.c +++ b/examples/loadables/kv.c @@ -71,7 +71,7 @@ kvsplit (SHELL_VAR *v, char *line, char *dstring) else value = ""; - return (bind_assoc_variable (v, name_cell (v), savestring (key), savestring (value), 0) != 0); + return (bind_assoc_variable (v, name_cell (v), savestring (key), value, 0) != 0); } int diff --git a/examples/loadables/stat.c b/examples/loadables/stat.c index 1093f7b0..d58f07e5 100644 --- a/examples/loadables/stat.c +++ b/examples/loadables/stat.c @@ -330,6 +330,7 @@ loadstat (char *vname, SHELL_VAR *var, char *fname, int flags, char *fmt, struct key = savestring (arraysubs[i]); value = statval (i, fname, flags, fmt, sp); v = bind_assoc_variable (var, vname, key, value, ASS_FORCE); + free (value); } return 0; } diff --git a/subst.c b/subst.c index b93374b8..0ecb4cf1 100644 --- a/subst.c +++ b/subst.c @@ -10850,6 +10850,7 @@ comsub: { chk_atstar (temp, quoted, pflags, quoted_dollar_at_p, contains_dollar_at); tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, 0); + free (temp1); if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) return (tdesc); ret = tdesc; @@ -10862,6 +10863,7 @@ comsub: { set_exit_status (EXECUTION_FAILURE); report_error (_("%s: invalid variable name for name reference"), temp); + free (temp1); return (&expand_wdesc_error); /* XXX */ } else
From 892cb679195298496a8fc86c36825b20b0a8e07c Mon Sep 17 00:00:00 2001 From: Grisha Levit <grishale...@gmail.com> Date: Sat, 3 Jun 2023 16:51:26 -0400 Subject: [PATCH] various leaks Found mostly by normal usage running a no-bash-malloc build with clang's LeakSanitizer enabled. So far seems to provide very accurate results. * arrayfunc.c - quote_compound_array_word: make sure to free VALUE - bind_assoc_var_internal: if assigning to a dynamic variable, make sure to free the key (usually assoc_insert would do it) * bashline.c - bash_command_name_stat_hook: free original *NAME if we are going to change what it points to (what the callers seem to expect) * builtins/evalstring.c - parse_and_execute: make sure to dispose of the parsed command resulting from a failed function import attempt - open_redir_file: if we did not get a pointer to pass back the expanded filename, make sure to free the name * examples/loadables/kv.c - kvsplit: bind_assoc_variable does not free its VALUE argument so do not pass a copy in the call calling * examples/loadables/stat.c - loadstat: bind_assoc_variable does not free its VALUE argument so make sure to do it * subst.c - param_expand: free temp1 value for codepaths that don't do it --- arrayfunc.c | 6 +++++- bashline.c | 1 + builtins/evalstring.c | 4 ++++ examples/loadables/kv.c | 2 +- examples/loadables/stat.c | 1 + subst.c | 2 ++ 6 files changed, 14 insertions(+), 2 deletions(-) diff --git a/arrayfunc.c b/arrayfunc.c index 28aee54b..ea7a559d 100644 --- a/arrayfunc.c +++ b/arrayfunc.c @@ -193,7 +193,10 @@ bind_assoc_var_internal (SHELL_VAR *entry, HASH_TABLE *hash, char *key, const ch newval = make_array_variable_value (entry, 0, key, value, flags); if (entry->assign_func) - (*entry->assign_func) (entry, newval, 0, key); + { + (*entry->assign_func) (entry, newval, 0, key); + FREE (key); + } else assoc_insert (hash, key, newval); @@ -945,6 +948,7 @@ quote_compound_array_word (char *w, int type) if (t != w+ind) free (t); strcpy (nword + i, value); + free (value); return nword; } diff --git a/bashline.c b/bashline.c index 6adc548e..c14d465f 100644 --- a/bashline.c +++ b/bashline.c @@ -1923,6 +1923,7 @@ bash_command_name_stat_hook (char **name) result = search_for_command (cname, 0); if (result) { + FREE (*name); *name = result; return 1; } diff --git a/builtins/evalstring.c b/builtins/evalstring.c index 11785de1..f4f62b2d 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -468,6 +468,8 @@ parse_and_execute (char *string, const char *from_file, int flags) should_jump_to_top_level = 0; last_result = last_command_exit_value = EX_BADUSAGE; set_pipestatus_from_exit (last_command_exit_value); + dispose_command(command); + global_command = (COMMAND *)NULL; reset_parser (); break; } @@ -766,6 +768,8 @@ open_redir_file (REDIRECT *r, char **fnp) if (fnp) *fnp = fn; + else + free (fn); return fd; } diff --git a/examples/loadables/kv.c b/examples/loadables/kv.c index 1dfceb6a..ee6dc7f0 100644 --- a/examples/loadables/kv.c +++ b/examples/loadables/kv.c @@ -71,7 +71,7 @@ kvsplit (SHELL_VAR *v, char *line, char *dstring) else value = ""; - return (bind_assoc_variable (v, name_cell (v), savestring (key), savestring (value), 0) != 0); + return (bind_assoc_variable (v, name_cell (v), savestring (key), value, 0) != 0); } int diff --git a/examples/loadables/stat.c b/examples/loadables/stat.c index 1093f7b0..d58f07e5 100644 --- a/examples/loadables/stat.c +++ b/examples/loadables/stat.c @@ -330,6 +330,7 @@ loadstat (char *vname, SHELL_VAR *var, char *fname, int flags, char *fmt, struct key = savestring (arraysubs[i]); value = statval (i, fname, flags, fmt, sp); v = bind_assoc_variable (var, vname, key, value, ASS_FORCE); + free (value); } return 0; } diff --git a/subst.c b/subst.c index b93374b8..0ecb4cf1 100644 --- a/subst.c +++ b/subst.c @@ -10850,6 +10850,7 @@ comsub: { chk_atstar (temp, quoted, pflags, quoted_dollar_at_p, contains_dollar_at); tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, 0); + free (temp1); if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) return (tdesc); ret = tdesc; @@ -10862,6 +10863,7 @@ comsub: { set_exit_status (EXECUTION_FAILURE); report_error (_("%s: invalid variable name for name reference"), temp); + free (temp1); return (&expand_wdesc_error); /* XXX */ } else -- 2.41.0