svn commit: r205118 - head/sbin/sysctl

Bruce Evans brde at optusnet.com.au
Sun Mar 14 11:26:16 UTC 2010


On Sat, 13 Mar 2010, Garrett Cooper wrote:

>> Log:
>>  Free the memory allocated via strdup.

Why bother?
1. Memory is infinite :-).
2. Memory is infinite relative to sysctl's requirements, especially for
    this strdup.  Normally this strdup is never reached.  It is normally
    reached a whole 1 time for sysctl -a (e.g., on ref9-amd64 now),
    since there is a whole 1 sysctl with a timeval format in the configured
    kernel, and not many more (if any more) than 1 in /sys.

>> Modified: head/sbin/sysctl/sysctl.c
>> ==============================================================================
>> --- head/sbin/sysctl/sysctl.c   Sat Mar 13 11:06:47 2010        (r205117)
>> +++ head/sbin/sysctl/sysctl.c   Sat Mar 13 11:08:57 2010        (r205118)
>> @@ -382,6 +382,7 @@ S_timeval(int l2, void *p)
>>                if (*p2 == '\n')
>>                        *p2 = '\0';
>>        fputs(p1, stdout);
>> +       free(p1);
>>        return (0);
>>  }

The \xa0's are ugly.

>    strdup(3) can fail in that section of code, thus the fputs(3)
> could segfault:

Who cares?
1. strdup() can't fail, since memory is infinite :-)
2. ... since memory is infinite relative to sysctl's requirements (see above).
3. Most systems are (mis)configured with MALLOC_OPTIONS=A..., so if strdup()
    fails it doesn't return, and all the careful code that checks
    malloc() and strdup() for failing becomes just an obfuscation.
    MALLOC_OPTIONS=A... seriously breaks programs that are likely to
    run out of memory and handle this, but such programs became rare when
    address spaces exceeded 64K and rarer when they exceeded 640K...; they
    are now infinite :-), so problems are rarely seen.

The strdup() is bogus anyway.  ctime() returns a non-const string so the
the string should be modified directly.  It is just as easy to avoid the
modification.  The function with this has lots more style bugs:

% static int
% S_timeval(int l2, void *p)

Style bug: *p should be const.

% {
% 	struct timeval *tv = (struct timeval*)p;

Style bug: initialization in declaration.

% 	time_t tv_sec;
% 	char *p1, *p2;
% 
% 	if (l2 != sizeof(*tv)) {
% 		warnx("S_timeval %d != %zu", l2, sizeof(*tv));
% 		return (1);
% 	}
% 	printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
% 		"{ sec = %jd, usec = %ld } ",
% 		(intmax_t)tv->tv_sec, tv->tv_usec);

Style bugs: non-KNF indentation of continued lines.

% 	tv_sec = tv->tv_sec;
% 	p1 = strdup(ctime(&tv_sec));

Style bug: strdup() just adds bloat (especially when you add memory
management and error handling for it).

% 	for (p2=p1; *p2 ; p2++)

Style bug: missing spaces around binary operator.

% 		if (*p2 == '\n')
% 			*p2 = '\0';

To avoid the modification, break here and print the (p2 - p1) characters
starting at p1 using "%.*s" format.  This leads to complete de-bloatation:
1: the newline is always at the end, so it can be located using strlen()
2: strlen() is unnecessary to, since the string always has length 25.
    Thus "%.*s", ..., [p2 - p1 OR strlen(p1) -1] reduces to "%.24s".

% 	fputs(p1, stdout);

There is also a style rule against using fputs()...

% 	free(p1);

So the above lines (here they are again, indented a bit, with some error
handling added for not-quite maximal verboseness):

 	% 	p1 = strdup(ctime(&tv_sec));
 	%	if (p1 == NULL)
 	%		err(1, "strdup");
 	% 	for (p2=p1; *p2 ; p2++)
 	% 		if (*p2 == '\n')
 	% 			*p2 = '\0';
 	% 	fputs(p1, stdout);
 	% 	free(p1);

are a verbose way of writing:

 	printf("%.24s", ctime(&tv_sec));

To reduce verboseness a little more, merge this printf() with the preceding
one.

To increase verboseness for both, add error handling for fputs() and printf().

% 	return (0);
% }


More information about the svn-src-all mailing list