[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: strlcpy and strlcat in linux libc ?



Richard Braakman <dark@xs4all.nl> writes:

> Are these stated anywhere?  I didn't read the mail archives
> referenced at the beginning of this thread, I'm using my memory of a
> disussion on glibc-dev (and cross-posted to hell and back :).  One
> of the reasons I saw for not including these functions was that they
> were underspecified, and the specification (i.e. manpage) would have
> to be deduced from the code, which wasn't the same in all
> implementations.

The OpenBSD man page seems fairly clear to me; I wrote my own versions
of strlcpy/strlcat from it.

What do you think the ambiguities are?

>> Also, notice that strncpy returns a pointer to dest.  This is
>> almost never used by anyone.  I personally have never used it
>> actually.  strlcpy does return a value, but returns instead the
>> number of characters copied from src.  This too I use rarely, but
>> whereas strncpy's return value has never been even remotely useful
>> to me, strlcpy's has upon occasion.

strcpy and strcat also return a pointer to the destination, and there
is an obvious idiom which makes use of this to eliminate explicit
temporaries, a simple example being:

  char *xstrdup(const char *s) {
    return strcpy(xmalloc(strlen(s) + 1), s);
  }

However the usual use of strn*/strl* is in situations where you have a
fixed size buffer, where this idiom is less useful.  I think the
return values of str* and strl* are chosen correctly.

> ... and strlcat returns the sum of the lengths of the strings, even if
> that didn't fit in the destination buffer.  That's why the function was
> called inefficient -- the implementation has to scan the entire source
> string, even if it doesn't have to copy all of it, for the sake of a
> rarely used return value.

snprintf does much the same, only more so as it has to work out what
all the conversion specifications expand to rather than just do the
equivalent of strlen.  The common case should not be overflow though -
if it is, your buffer size is wrongly chosen.

>> Also, since copying the string also calculates how long the string shall
>> be, this strlcpy is _more_ efficient than following the strncpy with a
>> strlen (dest), all other factors considered equal.
>
> It's still less efficient than knowing how long the string is in the
> first place, though.

Often you don't know this.  strlen+strcpy is hardly likely to be
faster than strlcpy, assuming equal quality of implementation.

If your code is sufficiently speed critical, or your strings so long,
that you can't afford the occasional strlen you should probably be
passing around string lengths instead of using null terminators
anyway, in which case you need a whole new set of string functions.

Also, if you are using fixed-size buffers everywhere then you have
upper bounds on string lengths, and thus on the costs associated with
length calculations, anyway.

> You seem to be comparing strl* to strn*.  Well, the strn* functions
> have unfortunate interfaces and just about anything would be better,
> including the normal str* functions combined with judicious use of
> strlen.  I think that is what you should be comparing strl* to.

If you want to work with fixed-size buffers then strl* do both the
check and the copy for you.  Personally I think the saving in LOC is
worthwhile.  This isn't just laziness for its own sake; more LOC means
more chance for human error, and more effort for readers in
understanding the code.

> I'd like to add that truncated strings can be a significant security
> problem.

That's absolutely true, yes.  Proper use of strl* in security-critical
code involves checking the return value.


Nobody is forcing anyone to use strl*, anyway.  The desired outcome is
for them to be supported in C libraries, which would have obvious
benefits for those programs that do use them.

-- 
http://www.greenend.org.uk/rjk/



Reply to: