Skip to content

Commit

Permalink
lib/string/: Redesign stpecpy() and stpeprintf()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Alejandro Colomar <[email protected]>
  • Loading branch information
alejandro-colomar committed Feb 8, 2025
1 parent 8a5852a commit 62d3f05
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 30 deletions.
26 changes: 9 additions & 17 deletions lib/string/sprintf/stpeprintf.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@

#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>

#include "attr.h"
#include "string/sprintf/snprintf.h"


#if !defined(HAVE_STPEPRINTF)
Expand Down Expand Up @@ -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.
*/


Expand All @@ -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;
}
Expand Down
27 changes: 14 additions & 13 deletions lib/string/strcpy/stpecpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/


Expand All @@ -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;

Expand All @@ -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

Expand Down

0 comments on commit 62d3f05

Please sign in to comment.