delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2003/01/08/15:30:41

Sender: rich AT phekda DOT freeserve DOT co DOT uk
Message-ID: <3E1C792F.10D665E6@phekda.freeserve.co.uk>
Date: Wed, 08 Jan 2003 19:17:03 +0000
From: Richard Dawe <rich AT phekda DOT freeserve DOT co DOT uk>
X-Mailer: Mozilla 4.77 [en] (X11; U; Linux 2.2.23 i586)
X-Accept-Language: de,fr
MIME-Version: 1.0
To: djgpp-workers AT delorie DOT com
Subject: RESEND: strlcat, strlcpy [PATCH]
Reply-To: djgpp-workers AT delorie DOT com

[Could someone review this patch, please?]

Hello.

Below is a patch to add the strlcat and strlcpy functions to DJGPP.
These have a better interface than their strn* equivalents, which makes
it easier to write code without buffer overflows. These interfaces
were designed by the OpenBSD team.

You can read the original paper here:

    http://www.openbsd.org/papers/strlcpy-paper.ps

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	17 Dec 2002 18:09:26 -0000
***************
*** 1,3 ****
--- 1,4 ----
+ /* 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 ****
--- 63,70 ----
  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	17 Dec 2002 18:09:26 -0000
***************
*** 1,3 ****
--- 1,4 ----
+ # 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 ****
--- 12,19 ----
  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.128
diff -p -c -3 -r1.128 wc204.txi
*** src/docs/kb/wc204.txi	15 Dec 2002 09:30:52 -0000	1.128
--- src/docs/kb/wc204.txi	17 Dec 2002 18:09:40 -0000
*************** Windows 2000 and XP.
*** 820,822 ****
--- 820,826 ----
  The functions @code{imaxabs}, @code{imaxdiv}, @code{strtoimax}
  and @code{strtoumax} were added.  The @code{PRI} and @code{SCN} families
  of macros were 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	17 Dec 2002 18:09:41 -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	Tue Dec 17 18:10:21 2002
--- src/libc/compat/string/strlcat.c	Tue Dec 10 21:05:14 2002
***************
*** 0 ****
--- 1,26 ----
+ /* 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);
+   const size_t dstlen = strlen(dst);
+   const size_t ret    = srclen + dstlen;
+ 
+   /* No space at all or dst is already full. size should be > dstlen,
+    * otherwise it's likely we have an invalid string. */
+   if (!size || (dstlen >= size))
+     return(ret);
+ 
+   if (ret < 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(ret);
+ }
*** /dev/null	Tue Dec 17 18:10:21 2002
--- src/libc/compat/string/strlcat.txh	Tue Dec 17 17:07:50 2002
***************
*** 0 ****
--- 1,50 ----
+ @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}).  Unlike @code{strncat},
+ @code{strlcat} @emph{always} nul-terminates the destination @var{dest}
+ for non-zero sizes @var{size}.
+ 
+ @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}.
+ 
+ @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	Tue Dec 17 18:10:21 2002
--- src/libc/compat/string/strlcpy.c	Tue Dec 10 21:05:32 2002
***************
*** 0 ****
--- 1,23 ----
+ /* 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	Tue Dec 17 18:10:22 2002
--- src/libc/compat/string/strlcpy.txh	Tue Dec 17 16:57:06 2002
***************
*** 0 ****
--- 1,46 ----
+ @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}.
+ 
+ @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	Tue Dec 17 18:10:22 2002
--- tests/libc/compat/string/t-stlcat.c	Tue Dec 17 18:08:06 2002
***************
*** 0 ****
--- 1,82 ----
+ #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);
+ 
+   puts("PASS");
+   return(EXIT_SUCCESS);
+ }
*** /dev/null	Tue Dec 17 18:10:22 2002
--- 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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019