From 62d3f05cf4666fb89d05a5238d7fc1626f4b903c Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Sat, 8 Feb 2025 14:41:16 +0100 Subject: [PATCH] lib/string/: Redesign stpecpy() and stpeprintf() Make them report truncation via errno and NULL. Instead of having three possible returns (a pointer to the NUL byte, the end of the array, or NULL), reduce it to two possible ones: one for success, and one for error. Use errno, which is a common way to signal the specific error, and thus treat truncation as any other error. This simplifies error handling after these calls. Also, if one misuses a pointer after truncation, the results are better if the pointer is NULL: the program will easily abort. If we returned 'end', the program could more easily produce a buffer overrun. Suggested-by: Douglas McIlroy Signed-off-by: Alejandro Colomar --- lib/string/sprintf/stpeprintf.h | 26 +++++++++----------------- lib/string/strcpy/stpecpy.h | 27 ++++++++++++++------------- 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/lib/string/sprintf/stpeprintf.h b/lib/string/sprintf/stpeprintf.h index ccd844bc2..3439d30f1 100644 --- a/lib/string/sprintf/stpeprintf.h +++ b/lib/string/sprintf/stpeprintf.h @@ -10,9 +10,9 @@ #include #include -#include #include "attr.h" +#include "string/sprintf/snprintf.h" #if !defined(HAVE_STPEPRINTF) @@ -57,20 +57,17 @@ inline char *vstpeprintf(char *dst, char *end, const char *restrict fmt, * * RETURN VALUE * dst + strlen(dst) - * • On success, these functions return a pointer to the - * terminating NUL byte. + * On success, these functions return a pointer to the + * terminating NUL byte. * - * end - * • If this call truncated the resulting string. - * • If `dst == end` (a previous chained call to these - * functions truncated). - * NULL - * • If this function failed (see ERRORS). - * • If `dst == NULL` (a previous chained call to these - * functions failed). + * NULL On error. * * ERRORS + * E2BIG The string was truncated. + * * These functions may fail for the same reasons as vsnprintf(3). + * + * If dst is NULL at input, this function doesn't clobber errno. */ @@ -97,18 +94,13 @@ vstpeprintf(char *dst, char *end, const char *restrict fmt, va_list ap) int len; ptrdiff_t size; - if (dst == end) - return end; if (dst == NULL) return NULL; size = end - dst; - len = vsnprintf(dst, size, fmt, ap); - + len = vsnprintf_(dst, size, fmt, ap); if (len == -1) return NULL; - if (len >= size) - return end; return dst + len; } diff --git a/lib/string/strcpy/stpecpy.h b/lib/string/strcpy/stpecpy.h index e9debe4ec..6ef98c561 100644 --- a/lib/string/strcpy/stpecpy.h +++ b/lib/string/strcpy/stpecpy.h @@ -47,19 +47,15 @@ inline char *stpecpy(char *dst, char *end, const char *restrict src); * * RETURN VALUE * dst + strlen(dst) - * • On success, this function returns a pointer to the - * terminating NUL byte. + * On success, this function returns a pointer to the + * terminating NUL byte. * - * end - * • If this call truncated the resulting string. - * • If `dst == end` (a previous chained call to these - * functions truncated). - * NULL - * • If `dst == NULL` (a previous chained call to - * [v]stpeprintf() failed). + * NULL On error. * * ERRORS - * This function doesn't set errno. + * E2BIG The string was truncated. + * + * If dst is NULL at input, this function doesn't clobber errno. */ @@ -68,10 +64,9 @@ inline char * stpecpy(char *dst, char *end, const char *restrict src) { bool trunc; + char *p; size_t dsize, dlen, slen; - if (dst == end) - return end; if (dst == NULL) return NULL; @@ -80,7 +75,13 @@ stpecpy(char *dst, char *end, const char *restrict src) trunc = (slen == dsize); dlen = slen - trunc; - return stpcpy(mempcpy(dst, src, dlen), "") + trunc; + p = stpcpy(mempcpy(dst, src, dlen), ""); + if (trunc) { + errno = E2BIG; + return NULL; + } + + return p; } #endif