Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 12 Jul 2001 01:09:08 -0700 (PDT)
From:      Matt Dillon <dillon@earth.backplane.com>
To:        Dima Dorfman <dima@unixfreak.org>
Cc:        Mark Peek <mark@whistle.com>, stable@FreeBSD.ORG
Subject:   Re: cron exited on signal 11 
Message-ID:  <200107120809.f6C898Q42216@earth.backplane.com>
References:   <20010712065159.619703E2F@bazooka.unixfreak.org>

next in thread | previous in thread | raw e-mail | index | archive | help

:
:Matt Dillon <dillon@earth.backplane.com> writes:
:>     Well this certainly opens up a can of worms!  Not your patch, but what 
:>     it implies.  For example, env_set() assumes envp is not NULL as well.
:>     In fact, most of the code assumes envp is not NULL, and 99% of the time
:>     that is true due to the env_init() calls.
:
:I think it should be 100%; why would envp be NULL?
:
:>     I found at least one case in the code where free_entry() is called with
:>     e->envp == NULL.  Perhaps a more correct fix would simply be to have
:>     free_entry() check for e->envp != NULL before calling env_free() rather
:>     then having env_free() check for NULL.
:
:On the contrary, I think free_entry() should assume that all members
:aren't NULL because if they're NULL, it's probably a bug (in which
:case a core dump is advisable).
:
:Below is a copy of an e-mail I sent to Mark Peek on this topic.  The
:only thing I'd like to add is that the patch below addresses two
:different problems.  The first is that free_entry() simply shouldn't
:be called after the eof: label.  The second is that the `class' member
:is unnecessarily treated inconsistently from the others.  They really
:don't belong in the same patch, because the former is a bugfix while
:the latter is a style/consistency fix.

    Well, I think I disagree here... the eof label does a 'general cleanup'.
    It is entirely appropriate for it to call free_entry() here, as long
    as free_entry() is designed to handle a partially instantiated structure.
    This is a fairly typical programming practice used to avoid having to
    do piecemeal unwinds of partially instantiated structures all over the
    code (which is what you did in your patch).  So I believe the
    proper solution is to imply make it so that free_entry() can deal with
    a partially instantiated structure - a one line fix.

    The eof label itself may not be good programming practice, but the
    concept of a general cleanup at the end of a procedure or in case of
    error is sound.

						-Matt

:
:I think that whether a free()-like routine should check if its
:argument (or members thereof) are NULL is a religious/philosophical
:thing.  We've had arguments about whether free(3) should crash if its
:argument is NULL, or if it should just let it go.  Furthermore, some
:programmers religiously rely on free_something() doing the right thing
:with a half-filled structure, while others prefer to have the routine
:filling in the structure clean up after itself.  I don't want to argue
:about which approach is better, but since the original author used the
:latter, I think we should stick to it unless there's a good reason
:(and there isn't, really).
:
:Right now, cron consistently uses the latter approach except for the
:`class' member of `entry'; that was added by ache@, and he chose to be
:inconsistent.  I think we should just fix the inconsistency.  If
:free_entry() is called somewhere when `envp' is NULL, that's another
:bug that should be fixed.
:
:But again, I'd like to point out that there are two issues here: (1)
:the bugfix, which is pretty straight-forward (free_entry -> free), and
:(2) the inconsistency issue, which is less straight-forward.
:
:Regards,
:
:					Dima Dorfman
:					dima@unixfreak.org
:
:
:> Date:    Wed, 11 Jul 2001 21:19:07 PDT
:> To:      Mark Peek <mark@whistle.com>
:> From:    Dima Dorfman <dima@hornet.unixfreak.org>
:> Subject: Re: cron exited on signal 11 
:> 
:> In-Reply-To: <p0510032db772c73d2f62@[207.76.207.129]>; from mark@whistle.com on
:>      *** "Wed, 11 Jul 2001 20:27:54 -0700"
:> 
:> Mark Peek <mark@whistle.com> writes:
:> > Index: usr.sbin/cron/lib/env.c
:> > ===================================================================
:> > RCS file: /cvs/freebsd/src/usr.sbin/cron/lib/env.c,v
:> > retrieving revision 1.9
:> > diff -u -r1.9 env.c
:> > --- usr.sbin/cron/lib/env.c	2000/04/30 15:57:00	1.9
:> > +++ usr.sbin/cron/lib/env.c	2001/07/12 03:12:29
:> > @@ -41,6 +41,8 @@
:> >   {
:> >   	char	**p;
:> > 
:> > +	if (envp == NULL)
:> > +		return;
:> >   	for (p = envp;  *p;  p++)
:> >   		free(*p);
:> >   	free(envp);
:> 
:> I think this is the wrong fix; the bug is your/our original change of
:> free(e) -> free_entry(e) after the eof: label.  This routine takes
:> great care (but not great enough, see below) to make sure that it
:> doesn't forgot to free() something in this structure before jumping to
:> eof.  There's code like this (entry.c, line 397 of rev. 1.12):
:> 
:> :        ch = get_string(cmd, MAX_COMMAND, file, "\n");
:> :
:> :        /* a file without a \n before the EOF is rude, so we'll complain...
:> :         */
:> :        if (ch == EOF) {
:> :                env_free(e->envp);
:> :                ecode = e_cmd;
:> :                goto eof;
:> :        }
:> 
:> Notice how it calls env_free() before jumping to eof.  There are
:> similar fragments throughout the routine.  `envp', `cmd', and `class'
:> are the only members of `entry' that need to be free()'d.  The routine
:> does a very good job of free()'ing `envp' and `cmd' when appropriate,
:> but since `class' is an afterthough (introduced in rev. 1.8), it
:> doesn't bother with that.
:> 
:> Thus, I think the right fix is to correct its behavior with regards to
:> free()'ing `class'.  Changing free_entry() (or env_free()) not to free
:> something if it isn't NULL seems wrong; it will just mask other bugs
:> (e.g., if there is an `entry' floating around with one of the fields
:> not filled in; it should crash, but wouldn't with your fix).
:> 
:> Below is a patch that demonstrates what I mean.  I haven't tested it
:> beyond compiling it, but I think it should work.  It isn't very pretty
:> from the point of view of the source code (those #ifdef LOGIN_CAP's
:> are evil!), but I think the result is a better product.  Also note
:> that not free()'ing `class' didn't result in a leak because it was
:> taken care of in free_entry(); however, I think that either all or
:> none members should be free()'d before jumping to eof.  The former
:> (all) seems to be the better choice.
:> 
:> Thoughts?
:> 
:> Thanks,
:> 
:> 					Dima Dorfman
:> 					dima@unixfreak.org
:> 
:> P.S.  I haven't carefully checked that it doesn't forget to free()
:> something else.  `class' is just the obvious one.
:> 
:> Index: entry.c
:> ===================================================================
:> RCS file: /stl/src/FreeBSD/src/usr.sbin/cron/lib/entry.c,v
:> retrieving revision 1.12
:> diff -u -r1.12 entry.c
:> --- entry.c	2001/06/13 05:49:37	1.12
:> +++ entry.c	2001/07/12 04:17:29
:> @@ -70,8 +70,7 @@
:>  	entry	*e;
:>  {
:>  #ifdef LOGIN_CAP
:> -	if (e->class != NULL)
:> -		free(e->class);
:> +	free(e->class);
:>  #endif
:>  	free(e->cmd);
:>  	env_free(e->envp);
:> @@ -291,6 +290,7 @@
:>  			goto eof;
:>  		}
:>  		if ((lc = login_getclass(e->class)) == NULL) {
:> +			free(e->class);
:>  			ecode = e_class;
:>  			goto eof;
:>  		}
:> @@ -300,6 +300,9 @@
:>  		if ((s = strrchr(username, ':')) != NULL) {
:>  			*s = '\0';
:>  			if ((grp = getgrnam(s + 1)) == NULL) {
:> +#ifdef LOGIN_CAP
:> +				free(e->class);
:> +#endif
:>  				ecode = e_group;
:>  				goto eof;
:>  			}
:> @@ -307,6 +310,9 @@
:>  
:>  		pw = getpwnam(username);
:>  		if (pw == NULL) {
:> +#ifdef LOGIN_CAP
:> +			free(e->class);
:> +#endif
:>  			ecode = e_username;
:>  			goto eof;
:>  		}
:> @@ -319,6 +325,9 @@
:>  	}
:>  
:>  	if (pw->pw_expire && time(NULL) >= pw->pw_expire) {
:> +#ifdef LOGIN_CAP
:> +		free(e->class);
:> +#endif
:>  		ecode = e_username;
:>  		goto eof;
:>  	}
:> @@ -332,6 +341,9 @@
:>  	e->envp = env_copy(envp);
:>  	if (e->envp == NULL) {
:>  		warn("env_copy");
:> +#ifdef LOGIN_CAP
:> +		free(e->class);
:> +#endif
:>  		ecode = e_mem;
:>  		goto eof;
:>  	}
:> @@ -341,6 +353,9 @@
:>  		e->envp = env_set(e->envp, envstr);
:>  		if (e->envp == NULL) {
:>  			warn("env_set(%s)", envstr);
:> +#ifdef LOGIN_CAP
:> +			free(e->class);
:> +#endif
:>  			env_free(prev_env);
:>  			ecode = e_mem;
:>  			goto eof;
:> @@ -351,6 +366,9 @@
:>  	e->envp = env_set(e->envp, envstr);
:>  	if (e->envp == NULL) {
:>  		warn("env_set(%s)", envstr);
:> +#ifdef LOGIN_CAP
:> +		free(e->class);
:> +#endif
:>  		env_free(prev_env);
:>  		ecode = e_mem;
:>  		goto eof;
:> @@ -361,6 +379,9 @@
:>  		e->envp = env_set(e->envp, envstr);
:>  		if (e->envp == NULL) {
:>  			warn("env_set(%s)", envstr);
:> +#ifdef LOGIN_CAP
:> +			free(e->class);
:> +#endif
:>  			env_free(prev_env);
:>  			ecode = e_mem;
:>  			goto eof;
:> @@ -371,6 +392,9 @@
:>  	e->envp = env_set(e->envp, envstr);
:>  	if (e->envp == NULL) {
:>  		warn("env_set(%s)", envstr);
:> +#ifdef LOGIN_CAP
:> +		free(e->class);
:> +#endif
:>  		env_free(prev_env);
:>  		ecode = e_mem;
:>  		goto eof;
:> @@ -381,6 +405,9 @@
:>  	e->envp = env_set(e->envp, envstr);
:>  	if (e->envp == NULL) {
:>  		warn("env_set(%s)", envstr);
:> +#ifdef LOGIN_CAP
:> +		free(e->class);
:> +#endif
:>  		env_free(prev_env);
:>  		ecode = e_mem;
:>  		goto eof;
:> @@ -399,6 +426,9 @@
:>  	/* a file without a \n before the EOF is rude, so we'll complain...
:>  	 */
:>  	if (ch == EOF) {
:> +#ifdef LOGIN_CAP
:> +		free(e->class);
:> +#endif
:>  		env_free(e->envp);
:>  		ecode = e_cmd;
:>  		goto eof;
:> @@ -409,6 +439,9 @@
:>  	e->cmd = strdup(cmd);
:>  	if (e->cmd == NULL) {
:>  		warn("strdup(\"%d\")", cmd);
:> +#ifdef LOGIN_CAP
:> +		free(e->class);
:> +#endif
:>  		env_free(e->envp);
:>  		ecode = e_mem;
:>  		goto eof;
:> @@ -420,7 +453,7 @@
:>  	return e;
:>  
:>   eof:
:> -	free_entry(e);
:> +	free(e);
:>  	if (ecode != e_none && error_func)
:>  		(*error_func)(ecodes[(int)ecode]);
:>  	while (ch != EOF && ch != '\n')
:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-stable" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200107120809.f6C898Q42216>