This is less error-prone. Supply a mempcpy if the system lacks it. * Makefile, NEWS: Mention this. * localtime.c (tzloadbody, tzparse): * zic.c (random_dirent, relname, doabbr): * zdump.c (my_snprintf) [!HAVE_SNPRINTF]: (istrftime): Prefer mempcpy to doing it by hand. * private.h (HAVE_MEMPCPY): New macro. (mempcpy) [!HAVE_MEMPCPY]: New function. --- Makefile | 1 + NEWS | 3 +++ localtime.c | 13 +++++++------ private.h | 17 +++++++++++++++++ zdump.c | 11 +++++++---- zic.c | 36 ++++++++++++++++++++---------------- 6 files changed, 55 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index 83122ecc..5b577781 100644 --- a/Makefile +++ b/Makefile @@ -262,6 +262,7 @@ LDLIBS= # -DHAVE_LOCALTIME_RZ=0 if you do not want zdump to use localtime_rz # localtime_rz can make zdump significantly faster, but is nonstandard. # -DHAVE_MALLOC_ERRNO=0 if malloc etc. do not set errno on failure. +# -DHAVE_MEMPCPY=1 if your system has mempcpy, 0 if not (default is guessed) # -DHAVE_POSIX_DECLS=0 if your system's include files do not declare # functions like 'link' or variables like 'tzname' required by POSIX # -DHAVE_SETENV=0 if your system lacks the setenv function diff --git a/NEWS b/NEWS index 5c4786cb..0436c615 100644 --- a/NEWS +++ b/NEWS @@ -51,6 +51,9 @@ Unreleased, experimental changes -DHAVE_GETRESUID=[01], and -DHAVE_GETEUID=[01] to enable or disable these system calls' use. + tzcode now uses mempcpy if available, guessing its availability. + Compile with -DHAVE_MEMPCPY=1 or 0 to override the guess. + tzcode now uses strnlen to improve asymptotic performance a bit. Compile with -DHAVE_STRNLEN=0 if your platform lacks it. diff --git a/localtime.c b/localtime.c index 67500312..316c7504 100644 --- a/localtime.c +++ b/localtime.c @@ -624,6 +624,7 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags, } if (!SUPPRESS_TZDIR && name[0] != '/') { + char *cp; if (sizeof lsp->fullname - sizeof tzdirslash <= strnlen(name, sizeof lsp->fullname - sizeof tzdirslash)) return ENAMETOOLONG; @@ -631,8 +632,9 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags, /* Create a string "TZDIR/NAME". Using sprintf here would pull in stdio (and would fail if the resulting string length exceeded INT_MAX!). */ - memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash); - strcpy(lsp->fullname + sizeof tzdirslash, name); + cp = lsp->fullname; + cp = mempcpy(cp, tzdirslash, sizeof tzdirslash); + strcpy(cp, name); name = lsp->fullname; } @@ -1471,12 +1473,11 @@ tzparse(const char *name, struct state *sp, struct state const *basep) } sp->charcnt = charcnt; cp = sp->chars; - memcpy(cp, stdname, stdlen); - cp += stdlen; + cp = mempcpy(cp, stdname, stdlen); *cp++ = '\0'; if (dstlen != 0) { - memcpy(cp, dstname, dstlen); - *(cp + dstlen) = '\0'; + cp = mempcpy(cp, dstname, dstlen); + *cp = '\0'; } return true; } diff --git a/private.h b/private.h index 6ae0c2fd..867340fa 100644 --- a/private.h +++ b/private.h @@ -837,6 +837,23 @@ extern char *asctime_r(struct tm const *restrict, char *restrict); extern char **environ; #endif +#ifndef HAVE_MEMPCPY +# if (defined mempcpy \ + || defined __FreeBSD__ || defined __NetBSD__ || defined __linux__) +# define HAVE_MEMPCPY 1 +# else +# define HAVE_MEMPCPY 0 +# endif +#endif +#if !HAVE_MEMPCPY +static void * +mempcpy(char *restrict s1, char const *restrict s2, size_t n) +{ + char *p = memcpy(s1, s2, n); + return p + n; +} +#endif + #if 2 <= HAVE_TZNAME + (TZ_TIME_T || !HAVE_POSIX_DECLS) extern char *tzname[]; #endif diff --git a/zdump.c b/zdump.c index 8e836e60..93fe05cb 100644 --- a/zdump.c +++ b/zdump.c @@ -927,6 +927,7 @@ my_snprintf(char *s, size_t size, char const *format, ...) int n; va_list args; char const *arg; + char *cp; size_t arglen, slen; char buf[1024]; va_start(args, format); @@ -943,8 +944,9 @@ my_snprintf(char *s, size_t size, char const *format, ...) arglen = n; } slen = arglen < size ? arglen : size - 1; - memcpy(s, arg, slen); - s[slen] = '\0'; + cp = s; + cp = mempcpy(cp, arg, slen); + *cp = '\0'; n = arglen <= INT_MAX ? arglen : -1; va_end(args); return n; @@ -1073,8 +1075,9 @@ istrftime(char *buf, ptrdiff_t size, char const *time_fmt, char fbuf[100]; bool oversized = sizeof fbuf <= f_prefix_copy_size; char *f_prefix_copy = oversized ? xmalloc(f_prefix_copy_size) : fbuf; - memcpy(f_prefix_copy, f, f_prefix_len); - strcpy(f_prefix_copy + f_prefix_len, "X"); + char *cp = f_prefix_copy; + cp = mempcpy(cp, f, f_prefix_len); + strcpy(cp, "X"); formatted_len = strftime(b, s, f_prefix_copy, tm); if (oversized) free(f_prefix_copy); diff --git a/zic.c b/zic.c index 6bdb039d..e78dfd47 100644 --- a/zic.c +++ b/zic.c @@ -1327,10 +1327,10 @@ random_dirent(char const **name, char **namealloc) uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6); if (!dst) { - dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); - memcpy(dst, src, dirlen); - memcpy(dst + dirlen, prefix, prefixlen); - dst[dirlen + prefixlen + suffixlen] = '\0'; + char *cp = dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); + cp = mempcpy(cp, src, dirlen); + cp = mempcpy(cp, prefix, prefixlen); + cp[suffixlen] = '\0'; *name = *namealloc = dst; } @@ -1430,15 +1430,17 @@ relname(char const *target, char const *linkname) if (*linkname == '/') { /* Make F absolute too. */ size_t len = strlen(directory); - size_t lenslash = len + (len && directory[len - 1] != '/'); + bool needs_slash = len && directory[len - 1] != '/'; + size_t lenslash = len + needs_slash; size_t targetsize = strlen(target) + 1; + char *cp; if (*directory != '/') return NULL; linksize = size_sum(lenslash, targetsize); - f = result = xmalloc(linksize); - memcpy(result, directory, len); - result[len] = '/'; - memcpy(result + lenslash, target, targetsize); + f = cp = result = xmalloc(linksize); + cp = mempcpy(cp, directory, len); + *cp = '/'; + memcpy(cp + needs_slash, target, targetsize); } for (i = 0; f[i] && f[i] == linkname[i]; i++) if (f[i] == '/') @@ -1448,11 +1450,13 @@ relname(char const *target, char const *linkname) taillen = strlen(f + dir_len); dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1); if (dotdotetcsize <= linksize) { + char *cp; if (!result) result = xmalloc(dotdotetcsize); + cp = result; for (i = 0; i < dotdots; i++) - memcpy(result + 3 * i, "../", 3); - memmove(result + 3 * dotdots, f + dir_len, taillen + 1); + cp = mempcpy(cp, "../", 3); + memmove(cp, f + dir_len, taillen + 1); } return result; } @@ -2875,11 +2879,11 @@ doabbr(char *abbr, struct zone const *zp, char const *letters, else if (letters == disable_percent_s) return 0; sprintf(abbr, format, letters); - } else if (isdst) { - strcpy(abbr, slashp + 1); - } else { - memcpy(abbr, format, slashp - format); - abbr[slashp - format] = '\0'; + } else if (isdst) + strcpy(abbr, slashp + 1); + else { + char *abbrend = mempcpy(abbr, format, slashp - format); + *abbrend = '\0'; } len = strlen(abbr); if (!doquotes) -- 2.48.1