diff options
| author | Joseph Myers <josmyers@redhat.com> | 2025-10-01 15:14:09 +0000 |
|---|---|---|
| committer | Joseph Myers <josmyers@redhat.com> | 2025-10-01 15:14:09 +0000 |
| commit | 0f201f4a817e39c01c502f523d4ea3c91f242767 (patch) | |
| tree | 363f693dbff6fd086faf1bfd89e014346837436e /string | |
| parent | a8ad2e9e431bac3ea207be07c64cddb72c290cde (diff) | |
Implement C23 memset_explicit (bug 32378)
Add the C23 memset_explicit function to glibc. Everything here is
closely based on the approach taken for explicit_bzero. This includes
the bits that relate to internal uses of explicit_bzero within glibc
(although we don't currently have any such internal uses of
memset_explicit), and also includes the nonnull attribute (when we
move to nonnull_if_nonzero for various functions following C2y, this
function should be included in that change).
The function is declared both for __USE_MISC and for __GLIBC_USE (ISOC23)
(so by default not just for compilers defaulting to C23 mode).
Tested for x86_64 and x86.
Diffstat (limited to 'string')
| -rw-r--r-- | string/Makefile | 6 | ||||
| -rw-r--r-- | string/Versions | 3 | ||||
| -rw-r--r-- | string/bits/string_fortified.h | 12 | ||||
| -rw-r--r-- | string/memset_explicit.c | 39 | ||||
| -rw-r--r-- | string/string.h | 7 | ||||
| -rw-r--r-- | string/test-memset.c | 12 | ||||
| -rw-r--r-- | string/test-memset_explicit.c | 19 | ||||
| -rw-r--r-- | string/tst-xbzero-opt.c | 4 | ||||
| -rw-r--r-- | string/tst-xmemset-opt.c | 2 |
9 files changed, 102 insertions, 2 deletions
diff --git a/string/Makefile b/string/Makefile index c83b195e2e..d842ae0457 100644 --- a/string/Makefile +++ b/string/Makefile @@ -69,6 +69,7 @@ routines := \ mempcpy \ memrchr \ memset \ + memset_explicit \ rawmemchr \ sigabbrev_np \ sigdescr_np \ @@ -125,6 +126,7 @@ routines_no_fortify += \ memmove \ mempcpy \ memset \ + memset_explicit \ stpcpy \ stpncpy \ strcat \ @@ -164,6 +166,7 @@ tests := \ test-mempcpy \ test-memrchr \ test-memset \ + test-memset_explicit \ test-rawmemchr \ test-sig_np \ test-stpcpy \ @@ -210,6 +213,7 @@ tests := \ tst-svc \ tst-svc2 \ tst-xbzero-opt \ + tst-xmemset-opt \ # tests tests-static-internal := \ @@ -262,6 +266,7 @@ CFLAGS-stratcliff.c += -fno-builtin CFLAGS-test-ffs.c += -fno-builtin CFLAGS-tst-inlcall.c += -fno-builtin CFLAGS-tst-xbzero-opt.c += -O3 +CFLAGS-tst-xmemset-opt.c += -O3 CFLAGS-test-endian-sign-conversion.c += -Werror -Wsign-conversion # BZ 21006: Resolve all functions but at least explicit_bzero at startup. # Otherwise the test fails on s390x as the memcpy in prepare_test_buffer is @@ -271,6 +276,7 @@ CFLAGS-test-endian-sign-conversion.c += -Werror -Wsign-conversion # and the call to memmem in count_test_patterns will find a hit of the # test_pattern on the stack. LDFLAGS-tst-xbzero-opt = -z now +LDFLAGS-tst-xmemset-opt = -z now # Called during TLS initialization. CFLAGS-memcpy.c += $(no-stack-protector) diff --git a/string/Versions b/string/Versions index c56e372a3c..5a63f5ced3 100644 --- a/string/Versions +++ b/string/Versions @@ -96,4 +96,7 @@ libc { strlcat; strlcpy; } + GLIBC_2.43 { + memset_explicit; + } } diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h index ae14cfbab0..9916e17aa0 100644 --- a/string/bits/string_fortified.h +++ b/string/bits/string_fortified.h @@ -60,6 +60,18 @@ __NTH (memset (void *__dest, int __ch, size_t __len)) __glibc_objsize0 (__dest)); } +#if defined __USE_MISC || __GLIBC_USE (ISOC23) +void *__memset_explicit_chk (void *__s, int __c, size_t __n, size_t __destlen) + __THROW __nonnull ((1)) __fortified_attr_access (__write_only__, 1, 3); + +__fortify_function void * +__NTH (memset_explicit (void *__dest, int __ch, size_t __len)) +{ + return __memset_explicit_chk (__dest, __ch, __len, + __glibc_objsize0 (__dest)); +} +#endif + #ifdef __USE_MISC # include <bits/strings_fortified.h> diff --git a/string/memset_explicit.c b/string/memset_explicit.c new file mode 100644 index 0000000000..29fec30bd9 --- /dev/null +++ b/string/memset_explicit.c @@ -0,0 +1,39 @@ +/* Erasure of sensitive data, generic implementation. + Copyright (C) 2016-2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +/* An assembler implementation of memset_explicit can be created as an + assembler alias of an optimized memset implementation. + Architecture-specific implementations also need to define + __memset_explicit_chk. */ + +#include <string.h> + +/* glibc-internal users use __memset_explicit_chk, and memset_explicit + redirects to that. */ +#undef memset_explicit + +/* Set LEN bytes of S to C. The compiler will not delete a call to + this function, even if S is dead after the call. */ +void * +memset_explicit (void *s, int c, size_t len) +{ + memset (s, c, len); + /* Compiler barrier. */ + asm volatile ("" ::: "memory"); + return s; +} diff --git a/string/string.h b/string/string.h index df4d489556..81f0b7fd21 100644 --- a/string/string.h +++ b/string/string.h @@ -60,6 +60,13 @@ extern void *memccpy (void *__restrict __dest, const void *__restrict __src, /* Set N bytes of S to C. */ extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1)); +#if defined __USE_MISC || __GLIBC_USE (ISOC23) +/* Like memset, but the compiler will not delete a call to this + function, even if S is dead after the call. */ +extern void *memset_explicit (void *__s, int __c, size_t __n) + __THROW __nonnull ((1)) __fortified_attr_access (__write_only__, 1, 3); +#endif + /* Compare N bytes of S1 and S2. */ extern int memcmp (const void *__s1, const void *__s2, size_t __n) __THROW __attribute_pure__ __nonnull ((1, 2)); diff --git a/string/test-memset.c b/string/test-memset.c index 19c613899b..00664004da 100644 --- a/string/test-memset.c +++ b/string/test-memset.c @@ -25,7 +25,11 @@ # endif #else # ifndef WIDE -# define TEST_NAME "memset" +# ifdef TEST_MEMSET_EXPLICIT +# define TEST_NAME "memset_explicit" +# else +# define TEST_NAME "memset" +# endif # else # define TEST_NAME "wmemset" # endif /* WIDE */ @@ -34,7 +38,11 @@ #include "test-string.h" #ifndef WIDE -# define MEMSET memset +# ifdef TEST_MEMSET_EXPLICIT +# define MEMSET memset_explicit +# else +# define MEMSET memset +# endif # define CHAR char # define UCHAR unsigned char # define SIMPLE_MEMSET simple_memset diff --git a/string/test-memset_explicit.c b/string/test-memset_explicit.c new file mode 100644 index 0000000000..b02954c6b0 --- /dev/null +++ b/string/test-memset_explicit.c @@ -0,0 +1,19 @@ +/* Test and measure memset_explicit. + Copyright (C) 2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ +#define TEST_MEMSET_EXPLICIT +#include "test-memset.c" diff --git a/string/tst-xbzero-opt.c b/string/tst-xbzero-opt.c index 7f5fbc7ffc..b6e07055d3 100644 --- a/string/tst-xbzero-opt.c +++ b/string/tst-xbzero-opt.c @@ -153,7 +153,11 @@ setup_explicit_clear (void) { unsigned char buf[TEST_BUFFER_SIZE]; prepare_test_buffer (buf); +#ifdef TEST_MEMSET_EXPLICIT + memset_explicit (buf, 0, TEST_BUFFER_SIZE); +#else explicit_bzero (buf, TEST_BUFFER_SIZE); +#endif } enum test_expectation diff --git a/string/tst-xmemset-opt.c b/string/tst-xmemset-opt.c new file mode 100644 index 0000000000..ce71a6cea1 --- /dev/null +++ b/string/tst-xmemset-opt.c @@ -0,0 +1,2 @@ +#define TEST_MEMSET_EXPLICIT 1 +#include "tst-xbzero-opt.c" |
