Skip to content
This repository has been archived by the owner on Nov 21, 2022. It is now read-only.

Commit

Permalink
lib/string.c: implement stpcpy
Browse files Browse the repository at this point in the history
LLVM implemented a recent "libcall optimization" that lowers calls to
`sprintf(dest, "%s", str)` where the return value is used to
`stpcpy(dest, str) - dest`. This generally avoids the machinery involved
in parsing format strings.  Calling `sprintf` with overlapping arguments
was clarified in ISO C99 and POSIX.1-2001 to be undefined behavior.

`stpcpy` is just like `strcpy` except it returns the pointer to the new
tail of `dest`. This allows you to chain multiple calls to `stpcpy` in
one statement.

`stpcpy` was first standardized in POSIX.1-2008.

Implement this so that we don't observe linkage failures due to missing
symbol definitions for `stpcpy`.

Similar to last year's fire drill with:
commit 5f074f3 ("lib/string.c: implement a basic bcmp")

This optimization was introduced into clang-12.

Reported-by: Sami Tolvanen <samitolvanen@google.com>
Suggested-by: Arvind Sankar <nivedita@alum.mit.edu>
Suggested-by: Joe Perches <joe@perches.com>
Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
Tested-by: Sami Tolvanen <samitolvanen@google.com>
Cc: stable@vger.kernel.org
Link: https://bugs.llvm.org/show_bug.cgi?id=47162
Link: ClangBuiltLinux/linux#1126
Link: https://man7.org/linux/man-pages/man3/stpcpy.3.html
Link: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stpcpy.html
Link: https://reviews.llvm.org/D85963
Link: https://lore.kernel.org/r/20200815020946.1538085-1-ndesaulniers@google.com
Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
  • Loading branch information
nickdesaulniers authored and nathanchance committed Aug 17, 2020
1 parent 0f1fa58 commit f8199a9
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/linux/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ size_t strlcpy(char *, const char *, size_t);
#ifndef __HAVE_ARCH_STRSCPY
ssize_t strscpy(char *, const char *, size_t);
#endif
#ifndef __HAVE_ARCH_STPCPY
extern char *stpcpy(char *__restrict__, const char *__restrict__);
#endif

/* Wraps calls to strscpy()/memset(), no arch specific code required */
ssize_t strscpy_pad(char *dest, const char *src, size_t count);
Expand Down
23 changes: 23 additions & 0 deletions lib/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,29 @@ ssize_t strscpy_pad(char *dest, const char *src, size_t count)
}
EXPORT_SYMBOL(strscpy_pad);

#ifndef __HAVE_ARCH_STPCPY
/**
* stpcpy - copy a string from src to dest returning a pointer to the new end
* of dest, including src's NUL terminator. May overrun dest.
* @dest: pointer to end of string being copied into. Must be large enough
* to receive copy.
* @src: pointer to the beginning of string being copied from. Must not overlap
* dest.
*
* stpcpy differs from strcpy in two key ways:
* 1. inputs must not overlap.
* 2. return value is the new NULL terminated character. (for strcpy, the
* return value is a pointer to src.
*/
#undef stpcpy
char *stpcpy(char *__restrict__ dest, const char *__restrict__ src)
{
while ((*dest++ = *src++) != '\0')
/* nothing */;
return --dest;
}
#endif

#ifndef __HAVE_ARCH_STRCAT
/**
* strcat - Append one %NUL-terminated string to another
Expand Down

0 comments on commit f8199a9

Please sign in to comment.