aboutsummaryrefslogtreecommitdiff
path: root/posix
diff options
context:
space:
mode:
Diffstat (limited to 'posix')
-rw-r--r--posix/Makefile3
-rw-r--r--posix/fnmatch_loop.c8
-rw-r--r--posix/glob.h3
-rw-r--r--posix/regcomp.c11
-rw-r--r--posix/tst-libc-message.c48
-rw-r--r--posix/tst-regcomp-bracket-free.c176
-rw-r--r--posix/tst-regex.input12
-rw-r--r--posix/tst-truncate-common.c2
8 files changed, 242 insertions, 21 deletions
diff --git a/posix/Makefile b/posix/Makefile
index c0e2242..a36e5de 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -304,6 +304,7 @@ tests := \
tst-posix_spawn-setsid \
tst-preadwrite \
tst-preadwrite64 \
+ tst-regcomp-bracket-free \
tst-regcomp-truncated \
tst-regex \
tst-regex2 \
@@ -348,6 +349,7 @@ tests-internal := \
bug-regex5 \
bug-regex20 \
bug-regex33 \
+ tst-libc-message \
# tests-internal
tests-container := \
@@ -391,6 +393,7 @@ endif
tests-static = \
tst-exec-static \
+ tst-libc-message \
tst-spawn-static \
# tests-static
diff --git a/posix/fnmatch_loop.c b/posix/fnmatch_loop.c
index 9ec5e0e..83f8861 100644
--- a/posix/fnmatch_loop.c
+++ b/posix/fnmatch_loop.c
@@ -537,7 +537,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
that it was properly set in the loop
above. */
DIAG_PUSH_NEEDS_COMMENT;
- DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized");
+ DIAG_IGNORE_NEEDS_COMMENT (16, "-Wmaybe-uninitialized");
if (! is_range
# if WIDE_CHAR_VERSION
@@ -560,7 +560,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
above it will be properly set by the loop.
*/
DIAG_PUSH_NEEDS_COMMENT;
- DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized");
+ DIAG_IGNORE_NEEDS_COMMENT (16, "-Wmaybe-uninitialized");
cold = wextra[1 + wextra[0]];
DIAG_POP_NEEDS_COMMENT;
# else
@@ -745,7 +745,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
means that it was properly set in the
loop above. */
DIAG_PUSH_NEEDS_COMMENT;
- DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized");
+ DIAG_IGNORE_NEEDS_COMMENT (16, "-Wmaybe-uninitialized");
cend = wextra[1 + wextra[0]];
DIAG_POP_NEEDS_COMMENT;
# else
@@ -754,7 +754,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
wextra above it will be properly set by
the loop. */
DIAG_PUSH_NEEDS_COMMENT;
- DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized");
+ DIAG_IGNORE_NEEDS_COMMENT (16, "-Wmaybe-uninitialized");
idx += 1 + extra[idx];
DIAG_POP_NEEDS_COMMENT;
/* Adjust for the alignment. */
diff --git a/posix/glob.h b/posix/glob.h
index 6bb0c6f..e5442dd 100644
--- a/posix/glob.h
+++ b/posix/glob.h
@@ -195,7 +195,8 @@ extern void globfree64 (glob64_t *__pglob) __THROW;
This function is not part of the interface specified by POSIX.2
but several programs want to use it. */
-extern int glob_pattern_p (const char *__pattern, int __quote) __THROW;
+extern int glob_pattern_p (const char *__pattern, int __quote) __THROW
+ __nonnull ((1));
#endif
__END_DECLS
diff --git a/posix/regcomp.c b/posix/regcomp.c
index 69675d8..f7278bb 100644
--- a/posix/regcomp.c
+++ b/posix/regcomp.c
@@ -3301,8 +3301,11 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
#ifdef RE_ENABLE_I18N
mbcset, &coll_sym_alloc,
#endif /* RE_ENABLE_I18N */
- start_elem.opr.name,
- nrules, table_size, symb_table, extra);
+ start_elem.opr.name
+#ifdef _LIBC
+ , nrules, table_size, symb_table, extra
+#endif
+ );
if (__glibc_unlikely (*err != REG_NOERROR))
goto parse_bracket_exp_free_return;
break;
@@ -3384,6 +3387,7 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
{
#ifdef RE_ENABLE_I18N
free_charset (mbcset);
+ mbcset = NULL;
#endif
/* Build a tree for simple bracket. */
br_token.type = SIMPLE_BRACKET;
@@ -3399,7 +3403,8 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
parse_bracket_exp_free_return:
re_free (sbcset);
#ifdef RE_ENABLE_I18N
- free_charset (mbcset);
+ if (__glibc_likely (mbcset != NULL))
+ free_charset (mbcset);
#endif /* RE_ENABLE_I18N */
return NULL;
}
diff --git a/posix/tst-libc-message.c b/posix/tst-libc-message.c
new file mode 100644
index 0000000..b85195e
--- /dev/null
+++ b/posix/tst-libc-message.c
@@ -0,0 +1,48 @@
+/* Internal test to verify __libc_fatal.
+ 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/>. */
+
+#include <signal.h>
+#include <stdio.h>
+
+#include <support/check.h>
+#include <support/capture_subprocess.h>
+
+static _Noreturn void
+run_libc_message (void *closure)
+{
+ /* We only support 4 arguments. Call with 5 to trigger failure. */
+ __libc_message_impl ("%s %s %s %s %s\n", "1", "2", "3", "4", "5");
+ __builtin_unreachable ();
+}
+
+static int
+do_test (void)
+{
+ struct support_capture_subprocess result
+ = support_capture_subprocess (run_libc_message, NULL);
+ support_capture_subprocess_check (&result, "libc_message", -SIGABRT,
+ sc_allow_stderr);
+
+ TEST_COMPARE_STRING (result.err.buffer, IOVEC_MAX_ERR_MSG);
+
+ support_capture_subprocess_free (&result);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/posix/tst-regcomp-bracket-free.c b/posix/tst-regcomp-bracket-free.c
new file mode 100644
index 0000000..3c091d8
--- /dev/null
+++ b/posix/tst-regcomp-bracket-free.c
@@ -0,0 +1,176 @@
+/* Test regcomp bracket parsing with injected allocation failures (bug 33185).
+ 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/>. */
+
+/* This test invokes regcomp multiple times, failing one memory
+ allocation in each call. The function call should fail with
+ REG_ESPACE (or succeed if it can recover from the allocation
+ failure). Previously, there was double-free bug. */
+
+#include <errno.h>
+#include <regex.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+
+/* Data structure allocated via MAP_SHARED, so that writes from the
+ subprocess are visible. */
+struct shared_data
+{
+ /* Number of tracked allocations performed so far. */
+ volatile unsigned int allocation_count;
+
+ /* If this number is reached, one allocation fails. */
+ volatile unsigned int failing_allocation;
+
+ /* The subprocess stores the expected name here. */
+ char name[100];
+};
+
+/* Allocation count in shared mapping. */
+static struct shared_data *shared;
+
+/* Returns true if a failure should be injected for this allocation. */
+static bool
+fail_this_allocation (void)
+{
+ if (shared != NULL)
+ {
+ unsigned int count = shared->allocation_count;
+ shared->allocation_count = count + 1;
+ return count == shared->failing_allocation;
+ }
+ else
+ return false;
+}
+
+/* Failure-injecting wrappers for allocation functions used by glibc. */
+
+void *
+malloc (size_t size)
+{
+ if (fail_this_allocation ())
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+ extern __typeof (malloc) __libc_malloc;
+ return __libc_malloc (size);
+}
+
+void *
+calloc (size_t a, size_t b)
+{
+ if (fail_this_allocation ())
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+ extern __typeof (calloc) __libc_calloc;
+ return __libc_calloc (a, b);
+}
+
+void *
+realloc (void *ptr, size_t size)
+{
+ if (fail_this_allocation ())
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+ extern __typeof (realloc) __libc_realloc;
+ return __libc_realloc (ptr, size);
+}
+
+/* No-op subprocess to verify that support_isolate_in_subprocess does
+ not perform any heap allocations. */
+static void
+no_op (void *ignored)
+{
+}
+
+/* Perform a regcomp call in a subprocess. Used to count its
+ allocations. */
+static void
+initialize (void *regexp1)
+{
+ const char *regexp = regexp1;
+
+ shared->allocation_count = 0;
+
+ regex_t reg;
+ TEST_COMPARE (regcomp (&reg, regexp, 0), 0);
+}
+
+/* Perform regcomp in a subprocess with fault injection. */
+static void
+test_in_subprocess (void *regexp1)
+{
+ const char *regexp = regexp1;
+ unsigned int inject_at = shared->failing_allocation;
+
+ regex_t reg;
+ int ret = regcomp (&reg, regexp, 0);
+
+ if (ret != 0)
+ {
+ TEST_COMPARE (ret, REG_ESPACE);
+ printf ("info: allocation %u failure results in return value %d,"
+ " error %s (%d)\n",
+ inject_at, ret, strerrorname_np (errno), errno);
+ }
+}
+
+static int
+do_test (void)
+{
+ char regexp[] = "[:alpha:]";
+
+ shared = support_shared_allocate (sizeof (*shared));
+
+ /* Disable fault injection. */
+ shared->failing_allocation = ~0U;
+
+ support_isolate_in_subprocess (no_op, NULL);
+ TEST_COMPARE (shared->allocation_count, 0);
+
+ support_isolate_in_subprocess (initialize, regexp);
+
+ /* The number of allocations in the successful case, plus some
+ slack. Once the number of expected allocations is exceeded,
+ injecting further failures does not make a difference. */
+ unsigned int maximum_allocation_count = shared->allocation_count;
+ printf ("info: successful call performs %u allocations\n",
+ maximum_allocation_count);
+ maximum_allocation_count += 10;
+
+ for (unsigned int inject_at = 0; inject_at <= maximum_allocation_count;
+ ++inject_at)
+ {
+ shared->allocation_count = 0;
+ shared->failing_allocation = inject_at;
+ support_isolate_in_subprocess (test_in_subprocess, regexp);
+ }
+
+ support_shared_free (shared);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/posix/tst-regex.input b/posix/tst-regex.input
index 1de30b3..38b8db6 100644
--- a/posix/tst-regex.input
+++ b/posix/tst-regex.input
@@ -8423,11 +8423,6 @@
* sysdeps/libm-ieee754/s_exp2f.c (__exp2f_deltatable): Renamed
from __exp2_deltatable.
-1998-02-26 Ulrich Drepper <drepper@cygnus.com>
-
- * nis/ypclnt.c (yp_master): Check result of strdup.
- Patch by Thorsten Kukuk.
-
1998-02-26 Thorsten Kukuk <kukuk@vt.uni-paderborn.de>
* nis/ypclnt.c: Give clnt handle after error checking free, change
@@ -11089,13 +11084,6 @@
inline functions by feature tests to avoid warning about missing
prototype declarations.
-1997-12-09 15:08 Thorsten Kukuk <kukuk@vt.uni-paderborn.de>
-
- * nis/nss_compat/compat-grp.c: Reset the blacklist correct, fix
- return code for non existent +name entries.
- * nis/nss_compat/compat-pwd.c: Likewise.
- * nis/nss_compat/compat-spwd.c: Likewise.
-
1997-12-10 13:52 Philip Blundell <pb@nexus.co.uk>
* sysdeps/standalone/arm/bits/errno.h (EAGAIN): Added.
diff --git a/posix/tst-truncate-common.c b/posix/tst-truncate-common.c
index 19c96b7..20ce168 100644
--- a/posix/tst-truncate-common.c
+++ b/posix/tst-truncate-common.c
@@ -36,7 +36,7 @@ static int temp_fd;
static void
do_prepare (void)
{
- temp_fd = create_temp_file ("tst-trucate.", &temp_filename);
+ temp_fd = create_temp_file ("tst-truncate.", &temp_filename);
if (temp_fd == -1)
{
printf ("cannot create temporary file: %m\n");