Well, my ADD has caused me to refocus my attention back to the issues of strlcat() and strlcpy(). I started some conversion several months ago, but other things have interrupted me. Late last week, I took a look at what I had started, and wasn't exceptionally impressed with what I saw. Although my initial patch did provide the benefits of strlcat() and strlcpy() to the core and module writers on systems with those functions in libc, elsewhere, people were still out in the cold.
The attached patch helps to fix that. It adds two new functions to util.c: Perl_my_strlcat() and Perl_my_strlcpy(). These functions provide all the functionality that strlcat() and strlcpy() provide in systems where these functions are not included in libc. The code for these functions were originally released as part of C<inn>, but the code for strlcat() and strlcpy() within C<inn> was released into the public domain. The code required few modifications to be worked into Perl, but are mostly as Russ Allbery original had written them. Thanks Russ! The patch included was tested on Linux, with and without ithreads and DEBUGGING, and passed all of its tests. Steve Peters [EMAIL PROTECTED]
--- doio.c.old 2005-06-23 05:49:45.000000000 -0500 +++ doio.c 2005-06-27 09:37:50.807826128 -0500 @@ -274,17 +274,10 @@ } mode[0] = 'w'; writing = 1; -#ifdef HAS_STRLCAT if (out_raw) strlcat(mode, "b", PERL_MODE_MAX); else if (out_crlf) strlcat(mode, "t", PERL_MODE_MAX); -#else - if (out_raw) - strcat(mode, "b"); - else if (out_crlf) - strcat(mode, "t"); -#endif if (num_svs > 1) { fp = PerlProc_popen_list(mode, num_svs, svp); } @@ -312,17 +305,10 @@ } writing = 1; -#ifdef HAS_STRLCAT if (out_raw) strlcat(mode, "b", PERL_MODE_MAX); else if (out_crlf) strlcat(mode, "t", PERL_MODE_MAX); -#else - if (out_raw) - strcat(mode, "b"); - else if (out_crlf) - strcat(mode, "t"); -#endif if (*type == '&') { duplicity: dodup = PERLIO_DUP_FD; @@ -440,17 +426,10 @@ else if (*type == IoTYPE_RDONLY) { for (type++; isSPACE(*type); type++) ; mode[0] = 'r'; -#ifdef HAS_STRLCAT if (in_raw) strlcat(mode, "b", PERL_MODE_MAX); else if (in_crlf) strlcat(mode, "t", PERL_MODE_MAX); -#else - if (in_raw) - strcat(mode, "b"); - else if (in_crlf) - strcat(mode, "t"); -#endif if (*type == '&') { goto duplicity; } @@ -501,17 +480,10 @@ TAINT_PROPER("piped open"); mode[0] = 'r'; -#ifdef HAS_STRLCAT if (in_raw) strlcat(mode, "b", PERL_MODE_MAX); else if (in_crlf) strlcat(mode, "t", PERL_MODE_MAX); -#else - if (in_raw) - strcat(mode, "b"); - else if (in_crlf) - strcat(mode, "t"); -#endif if (num_svs > 1) { fp = PerlProc_popen_list(mode,num_svs,svp); @@ -538,17 +510,10 @@ ; mode[0] = 'r'; -#ifdef HAS_STRLCAT if (in_raw) strlcat(mode, "b", PERL_MODE_MAX); else if (in_crlf) strlcat(mode, "t", PERL_MODE_MAX); -#else - if (in_raw) - strcat(mode, "b"); - else if (in_crlf) - strcat(mode, "t"); -#endif if (*name == '-' && name[1] == '\0') { fp = PerlIO_stdin(); @@ -1532,19 +1497,11 @@ char flags[PERL_FLAGS_MAX]; if (strnEQ(cmd,PL_cshname,PL_cshlen) && strnEQ(cmd+PL_cshlen," -c",3)) { -#ifdef HAS_STRLCPY - strlcpy(flags, "-c", PERL_FLAGS_MAX); -#else - strcpy(flags,"-c"); -#endif + strlcpy(flags, "-c", PERL_FLAGS_MAX); s = cmd+PL_cshlen+3; if (*s == 'f') { s++; -#ifdef HAS_STRLCPY strlcat(flags, "f", PERL_FLAGS_MAX); -#else - strcat(flags,"f"); -#endif } if (*s == ' ') s++; --- embed.fnc.old 2005-06-24 09:30:49.000000000 -0500 +++ embed.fnc 2005-06-25 08:35:49.000000000 -0500 @@ -488,6 +488,12 @@ Ap |void |my_setenv |const char* nam|const char* val Ap |I32 |my_stat Ap |char * |my_strftime |const char *fmt|int sec|int min|int hour|int mday|int mon|int year|int wday|int yday|int isdst +#if !defined(HAS_STRLCAT) +Ap |size_t |my_strlcat |char *dst|const char* src|size_t size +#endif +#if !defined(HAS_STRLCPY) +Ap |size_t |my_strlcpy |char *dst|const char* src|size_t size +#endif #if defined(MYSWAP) ApPa |short |my_swap |short s ApPa |long |my_htonl |long l --- op.c.old 2005-06-20 04:35:16.000000000 -0500 +++ op.c 2005-06-27 10:24:29.097421448 -0500 @@ -223,7 +223,8 @@ /* The next block assumes the buffer is at least 205 chars long. At present, it's always at least 256 chars. */ if (p-name > 200) { - strcpy(name+200, "..."); + char *dot_dot = name + 200; + strlcpy(dot_dot, "...", sizeof("...")); p = name+199; } else { --- perl.h.old 2005-06-24 09:25:41.000000000 -0500 +++ perl.h 2005-06-27 10:42:16.820102928 -0500 @@ -978,6 +978,14 @@ # endif #endif /* !HAS_BCMP */ +#ifndef HAS_STRLCAT +# define strlcat(d,s,sz) my_strlcat(aTHX_ d,s,sz) +#endif + +#ifndef HAS_STRLCPY +# define strlcpy(d,s,sz) my_strlcpy(aTHX_ d,s,sz) +#endif + #ifdef I_NETINET_IN # include <netinet/in.h> #endif --- pp_ctl.c.old 2005-06-23 14:23:56.000000000 -0500 +++ pp_ctl.c 2005-06-27 10:25:13.779628720 -0500 @@ -3485,7 +3485,7 @@ ret = doeval(gimme, NULL, runcv, seq); if (PERLDB_INTER && was != (I32)PL_sub_generation /* Some subs defined here. */ && ret != PL_op->op_next) { /* Successive compilation. */ - strcpy(safestr, "_<(eval )"); /* Anything fake and short. */ + strlcpy(safestr, "_<(eval )", strlen(safestr) + 1); /* Anything fake and short. */ } return DOCATCH(ret); } --- pp_sys.c.old 2005-06-24 03:09:51.000000000 -0500 +++ pp_sys.c 2005-06-27 09:35:29.548300840 -0500 @@ -3721,14 +3721,15 @@ PerlIO *myfp; int anum = 1; - New(666, cmdline, strlen(cmd) + (strlen(filename) * 2) + 10, char); - strcpy(cmdline, cmd); - strcat(cmdline, " "); + const int size = strlen(cmd) + (strlen(filename) * 2) + 10; + New(666, cmdline, size, char); + strlcpy(cmdline, cmd, size); + strlcat(cmdline, " ", size); for (s = cmdline + strlen(cmdline); *filename; ) { *s++ = '\\'; *s++ = *filename++; } - strcpy(s, " 2>&1"); + strlcpy(s, " 2>&1", size); myfp = PerlProc_popen(cmdline, "r"); Safefree(cmdline); --- sv.c.old 2005-06-24 09:30:49.000000000 -0500 +++ sv.c 2005-06-27 09:30:01.173221440 -0500 @@ -3308,7 +3308,8 @@ s = SvGROW_mutable(sv, len + 1); SvCUR_set(sv, len); SvPOKp_on(sv); - return strcpy(s, t); + (void)strlcpy(s,t,len + 1); + return s; } } 768c768,769 < return strcpy(newaddr,pv); --- > (void)strlcpy(newaddr,pv,pvlen); > return newaddr; 814a816 > int sz; 817,818c819,820 < < newaddr = (char*)PerlMemShared_malloc(strlen(pv)+1); --- > sz = strlen(pv)+1; > newaddr = (char*)PerlMemShared_malloc(sz); 824c826,827 < return strcpy(newaddr,pv); --- > (void)strlcpy(newaddr,pv,sz); > return newaddr; 2811c2814 < strcat(tmpbuf, scriptname); --- > strlcat(tmpbuf, scriptname, MAXPATHLEN); 2843c2846,2847 < cur = strcpy(tmpbuf, scriptname); --- > (void)strlcpy(tmpbuf, scriptname, MAXPATHLEN); > cur = tmpbuf; 4907a4912,4989 > #ifndef HAS_STRLCPY > > /* > * =for apidoc strlcpy > * > * This function copies from C<src> to C<dst> up to a maximum > * size of C<size>, and guarantees that C<dst> is NUL-terminated > * with a size no larger than C<size>. > * > * This function is included in Perl only when the system's libc > * does not already include a library function called > * C<strlcpy>. Thanks to macros to redefine the function name, > * C<my_strlcpy> should not be called directly. C<strlcpy> > * should be called instead. > * > * =cut > * */ > > /* > * This code originally written by Russ Allberry for C<inn> and > * released in the public domain. It was modified slightly for > * use within Perl. > */ > > size_t > Perl_my_strlcpy(pTHX_ char *dst, const char *src, size_t size) > { > size_t length, copy; > > length = strlen(src); > if (size > 0) { > copy = (length >= size) ? size - 1 : length; > memcpy(dst, src, copy); > dst[copy] = '\0'; > } > return length; > } > #endif > > #ifndef HAS_STRLCAT > /* > * =for apidoc strlcpy > * > * This function concatenates C<src> to C<dst> up to a maximum > * size of C<size>, and guarantees that C<dst> is NUL-terminated > * with a size no larger than C<size>. > * > * This function is included in Perl only when the system's libc > * does not already include a library function called > * C<strlcat>. Thanks to macros to redefine the function name, > * C<my_strlcat> should not be called directly. C<strlcat> > * should be called instead. > * > * =cut > * */ > > /* > * This code originally written by Russ Allberry for C<inn> and > * released in the public domain. It was modified slightly for > * use within Perl. > */ > > size_t > Perl_my_strlcat(pTHX_ char *dst, const char *src, size_t size) > { > size_t used, length, copy; > > used = strlen(dst); > length = strlen(src); > if (size > 0 && used < size - 1) { > copy = (length >= size - used) ? size - used - 1 : length; > memcpy(dst + used, src, copy); > dst[used + copy] = '\0'; > } > return used + length; > } > #endif >