From 02111ad8a762e3419a7108270c64743483d49609 Mon Sep 17 00:00:00 2001 From: DJ Delorie Date: Mon, 20 Oct 2025 17:14:26 -0400 Subject: [PATCH] assert: Improve POSIX conformance of allocation failure path (RHEL-119422) Resolves: RHEL-119422 --- glibc-RHEL-119422-1.patch | 255 ++++++++++++++++++++++++++++++++++++++ glibc-RHEL-119422-2.patch | 23 ++++ glibc-RHEL-119422-3.patch | 20 +++ 3 files changed, 298 insertions(+) create mode 100644 glibc-RHEL-119422-1.patch create mode 100644 glibc-RHEL-119422-2.patch create mode 100644 glibc-RHEL-119422-3.patch diff --git a/glibc-RHEL-119422-1.patch b/glibc-RHEL-119422-1.patch new file mode 100644 index 0000000..6e8de49 --- /dev/null +++ b/glibc-RHEL-119422-1.patch @@ -0,0 +1,255 @@ +commit e79e5c4899e82eff1032b1f8e530234c8fcbd8b9 +Author: DJ Delorie +Date: Thu Nov 14 15:12:57 2024 -0500 + + assert: ensure posix compliance, add tests for such + + Fix assert.c so that even the fallback + case conforms to POSIX, although not exactly the same as + the default case so a test can tell the difference. + + Add a test that verifies that abort is called, and that the + message printed to stderr has all the info that POSIX requires. + Verify this even when malloc isn't usable. + + Reviewed-by: Paul Eggert + +Conflicts: + assert/Makefile + context + +diff --git a/assert/Makefile b/assert/Makefile +index 24a9bdb96306ca08..85358fad51367b49 100644 +--- a/assert/Makefile ++++ b/assert/Makefile +@@ -39,6 +39,7 @@ tests := \ + tst-assert-c++ \ + tst-assert-g++ \ + tst-assert-sa-2025-0001 \ ++ test-assert-2 \ + # tests + + ifeq ($(have-cxx-thread_local),yes) +diff --git a/assert/assert.c b/assert/assert.c +index 989126c7e5b6b265..6002cc953cdb2d39 100644 +--- a/assert/assert.c ++++ b/assert/assert.c +@@ -26,6 +26,8 @@ + #include + #include + #include ++#include ++#include + + + extern const char *__progname; +@@ -85,8 +87,35 @@ __assert_fail_base (const char *fmt, const char *assertion, const char *file, + else + { + /* At least print a minimal message. */ +- static const char errstr[] = "Unexpected error.\n"; +- __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1); ++ char linebuf[INT_STRLEN_BOUND (int) + sizeof ":: "]; ++ struct iovec v[9]; ++ int i = 0; ++ ++#define WS(s) (v[i].iov_len = strlen (v[i].iov_base = (void *) (s)), i++) ++ ++ if (__progname) ++ { ++ WS (__progname); ++ WS (": "); ++ } ++ ++ WS (file); ++ v[i++] = (struct iovec) {.iov_base = linebuf, ++ .iov_len = sprintf (linebuf, ":%d: ", line)}; ++ ++ if (function) ++ { ++ WS (function); ++ WS (": "); ++ } ++ ++ WS ("Assertion `"); ++ WS (assertion); ++ /* We omit the '.' here so that the assert tests can tell when ++ this code path is taken. */ ++ WS ("' failed\n"); ++ ++ (void) writev (STDERR_FILENO, v, i); + } + + abort (); +diff --git a/assert/test-assert-2.c b/assert/test-assert-2.c +new file mode 100644 +index 0000000000000000..99f8f683e87a0c64 +--- /dev/null ++++ b/assert/test-assert-2.c +@@ -0,0 +1,166 @@ ++/* Test assert's compliance with POSIX requirements. ++ Copyright (C) 2024 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 ++ . */ ++ ++/* This test verifies that a failed assertion acts in accordance with ++ the POSIX requirements, despite any internal failures. We do so by ++ calling test routines via fork() and monitoring their exit codes ++ and stderr, while possibly forcing internal functions (malloc) to ++ fail. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#undef NDEBUG ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* We need to be able to make malloc() "fail" so that __asprintf ++ fails. */ ++ ++void * (*next_malloc)(size_t sz) = 0; ++static volatile bool fail_malloc = 0; ++ ++void * ++malloc (size_t sz) ++{ ++ if (fail_malloc) ++ return NULL; ++ if (next_malloc == 0) ++ next_malloc = dlsym (RTLD_NEXT, "malloc"); ++ if (next_malloc == 0) ++ return NULL; ++ return next_malloc (sz); ++} ++ ++/* We can tell if abort() is called by looking for the custom return ++ value. */ ++ ++void ++abort_handler(int s) ++{ ++ _exit(5); ++} ++ ++static int do_lineno; ++static const char *do_funcname; ++ ++/* Hack to get the line of the assert. */ ++#define GET_INFO_1(l) \ ++ if (closure != NULL) \ ++ { \ ++ do_lineno = l; \ ++ do_funcname = __func__; \ ++ return; \ ++ } ++#define GET_INFO() GET_INFO_1(__LINE__+1) ++ ++/* These are the two test cases. */ ++ ++static void ++test_assert_normal (void *closure) ++{ ++ if (closure == NULL) ++ signal (SIGABRT, abort_handler); ++ ++ GET_INFO (); ++ assert (1 == 2); ++} ++ ++ ++static void ++test_assert_nomalloc (void *closure) ++{ ++ if (closure == NULL) ++ { ++ signal (SIGABRT, abort_handler); ++ fail_malloc = 1; ++ } ++ ++ GET_INFO (); ++ assert (1 == 2); ++} ++ ++static void ++check_posix (const char *buf, int rv, int line, ++ const char *funcname, const char *testarg) ++{ ++ /* POSIX requires that a failed assertion write a diagnostic to ++ stderr and call abort. The diagnostic must include the filename, ++ line number, and function where the assertion failed, along with ++ the text of the assert() argument. ++ */ ++ char linestr[100]; ++ ++ sprintf (linestr, "%d", line); ++ ++ /* If abort is called, our handler will return 5. */ ++ TEST_VERIFY (rv == 5); ++ ++ TEST_VERIFY (strstr (buf, __FILE__) != NULL); ++ TEST_VERIFY (strstr (buf, linestr) != NULL); ++ TEST_VERIFY (strstr (buf, funcname) != NULL); ++ TEST_VERIFY (strstr (buf, testarg) != NULL); ++ ++} ++ ++static void ++one_test (void (*func)(void *), int which_path) ++{ ++ struct support_capture_subprocess sp; ++ int rv; ++ ++ func (&do_lineno); ++ printf("running test for %s, line %d\n", do_funcname, do_lineno); ++ ++ sp = support_capture_subprocess (func, NULL); ++ rv = WEXITSTATUS (sp.status); ++ ++ check_posix (sp.err.buffer, rv, do_lineno, do_funcname, "1 == 2"); ++ ++ /* Look for intentional subtle differences in messages to verify ++ that the intended code path was taken. */ ++ switch (which_path) ++ { ++ case 0: ++ TEST_VERIFY (strstr (sp.err.buffer, "failed.\n") != NULL); ++ break; ++ case 1: ++ TEST_VERIFY (strstr (sp.err.buffer, "failed\n") != NULL); ++ break; ++ } ++ ++ support_capture_subprocess_free (&sp); ++} ++ ++static int ++do_test(void) ++{ ++ one_test (test_assert_normal, 0); ++ one_test (test_assert_nomalloc, 1); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-119422-2.patch b/glibc-RHEL-119422-2.patch new file mode 100644 index 0000000..a740b14 --- /dev/null +++ b/glibc-RHEL-119422-2.patch @@ -0,0 +1,23 @@ +commit 3fb895ac88e99201573352b1abc18db4340ecede +Author: DJ Delorie +Date: Sat Dec 21 23:12:41 2024 -0500 + + assert: Use __writev in assert.c [BZ #32492] + + Replace writev with __writev in assert/assert.c. This fixes [BZ #32492]. + + Reviewed-by: H.J. Lu + +diff --git a/assert/assert.c b/assert/assert.c +index 6002cc953cdb2d39..1e9683cf0707b0d3 100644 +--- a/assert/assert.c ++++ b/assert/assert.c +@@ -119,7 +119,7 @@ __assert_fail_base (const char *fmt, const char *assertion, const char *file, + this code path is taken. */ + WS ("' failed\n"); + +- (void) writev (STDERR_FILENO, v, i); ++ (void) __writev (STDERR_FILENO, v, i); + } + + abort (); diff --git a/glibc-RHEL-119422-3.patch b/glibc-RHEL-119422-3.patch new file mode 100644 index 0000000..c1c5f9b --- /dev/null +++ b/glibc-RHEL-119422-3.patch @@ -0,0 +1,20 @@ +commit fd30525eadff6a4b2ac9478bdd6490d0c9c116d9 +Author: Samuel Thibault +Date: Sun Dec 22 23:33:27 2024 +0100 + + assert/test-assert-2.c: Include + + For _exit declaration. + +diff --git a/assert/test-assert-2.c b/assert/test-assert-2.c +index 99f8f683e87a0c64..3288609ab28701ed 100644 +--- a/assert/test-assert-2.c ++++ b/assert/test-assert-2.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #undef NDEBUG + #include