Mail Archives: djgpp-workers/2003/01/12/08:09:43
Hello.
Below is revision 3 of the strlcat, strlcpy patch. Changes:
* Suggest what might happen with overlapping buffers. The behaviour
is undefined, since we don't cope with overlapping buffers.
* strncat always nul-terminates. Remove a comment about it not doing
that from the strlcat info page. (Thanks for catching that Eli.
I confused that particular behaviour from strncpy with strncat.)
OK to commit?
Bye, Rich =]
Index: include/string.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/string.h,v
retrieving revision 1.5
diff -p -c -3 -r1.5 string.h
*** include/string.h 5 Dec 2000 14:05:53 -0000 1.5
--- include/string.h 12 Jan 2003 13:06:27 -0000
***************
*** 1,3 ****
--- 1,5 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
+ /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
*************** char * rindex(const char *_string, int
*** 62,67 ****
--- 64,71 ----
char * stpcpy(char *_dest, const char *_src);
char * stpncpy(char *_dest, const char *_src, size_t _n);
char * strdup(const char *_s);
+ size_t strlcat(char *_dest, const char *_src, size_t _size);
+ size_t strlcpy(char *_dest, const char *_src, size_t _size);
char * strlwr(char *_s);
int strcasecmp(const char *_s1, const char *_s2);
int stricmp(const char *_s1, const char *_s2);
Index: src/libc/compat/string/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/string/makefile,v
retrieving revision 1.6
diff -p -c -3 -r1.6 makefile
*** src/libc/compat/string/makefile 17 Oct 2002 23:00:25 -0000 1.6
--- src/libc/compat/string/makefile 12 Jan 2003 13:06:27 -0000
***************
*** 1,3 ****
--- 1,5 ----
+ # Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details
+ # Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details
# Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details
# Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details
# Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
*************** SRC += stpncpy.c
*** 11,16 ****
--- 13,20 ----
SRC += strcasec.S
SRC += strdup.c
SRC += stricmp.c
+ SRC += strlcat.c
+ SRC += strlcpy.c
SRC += strlwr.c
SRC += strncase.S
SRC += strnicmp.c
Index: src/docs/kb/wc204.txi
===================================================================
RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v
retrieving revision 1.132
diff -p -c -3 -r1.132 wc204.txi
*** src/docs/kb/wc204.txi 8 Jan 2003 20:18:00 -0000 1.132
--- src/docs/kb/wc204.txi 12 Jan 2003 13:06:32 -0000
*************** to @code{getenv} which are not needed.
*** 836,838 ****
--- 836,842 ----
@findex strtof
The function @code{strtof} was added.
+
+ @findex strlcat
+ @findex strlcpy
+ The functions @code{strlcat} and @code{strlcpy} were added.
Index: tests/libc/compat/string/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/compat/string/makefile,v
retrieving revision 1.2
diff -p -c -3 -r1.2 makefile
*** tests/libc/compat/string/makefile 3 Aug 2000 11:17:12 -0000 1.2
--- tests/libc/compat/string/makefile 12 Jan 2003 13:06:32 -0000
*************** TOP=../..
*** 3,7 ****
--- 3,9 ----
SRC += ffs.c
SRC += stpcpy.c
SRC += stpncpy.c
+ SRC += t-stlcat.c
+ SRC += t-stlcpy.c
include $(TOP)/../makefile.inc
*** /dev/null Sun Jan 12 13:07:53 2003
--- src/libc/compat/string/strlcat.c Thu Jan 9 21:16:20 2003
***************
*** 0 ****
--- 1,32 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
+ /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
+ #include <string.h>
+
+ size_t
+ strlcat (char *dst, const char *src, size_t size)
+ {
+ const size_t srclen = strlen(src);
+ size_t dstlen = 0;
+ size_t i;
+
+ /* Find the length of dst. Don't go past the size'th element. */
+ for (i = 0; i < size; i++) { if (dst[i] == '\0') break; }
+
+ if (i == size)
+ /* dst is not nul terminated. As per OpenBSD and NetBSD, return
+ * the sum of the buffer length and srclen. */
+ return(size + srclen);
+ else
+ dstlen = i;
+
+ if ((dstlen + srclen) < size) {
+ /* Enough space - just copy the string. */
+ strcpy(dst + dstlen, src);
+ } else {
+ /* Truncate the string to fit. */
+ memcpy(dst + dstlen, src, size - dstlen - 1);
+ dst[size - 1] = '\0';
+ }
+
+ return(dstlen + srclen);
+ }
*** /dev/null Sun Jan 12 13:07:53 2003
--- src/libc/compat/string/strlcat.txh Sun Jan 12 13:05:34 2003
***************
*** 0 ****
--- 1,61 ----
+ @node strlcat, string
+ @subheading Syntax
+
+ @example
+ #include <string.h>
+
+ size_t strlcat (char *dest, const char *src, size_t size);
+ @end example
+
+ @subheading Description
+
+ Concatenate characters from @var{src} to @var{dest} and nul-terminate
+ the resulting string. As much of @var{src} is copied into @var{dest}
+ as there is space for.
+
+ @var{size} should be the size of the destination string buffer @var{dest}
+ plus the space for the nul-terminator. @var{size} may be computed
+ in many cases using the @code{sizeof} operator.
+
+ @code{strlcat} may be used as a less ambiguous alternative
+ to @code{strncat} (@pxref{strncat}).
+
+ If @var{dest} is not nul-terminated, then @var{dest} is not modified.
+
+ @code{strlcat} will not examine more than @var{size} characters
+ of @var{dest}. This is to avoid overrunning the buffer @var{dest}.
+
+ If @var{dest} and @var{src} are overlapping buffers, the behavior
+ is undefined. One possible result is a buffer overrun - accessing
+ out-of-bounds memory.
+
+ @subheading Return Value
+
+ The length of the string that @code{strlcat} tried to create is returned,
+ whether or not @code{strlcat} could store it in @var{dest}. If all
+ of @var{src} was concatenated to @var{dst}, the return value will be less
+ than @var{size}.
+
+ If @var{dest} is not nul-terminated, then @code{strlcat} will consider
+ @var{dest} to be @var{size} in length and return @var{size} plus
+ the length of @var{src}.
+
+ @subheading Portability
+
+ @portability !ansi, !posix
+
+ @subheading Example
+
+ The following example shows how you can check that
+ the destination string buffer was large enough to store
+ the source string concatenated to the destination string.
+ In this case @code{somestring} is truncated, when it is concatenated
+ to @code{buf}.
+
+ @example
+ const char somestring[] = "bar";
+ char buf[5] = "foo";
+
+ if (strlcat(buf, somestring, sizeof(buf)) >= sizeof(buf))
+ puts("somestring was truncated, when concatenating to buf.");
+ @end example
*** /dev/null Sun Jan 12 13:07:53 2003
--- src/libc/compat/string/strlcpy.c Thu Jan 9 20:59:12 2003
***************
*** 0 ****
--- 1,24 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
+ /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
+ #include <string.h>
+
+ size_t
+ strlcpy (char *dst, const char *src, size_t size)
+ {
+ const size_t srclen = strlen(src);
+ const size_t ret = srclen;
+
+ if (!size)
+ return(ret); /* No space at all. */
+
+ if (srclen < size) {
+ /* Enough space - just copy the string. */
+ strcpy(dst, src);
+ } else {
+ /* Truncate the string to fit. */
+ memcpy(dst, src, size - 1);
+ dst[size - 1] = '\0';
+ }
+
+ return(ret);
+ }
*** /dev/null Sun Jan 12 13:07:53 2003
--- src/libc/compat/string/strlcpy.txh Sun Jan 12 12:55:50 2003
***************
*** 0 ****
--- 1,50 ----
+ @node strlcpy, string
+ @subheading Syntax
+
+ @example
+ #include <string.h>
+
+ size_t strlcpy (char *dest, const char *src, size_t size);
+ @end example
+
+ @subheading Description
+
+ Copy characters from @var{src} to @var{dest} and nul-terminate
+ the resulting string. Up to @code{@var{size} - 1} characters are
+ copied to @var{dest}.
+
+ @var{size} should be the size of the destination string buffer @var{dest}
+ plus the space for the nul-terminator. @var{size} may be computed
+ in many cases using the @code{sizeof} operator.
+
+ @code{strlcpy} is a less ambiguous version of @code{strncpy}
+ (@pxref{strncpy}). Unlike @code{strncpy}, @code{strlcpy} @emph{always}
+ nul-terminates the destination @var{dest} for non-zero sizes @var{size}.
+
+ If @var{dest} and @var{src} are overlapping buffers, the behavior
+ is undefined. One possible result is a buffer overrun - accessing
+ out-of-bounds memory.
+
+ @subheading Return Value
+
+ The length of the string that @code{strlcpy} tried to create is returned,
+ whether or not @code{strlcpy} could store it in @var{dest}. If all
+ of @var{src} was copied, the return value will be less than @var{size}.
+
+ @subheading Portability
+
+ @portability !ansi, !posix
+
+ @subheading Example
+
+ The following example shows how you can check that
+ the destination string buffer was large enough to store the source string.
+ In this case @code{somestring} is truncated to fit into @code{buf}.
+
+ @example
+ const char somestring[] = "foo";
+ char buf[3];
+
+ if (strlcpy(buf, somestring, sizeof(buf)) >= sizeof(buf))
+ puts("somestring was truncated, when copying to buf.");
+ @end example
*** /dev/null Sun Jan 12 13:07:53 2003
--- tests/libc/compat/string/t-stlcat.c Thu Jan 9 21:20:14 2003
***************
*** 0 ****
--- 1,91 ----
+ #include <assert.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+
+ #define FILL_CHAR 'X'
+
+ static void
+ check_too_small (const char *somestring,
+ char *buf2, const size_t buf2size,
+ const size_t fakesize)
+ {
+ const size_t len_somestring = strlen(somestring);
+ int i;
+
+ assert(fakesize < buf2size);
+
+ memset(buf2, FILL_CHAR, buf2size);
+ strcpy(buf2, somestring);
+
+ assert(strlcat(buf2, somestring, fakesize) >= fakesize);
+ assert(strncmp(buf2, somestring, len_somestring) == 0);
+ assert(strncmp(buf2 + len_somestring, somestring,
+ fakesize - len_somestring - 1) == 0);
+ assert(buf2[fakesize - 1] == '\0');
+ for (i = fakesize; i < buf2size; i++) {
+ assert(buf2[i] == FILL_CHAR);
+ }
+ }
+
+ int
+ main (void)
+ {
+ const char somestring[] = "somestring";
+ const size_t len_somestring = strlen(somestring);
+ char buf[22]; /* More than big enough to contain two somestrings. */
+ char buf2[20]; /* Just too small to contain two somestrings. */
+ int i;
+
+ /* Try a zero size. Check that the buffer is untouched. */
+ memset(buf, FILL_CHAR, sizeof(buf));
+ buf[0] = '\0'; /* Make buf a valid string. */
+
+ assert(strlcat(buf, somestring, 0) == strlen(somestring));
+ for (i = 1; i < sizeof(buf); i++) {
+ assert(buf[i] == FILL_CHAR);
+ }
+
+ /* Check that two strings fit into buf. Check that it hasn't overrun. */
+ memset(buf, FILL_CHAR, sizeof(buf));
+ strcpy(buf, somestring);
+
+ assert(strlcat(buf, somestring, sizeof(buf)) < sizeof(buf));
+ assert(strncmp(buf, somestring, len_somestring) == 0);
+ assert(strncmp(buf + len_somestring, somestring, len_somestring) == 0);
+ assert(buf[sizeof(buf) - 1] == FILL_CHAR);
+
+ /* Check that two strings just fail to fit into buf2. Check
+ * its nul-termination. */
+ memset(buf2, FILL_CHAR, sizeof(buf2));
+ strcpy(buf2, somestring);
+
+ assert(strlcat(buf2, somestring, sizeof(buf2)) >= sizeof(buf2));
+ assert(strncmp(buf2, somestring, len_somestring) == 0);
+ assert(strncmp(buf2 + len_somestring, somestring,
+ sizeof(buf2) - len_somestring - 1) == 0);
+ assert(buf2[sizeof(buf2) - 1] == '\0');
+
+ /* Copy somestring into a way-too-small buffer. Lie about the size
+ * of the buffer and check for buffer overrun. */
+
+ /* Case 1: None of the source string will fit. */
+ check_too_small(somestring, buf2, sizeof(buf2), sizeof(somestring));
+
+ /* Case 2: Some of the source string will fit. */
+ check_too_small(somestring, buf2, sizeof(buf2), sizeof(somestring) + 1);
+ check_too_small(somestring, buf2, sizeof(buf2), sizeof(somestring) + 2);
+ check_too_small(somestring, buf2, sizeof(buf2), sizeof(somestring) + 4);
+
+ /* Check that copying into a buffer that is not nul-terminated
+ * returns size of destination buffer plus the length of string
+ * we're concatenating. */
+ memset(buf, FILL_CHAR, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+
+ assert( strlcat(buf, somestring, sizeof(buf) - 1)
+ == (sizeof(buf) - 1 + strlen(somestring)));
+
+ puts("PASS");
+ return(EXIT_SUCCESS);
+ }
*** /dev/null Sun Jan 12 13:07:53 2003
--- tests/libc/compat/string/t-stlcpy.c Tue Dec 17 18:00:22 2002
***************
*** 0 ****
--- 1,57 ----
+ #include <assert.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+
+ #define FILL_CHAR 'X'
+
+ int
+ main (void)
+ {
+ const char somestring[] = "somestring";
+ char buf[12]; /* More than big enough to contain somestring */
+ char buf2[10]; /* Just too small to contain somestring. */
+ int i;
+
+ /* Try a zero size. Check that the buffer is untouched. */
+ memset(buf, FILL_CHAR, sizeof(buf));
+
+ assert(strlcpy(buf, somestring, 0) == strlen(somestring));
+ for (i = 0; i < sizeof(buf); i++) {
+ assert(buf[i] == FILL_CHAR);
+ }
+
+ /* Copy somestring into a large-enough buffer. Check that it hasn't
+ * overrun. */
+ memset(buf, FILL_CHAR, sizeof(buf));
+
+ assert(strlcpy(buf, somestring, sizeof(buf)) < sizeof(buf));
+ assert(strcmp(buf, somestring) == 0);
+ assert(buf[sizeof(buf) - 1] == FILL_CHAR);
+
+ /* Copy somestring into a just-too-small buffer. Check
+ * its nul-termination. */
+ memset(buf2, FILL_CHAR, sizeof(buf2));
+
+ assert(strlcpy(buf2, somestring, sizeof(buf2)) == sizeof(buf2));
+ assert(strncmp(buf2, somestring, sizeof(buf2) - 1) == 0);
+ assert(buf2[sizeof(buf2) - 1] == '\0');
+
+ /* Copy somestring into a way-too-small buffer. Lie about the size
+ * of the buffer and check for buffer overrun. */
+ #define MADE_UP_SIZE 3
+ assert(MADE_UP_SIZE < sizeof(buf2));
+
+ memset(buf2, FILL_CHAR, sizeof(buf2));
+
+ assert(strlcpy(buf2, somestring, MADE_UP_SIZE) >= MADE_UP_SIZE);
+ assert(strncmp(buf2, somestring, MADE_UP_SIZE - 1) == 0);
+ assert(buf2[MADE_UP_SIZE - 1] == '\0');
+ for (i = MADE_UP_SIZE; i < sizeof(buf2); i++) {
+ assert(buf2[i] == FILL_CHAR);
+ }
+ #undef MADE_UP_SIZE
+
+ puts("PASS");
+ return(EXIT_SUCCESS);
+ }
- Raw text -