Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 12 May 2001 17:05:44 +0300
From:      Valentin Nechayev <netch@iv.nn.kiev.ua>
To:        Daniel Hemmerich <dan@BSDpro.com>
Cc:        freebsd-hackers@FreeBSD.ORG
Subject:   Re: adding a new function to libc
Message-ID:  <20010512170544.A343@iv.nn.kiev.ua>
In-Reply-To: <01051202104500.95296@blackhole.BSDpro.com>; from dan@BSDpro.com on Sat, May 12, 2001 at 02:10:45AM -0400
References:  <01051202104500.95296@blackhole.BSDpro.com>

next in thread | previous in thread | raw e-mail | index | archive | help
Hello Daniel Hemmerich! 

 Sat, May 12, 2001 at 02:10:45, dan (Daniel Hemmerich) wrote about "adding a new function to libc": 

> Any comments, suggestions, swears concerning adding a new function, 
> strndup(), to libc?
> 
> So that instead of permitting it to attempt to allocate a large chunk of 
> memory, it is possible to give it a max length.

Really, one should not use C-style null-terminated strings
except situations where they are nesessary (e.g. kernel interface)
because they all are too longfied nightmare, due to brain-damaged
interface and high inefficiency. Recent libc changes - adding
strlcpy() and strlcat() - were motivated AFAIU with well-grounded
fear to find *selves in BugTraq top list of buggy platforms, and with
aspiration to get rid of K&R crap - strcpy(), etc. (There is no
such object as "unlimited string buffer"; there are "limited buffer"
and "NUL-terminated constant string". strcpy() was designed to work
with wrong "unlimited string buffer" concept and hence it must die.
The same for its sisters such as strncat().)

strndup(), in any of common-possible interpretations, is danger because
caller cannot get info whether source string were longer (and copy is cut)
or not. You can use such cutting actively in rare cases, e.g. debugging
printing, but for sensitive work such _silent_ cutting can produce
only bugs, not any useful thing. I cannot see any reason to include
such danger function to libc.

The most concrete factor is that your code is buggy because if
source string is longer than max_len, destination string is not
terminated with NUL properly. And it is inefficient: there is no
need to waste processor time and cache cells to read unuseful data
in strlen().

Hence, I'll think the better implementation is

char*
strndup( const char* src, size_t max_len )
{
	size_t len = strnlen( src, max_len );
	char* ret = malloc( len + 1 );
	if( ret ) {
		strncpy( ret, src, len );
		ret[ len ] = 0;
	}
	return ret;
}

Here strnlen() is used which is non-standard but I saw it in ~4 quite
different projects (e.g. Linux kernel) with identical interface
and result value; a variant of implementation follows:

/* This is candidate to have optimized assembler variant */
size_t strnlen( const char* src, size_t max )
{
	size_t n;
	while( n < max && *src != '\0' )
		n++;
	return n;
}
	

> char *
> strndup(str, max_len)
>         const char *str;
>         size_t max_len;
> {
>         size_t len;
>         char *copy;
> 
>         len = strlen(str) + 1;
>         if (len > max_len)
>                 len = max_len;
>         if ((copy = malloc(len)) == NULL)
>                 return (NULL);
>         memcpy(copy, str, len);
>         return (copy);
> }
> 
> -- 
> Daniel Hemmerich
> dan@BSDpro.com
> 
> To Unsubscribe: send mail to majordomo@FreeBSD.org
> with "unsubscribe freebsd-hackers" in the body of the message


/netch

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




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