This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH v8] Implement strlcpy and strlcat [BZ #178]
- From: Alexander Cherepanov <cherepan at mccme dot ru>
- To: Florian Weimer <fweimer at redhat dot com>, GNU C Library <libc-alpha at sourceware dot org>
- Date: Mon, 11 Jan 2016 03:00:14 +0300
- Subject: Re: [PATCH v8] Implement strlcpy and strlcat [BZ #178]
- Authentication-results: sourceware.org; auth=none
- References: <56902FA4 dot 7070002 at redhat dot com>
On 2016-01-09 00:52, Florian Weimer wrote:
+size_t
+strlcat (char *__restrict dest, const char *__restrict src, size_t size)
+{
+ size_t src_length = strlen (src);
+
+ /* Our implementation strlcat supports dest == NULL if size == 0
+ (for consistency with snprintf and strlcpy), but strnlen does
+ not, so we have to cover this case explicitly. */
+ if (size == 0)
+ return src_length;
+
+ size_t dest_length = __strnlen (dest, size);
+ if (dest_length != size)
+ {
+ /* Copy at most the remaining number of characters in the
+ destination buffer. Leave for the NUL terminator. */
+ size_t to_copy = size - dest_length - 1;
+ /* But not more than what is available in the source string. */
+ if (to_copy > src_length)
+ to_copy = src_length;
+
+ char *target = dest + dest_length;
+ memcpy (target, src, to_copy);
+ target[to_copy] = '\0';
+ }
+
+ /* The sum cannot wrap around because both strings would be larger
+ than half of the address space, which is not possible due to
+ the restrict qualifier. */
+ _Static_assert (sizeof (uintptr_t) == sizeof (size_t),
+ "theoretical maximum object size covers address space");
+ return dest_length + src_length;
+}
First, I don't think the last comment is fully accurate -- both strings
are not required to be larger than half of the address space each, 1.5GB
and 3GB are enough for wrapping with 32-bit size_t.
Second, AIUI the full story is like this: strlcat (as documented in the
latest version) requires @var{to} to contain a null byte in its first
@var{size} bytes, hence @var{to} and @var{from} both being a sequence of
non-nulls followed by a mandatory null can overlap only when their
trailing nulls are the same. But the trailing null in @var{to} is
overwritten while the trailing null in @var{from} is read which
contradicts the restrict qualifier. Hence the strings don't overlap.
If you permit @var{to} to be non-null-terminated the situation is worse
-- it doesn't write anything and resrict doesn't come into play. Then
the following is defined and should return 5GB on 32-bit arch:
size_t gb = (size_t)1024 * 1024 * 1024;
s = malloc(3 * gb);
memset(s, 'A', 3 * gb);
strlcat(s, s, 2 * gb);
--
Alexander Cherepanov