diff --git a/glibc-RHEL-49490-1.patch b/glibc-RHEL-49490-1.patch new file mode 100644 index 0000000..3f2d6d8 --- /dev/null +++ b/glibc-RHEL-49490-1.patch @@ -0,0 +1,51 @@ +commit 9b7651410375ec8848a1944992d663d514db4ba7 +Author: Stefan Liebler +Date: Thu Jul 11 11:28:53 2024 +0200 + + s390x: Fix segfault in wcsncmp [BZ #31934] + + The z13/vector-optimized wcsncmp implementation segfaults if n=1 + and there is only one character (equal on both strings) before + the page end. Then it loads and compares one character and misses + to check n again. The following load fails. + + This patch removes the extra load and compare of the first character + and just start with the loop which uses vector-load-to-block-boundary. + This code-path also checks n. + + With this patch both tests are passing: + - the simplified one mentioned in the bugzilla 31934 + - the full one in Florian Weimer's patch: + "manual: Document a GNU extension for strncmp/wcsncmp" + (https://patchwork.sourceware.org/project/glibc/patch/874j9eml6y.fsf@oldenburg.str.redhat.com/): + On s390x-linux-gnu (z16), the new wcsncmp test fails due to bug 31934. + Reviewed-by: Carlos O'Donell + +diff --git a/sysdeps/s390/wcsncmp-vx.S b/sysdeps/s390/wcsncmp-vx.S +index bf6dfa6bc2..8b081567a2 100644 +--- a/sysdeps/s390/wcsncmp-vx.S ++++ b/sysdeps/s390/wcsncmp-vx.S +@@ -59,14 +59,7 @@ ENTRY(WCSNCMP_Z13) + sllg %r4,%r4,2 /* Convert character-count to byte-count. */ + locgrne %r4,%r1 /* Use max byte-count, if bit 0/1 was one. */ + +- /* Check first character without vector load. */ +- lghi %r5,4 /* current_len = 4 bytes. */ +- /* Check s1/2[0]. */ +- lt %r0,0(%r2) +- l %r1,0(%r3) +- je .Lend_cmp_one_char +- crjne %r0,%r1,.Lend_cmp_one_char +- ++ lghi %r5,0 /* current_len = 0 bytes. */ + .Lloop: + vlbb %v17,0(%r5,%r3),6 /* Load s2 to block boundary. */ + vlbb %v16,0(%r5,%r2),6 /* Load s1 to block boundary. */ +@@ -167,7 +160,6 @@ ENTRY(WCSNCMP_Z13) + srl %r4,2 /* And convert it to character-index. */ + vlgvf %r0,%v16,0(%r4) /* Load character-values. */ + vlgvf %r1,%v17,0(%r4) +-.Lend_cmp_one_char: + cr %r0,%r1 + je .Lend_equal + lghi %r2,1 diff --git a/glibc-RHEL-49490-2.patch b/glibc-RHEL-49490-2.patch new file mode 100644 index 0000000..d83e1c5 --- /dev/null +++ b/glibc-RHEL-49490-2.patch @@ -0,0 +1,248 @@ +commit 54252394c25ddf0062e288d4a6ab7a885f8ae009 +Author: Florian Weimer +Date: Thu Jun 27 16:26:56 2024 +0200 + + Enhanced test coverage for strncmp, wcsncmp + + Add string/test-strncmp-nonarray and + wcsmbs/test-wcsncmp-nonarray. + + This is the test that uncovered bug 31934. Test run time + is more than one minute on a fairly current system, so turn + these into xtests that do not run automatically. + + Reviewed-by: Noah Goldstein + +diff -Nrup a/string/Makefile b/string/Makefile +--- a/string/Makefile 2024-09-17 14:28:06.030433788 -0400 ++++ b/string/Makefile 2024-09-17 14:33:56.846338606 -0400 +@@ -62,7 +62,11 @@ tests := tester inl-tester noinl-tester + test-endian-sign-conversion + + # This test allocates a lot of memory and can run for a long time. +-xtests = tst-strcoll-overflow ++xtests += tst-strcoll-overflow ++ ++# This test runs for a long time. ++xtests += test-strncmp-nonarray ++ + + # This test needs libdl. + ifeq (yes,$(build-shared)) +diff -Nrup a/string/test-Xncmp-nonarray.c b/string/test-Xncmp-nonarray.c +--- a/string/test-Xncmp-nonarray.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/string/test-Xncmp-nonarray.c 2024-09-17 14:27:27.538224809 -0400 +@@ -0,0 +1,183 @@ ++/* Test non-array inputs to string comparison functions. ++ 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 skeleton file is included from string/test-strncmp-nonarray.c and ++ wcsmbs/test-wcsncmp-nonarray.c to test that reading of the arrays stops ++ at the first null character. ++ ++ TEST_IDENTIFIER must be the test function identifier. TEST_NAME is ++ the same as a string. ++ ++ CHAR must be defined as the character type. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Much shorter than test-Xnlen-nonarray.c because of deeply nested loops. */ ++enum { buffer_length = 80 }; ++ ++/* The test buffer layout follows what is described test-Xnlen-nonarray.c, ++ except that there two buffers, left and right. The variables ++ a_count, zero_count, start_offset are all duplicated. */ ++ ++/* Return the maximum string length for a string that starts at ++ start_offset. */ ++static int ++string_length (int a_count, int start_offset) ++{ ++ if (start_offset == buffer_length || start_offset >= a_count) ++ return 0; ++ else ++ return a_count - start_offset; ++} ++ ++/* This is the valid maximum length argument computation for ++ strnlen/wcsnlen. See text-Xnlen-nonarray.c. */ ++static int ++maximum_length (int start_offset, int zero_count) ++{ ++ if (start_offset == buffer_length) ++ return 0; ++ else if (zero_count > 0) ++ /* Effectively unbounded, but we need to stop fairly low, ++ otherwise testing takes too long. */ ++ return buffer_length + 32; ++ else ++ return buffer_length - start_offset; ++} ++ ++typedef __typeof (TEST_IDENTIFIER) *proto_t; ++ ++#define TEST_MAIN ++#include "test-string.h" ++ ++IMPL (TEST_IDENTIFIER, 1) ++ ++static int ++test_main (void) ++{ ++ TEST_VERIFY_EXIT (sysconf (_SC_PAGESIZE) >= buffer_length); ++ test_init (); ++ ++ struct support_next_to_fault left_ntf ++ = support_next_to_fault_allocate (buffer_length * sizeof (CHAR)); ++ CHAR *left_buffer = (CHAR *) left_ntf.buffer; ++ struct support_next_to_fault right_ntf ++ = support_next_to_fault_allocate (buffer_length * sizeof (CHAR)); ++ CHAR *right_buffer = (CHAR *) right_ntf.buffer; ++ ++ FOR_EACH_IMPL (impl, 0) ++ { ++ printf ("info: testing %s\n", impl->name); ++ for (size_t i = 0; i < buffer_length; ++i) ++ left_buffer[i] = 'A'; ++ ++ for (int left_zero_count = 0; left_zero_count <= buffer_length; ++ ++left_zero_count) ++ { ++ if (left_zero_count > 0) ++ left_buffer[buffer_length - left_zero_count] = 0; ++ int left_a_count = buffer_length - left_zero_count; ++ for (size_t i = 0; i < buffer_length; ++i) ++ right_buffer[i] = 'A'; ++ for (int right_zero_count = 0; right_zero_count <= buffer_length; ++ ++right_zero_count) ++ { ++ if (right_zero_count > 0) ++ right_buffer[buffer_length - right_zero_count] = 0; ++ int right_a_count = buffer_length - right_zero_count; ++ for (int left_start_offset = 0; ++ left_start_offset <= buffer_length; ++ ++left_start_offset) ++ { ++ CHAR *left_start_pointer = left_buffer + left_start_offset; ++ int left_maxlen ++ = maximum_length (left_start_offset, left_zero_count); ++ int left_length ++ = string_length (left_a_count, left_start_offset); ++ for (int right_start_offset = 0; ++ right_start_offset <= buffer_length; ++ ++right_start_offset) ++ { ++ CHAR *right_start_pointer ++ = right_buffer + right_start_offset; ++ int right_maxlen ++ = maximum_length (right_start_offset, right_zero_count); ++ int right_length ++ = string_length (right_a_count, right_start_offset); ++ ++ /* Maximum length is modelled after strnlen/wcsnlen, ++ and must be valid for both pointer arguments at ++ the same time. */ ++ int maxlen = MIN (left_maxlen, right_maxlen); ++ ++ for (int length_argument = 0; length_argument <= maxlen; ++ ++length_argument) ++ { ++ if (test_verbose) ++ { ++ printf ("left: zero_count=%d" ++ " a_count=%d start_offset=%d\n", ++ left_zero_count, left_a_count, ++ left_start_offset); ++ printf ("right: zero_count=%d" ++ " a_count=%d start_offset=%d\n", ++ right_zero_count, right_a_count, ++ right_start_offset); ++ printf ("length argument: %d\n", ++ length_argument); ++ } ++ ++ /* Effective lengths bounded by length argument. ++ The effective length determines the ++ outcome of the comparison. */ ++ int left_effective ++ = MIN (left_length, length_argument); ++ int right_effective ++ = MIN (right_length, length_argument); ++ if (left_effective == right_effective) ++ TEST_COMPARE (CALL (impl, ++ left_start_pointer, ++ right_start_pointer, ++ length_argument), 0); ++ else if (left_effective < right_effective) ++ TEST_COMPARE (CALL (impl, ++ left_start_pointer, ++ right_start_pointer, ++ length_argument) < 0, 1); ++ else ++ TEST_COMPARE (CALL (impl, ++ left_start_pointer, ++ right_start_pointer, ++ length_argument) > 0, 1); ++ } ++ } ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++#include +diff -Nrup a/string/test-strncmp-nonarray.c b/string/test-strncmp-nonarray.c +--- a/string/test-strncmp-nonarray.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/string/test-strncmp-nonarray.c 2024-09-17 14:27:27.538224809 -0400 +@@ -0,0 +1,4 @@ ++#define TEST_IDENTIFIER strncmp ++#define TEST_NAME "strncmp" ++typedef char CHAR; ++#include "test-Xncmp-nonarray.c" +diff -Nrup a/wcsmbs/Makefile b/wcsmbs/Makefile +--- a/wcsmbs/Makefile 2018-08-01 01:10:47.000000000 -0400 ++++ b/wcsmbs/Makefile 2024-09-17 14:31:04.725404041 -0400 +@@ -53,6 +53,9 @@ tests := tst-wcstof wcsmbs-tst1 tst-wcsn + tst-wcstod-round test-char-types tst-fgetwc-after-eof \ + tst-wcstod-nan-sign $(addprefix test-,$(strop-tests)) + ++# This test runs for a long time. ++xtests += test-wcsncmp-nonarray ++ + include ../Rules + + ifeq ($(run-built-tests),yes) +diff -Nrup a/wcsmbs/test-wcsncmp-nonarray.c b/wcsmbs/test-wcsncmp-nonarray.c +--- a/wcsmbs/test-wcsncmp-nonarray.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/wcsmbs/test-wcsncmp-nonarray.c 2024-09-17 14:27:27.539224815 -0400 +@@ -0,0 +1,5 @@ ++#include ++#define TEST_IDENTIFIER wcsncmp ++#define TEST_NAME "wcsncmp" ++typedef wchar_t CHAR; ++#include "../string/test-Xncmp-nonarray.c" diff --git a/glibc.spec b/glibc.spec index e80d62f..5285422 100644 --- a/glibc.spec +++ b/glibc.spec @@ -132,7 +132,7 @@ end \ Summary: The GNU libc libraries Name: glibc Version: %{glibcversion} -Release: %{glibcrelease}.5 +Release: %{glibcrelease}.6 # In general, GPLv2+ is used by programs, LGPLv2+ is used for # libraries. @@ -1195,6 +1195,8 @@ Patch1007: glibc-RHEL-39994-2.patch Patch1008: glibc-RHEL-36147-1.patch Patch1009: glibc-RHEL-36147-2.patch Patch1010: glibc-RHEL-36147-3.patch +Patch1011: glibc-RHEL-49490-1.patch +Patch1012: glibc-RHEL-49490-2.patch ############################################################################## # Continued list of core "glibc" package information: @@ -3026,6 +3028,10 @@ fi %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared %changelog +* Tue Sep 17 2024 Patsy Griffin - 2.28-251.6 +- s390x: Fix segfault in wcsncmp +- Enhanced test coverage for strncmp, wcsncmp (RHEL-49490) + * Fri Aug 16 2024 Patsy Griffin - 2.28-251.5 - elf: Clarify and invert second argument of _dl_allocate_tls_init - elf: Avoid re-initializing already allocated TLS in dlopen (RHEL-36147)