This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: The semantics of strlcpy and strlcat
- From: Paul Eggert <eggert at cs dot ucla dot edu>
- To: Zack Weinberg <zackw at panix dot com>, GNU C Library <libc-alpha at sourceware dot org>
- Date: Thu, 21 Jan 2016 16:29:03 -0800
- Subject: Re: The semantics of strlcpy and strlcat
- Authentication-results: sourceware.org; auth=none
- References: <CAKCAbMhfFmfdrVB7_FovQmfrbAAXjKmis3-JWnD1qDEODi_gQg at mail dot gmail dot com>
On 01/21/2016 03:37 PM, Zack Weinberg wrote:
* If the buffers overlap, the behavior is undefined. That is, either
memcpy is used, or an overlap-blind copy loop is used - either way,
the "correct" behavior (= "what memmove would have done") will not
always happen.
But the OpenBSD implementation's behavior is not undefined. True,
OpenBSD strlcpy doesn't behave the way memmove would, but the behavior
of its overlap-blind copy is well-defined on all platforms. Similarly
for NetBSD and FreeBSD; they all use the same overlap-blind copy.
We cannot assume that overlap-blind copying is "incorrect" and that
memmove semantics are "correct" when we are trying to figure out what
the correct behavior should be, as that would be begging the question.
* If the destination-size argument is zero, the destination-buffer
pointer is not dereferenced. This is not by accident - all
implementations take special care to do this.
The implementations you looked at may do that, but the NetBSD
implementation doesn't. NetBSD strlcpy does not allow a size-zero
destination if the destination pointer is null. See:
http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/common/lib/libc/string/strlcpy.c
NetBSD demonstrates that there's no need to support calls that specify
the null pointer and size zero.
* Three out of four strlcat implementations have well-defined behavior
(they return `destsize+strlen(src)` and leave the destination buffer
unchanged) when the destination buffer does not contain a terminating
nul. The other one blindly calls strlen() on the destination buffer,
and I very strongly suspect that this is an oversight.
You missed an oversight in the other three implementations: adding
destsize to strlen(src) can overflow when the destination buffer does
not contain a terminating NUL. This can cause strlcat to return a
numerically incorrect value, which could cause a caller to incorrectly
conclude that the result fits within the output buffer, leading to havoc.
It is this sort of thing that caused us to go to a more-conservative
spec, which says that the troublesome cases noted above have undefined
behavior.