All of lore.kernel.org
 help / color / mirror / Atom feed
From: yumkam@gmail.com (Yuriy M. Kaminskiy)
To: util-linux@vger.kernel.org
Subject: Re: [PATCH 02/10] getopt: fix memory leaks and integer overflows [ASAN & valgrind]
Date: Sun, 13 Mar 2016 15:11:54 +0300	[thread overview]
Message-ID: <m37fh6inlh.fsf@gmail.com> (raw)
In-Reply-To: 1457865109-2881-3-git-send-email-kerolasa@iki.fi


On 03/13/16 13:31 , Sami Kerola wrote:
> The getopt(1) is short living command, and one could argue ensuring all
> allocations are freed at end of execution is waste of time.  There is a
> point in that, but making test-suite runs to be less noisy with ASAN is also
> nice as it encourages reading the errors when/if they happen.
>
> Signed-off-by: Sami Kerola <kerolasa@iki.fi>
> ---
>  misc-utils/getopt.c | 36 ++++++++++++++++++++++++++++--------
>  1 file changed, 28 insertions(+), 8 deletions(-)
>
> diff --git a/misc-utils/getopt.c b/misc-utils/getopt.c
> index c4144f6..be2ed38 100644
> --- a/misc-utils/getopt.c
> +++ b/misc-utils/getopt.c
> @@ -79,13 +79,23 @@
>  /* The shells recognized. */
>  typedef enum { BASH, TCSH } shell_t;
>  
> +/* This is a copy of getopt_long(3) structure, in which *name does not have
> + * const, so that is can be free'd at end of execution.  */
> +struct getoption {
> +	char *name;
> +	int has_arg;
> +	int *flag;
> +	int val;
> +};

What will happen if some implementation will add new fields in `struct
option`? (Sure, unlikely, but).
IMO, `free((char *)option->name)` is *much* safer.

>  struct getopt_control {
>  	shell_t shell;			/* the shell we generate output for */
>  	char *optstr;			/* getopt(3) optstring */
> -	struct option *long_options;	/* long options */
> +	struct getoption *long_options;	/* long options */
>  	int long_options_length;	/* length of options array */
>  	int long_options_nr;		/* number of used elements in array */
>  	unsigned int
> +		free_name:1,		/* free up argv[0] after printout */
>  		compatible:1,		/* compatibility mode for 'difficult' programs */
>  		quiet_errors:1,		/* print errors */
>  		quiet_output:1,		/* print output */
> @@ -181,7 +191,7 @@ static void print_normalized(const struct getopt_control *ctl, const char *arg)
>   * optstr must contain the short options, and longopts the long options.
>   * Other settings are found in global variables.
>   */
> -static int generate_output(const struct getopt_control *ctl, char *argv[], int argc)
> +static int generate_output(struct getopt_control *ctl, char *argv[], int argc)
>  {
>  	int exit_code = EXIT_SUCCESS;	/* Assume everything will be OK */
>  	int opt;
> @@ -195,8 +205,10 @@ static int generate_output(const struct getopt_control *ctl, char *argv[], int a
>  	optind = 0;
>  
>  	while ((opt =
> -		(getopt_long_fp(argc, argv, ctl->optstr, ctl->long_options, &longindex)))
> -	       != EOF)
> +		(getopt_long_fp
> +		 (argc, argv, ctl->optstr,
> +		  (const struct option *)ctl->long_options, &longindex)))
> +	       != EOF) {
>  		if (opt == '?' || opt == ':')
>  			exit_code = GETOPT_EXIT_CODE;
>  		else if (!ctl->quiet_output) {
> @@ -216,13 +228,19 @@ static int generate_output(const struct getopt_control *ctl, char *argv[], int a
>  					print_normalized(ctl, optarg ? optarg : "");
>  			}
>  		}
> -
> +	}
>  	if (!ctl->quiet_output) {
>  		printf(" --");
>  		while (optind < argc)
>  			print_normalized(ctl, argv[optind++]);
>  		printf("\n");
>  	}
> +	for (longindex = 0; longindex < ctl->long_options_nr; longindex++)
> +		free(ctl->long_options[longindex].name);
> +	free(ctl->long_options);
> +	free(ctl->optstr);
> +	if (ctl->free_name)
> +		free(argv[0]);
>  	return exit_code;
>  }
>  
> @@ -373,9 +391,6 @@ int main(int argc, char *argv[])
>  	textdomain(PACKAGE);
>  	atexit(close_stdout);
>  
> -	add_longopt(&ctl, NULL, 0);	/* init */
> -	getopt_long_fp = getopt_long;
> -
>  	if (getenv("GETOPT_COMPATIBLE"))
>  		ctl.compatible = 1;
>  
> @@ -391,6 +406,9 @@ int main(int argc, char *argv[])
>  			parse_error(_("missing optstring argument"));
>  	}
>  
> +	add_longopt(&ctl, NULL, 0);	/* init */
> +	getopt_long_fp = getopt_long;
> +
>  	if (argv[1][0] != '-' || ctl.compatible) {
>  		ctl.quote = 0;
>  		ctl.optstr = xmalloc(strlen(argv[1]) + 1);
> @@ -417,6 +435,7 @@ int main(int argc, char *argv[])
>  		case 'n':
>  			free(name);
>  			name = xstrdup(optarg);
> +			ctl.free_name = 1;
>  			break;
>  		case 'q':
>  			ctl.quiet_errors = 1;
> @@ -428,6 +447,7 @@ int main(int argc, char *argv[])
>  			ctl.shell = shell_type(optarg);
>  			break;
>  		case 'T':
> +			free(ctl.long_options);
>  			return TEST_EXIT_CODE;
>  		case 'u':
>  			ctl.quote = 0;
> -- 
> 2.7.2


  reply	other threads:[~2016-03-13 12:12 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-03-13 10:31 [PATCH 00/10] pull: release v2.28 prep work Sami Kerola
2016-03-13 10:31 ` [PATCH 01/10] logger: fix memory leak [ASAN and valgrind] Sami Kerola
2016-03-13 10:31 ` [PATCH 02/10] getopt: fix memory leaks and integer overflows [ASAN & valgrind] Sami Kerola
2016-03-13 12:11   ` Yuriy M. Kaminskiy [this message]
2016-03-14 21:24     ` Sami Kerola
2016-03-13 10:31 ` [PATCH 03/10] lsipc, lslogins, rtcwake: replace asctime() with strftime() Sami Kerola
2016-03-13 11:28   ` Ruediger Meier
2016-03-13 13:20   ` Yuriy M. Kaminskiy
2016-03-14 12:08     ` Karel Zak
2016-03-13 10:31 ` [PATCH 04/10] isosize: stop unmeaningful printing errno message Sami Kerola
2016-03-13 10:31 ` [PATCH 05/10] setsid: fix argument count bug Sami Kerola
2016-03-13 10:31 ` [PATCH 06/10] bash-completion: fsck.cramfs, isosize: find files an argument Sami Kerola
2016-03-13 10:31 ` [PATCH 07/10] bash-completion: ipcmk: add missing completion file Sami Kerola
2016-03-13 10:31 ` [PATCH 08/10] bash-completion: lslogins: " Sami Kerola
2016-03-13 10:31 ` [PATCH 09/10] bash-completion: lsns: " Sami Kerola
2016-03-13 10:31 ` [PATCH 10/10] docs: update AUTHORS file Sami Kerola
2016-03-14 12:17 ` [PATCH 00/10] pull: release v2.28 prep work Karel Zak

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=m37fh6inlh.fsf@gmail.com \
    --to=yumkam@gmail.com \
    --cc=util-linux@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.