import CS glibc-2.34-231.el9
This commit is contained in:
parent
72b1f60f08
commit
14fb3c3b25
148
SOURCES/glibc-RHEL-101986-1.patch
Normal file
148
SOURCES/glibc-RHEL-101986-1.patch
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
commit 8329939a37f483a16013dd8af8303cbcb86d92cb
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Jul 4 21:46:16 2025 +0200
|
||||||
|
|
||||||
|
elf: Introduce _dl_debug_change_state
|
||||||
|
|
||||||
|
It combines updating r_state with the debugger notification.
|
||||||
|
|
||||||
|
The second change to _dl_open introduces an additional debugger
|
||||||
|
notification for dlmopen, but debuggers are expected to ignore it.
|
||||||
|
|
||||||
|
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||||||
|
|
||||||
|
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||||
|
index 236d89f67f3bf410..fa3974afba798073 100644
|
||||||
|
--- a/elf/dl-close.c
|
||||||
|
+++ b/elf/dl-close.c
|
||||||
|
@@ -472,8 +472,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||||
|
/* Notify the debugger we are about to remove some loaded objects.
|
||||||
|
LA_ACT_DELETE has already been signalled above for !unload_any. */
|
||||||
|
struct r_debug *r = _dl_debug_update (nsid);
|
||||||
|
- r->r_state = RT_DELETE;
|
||||||
|
- _dl_debug_state ();
|
||||||
|
+ _dl_debug_change_state (r, RT_DELETE);
|
||||||
|
LIBC_PROBE (unmap_start, 2, nsid, r);
|
||||||
|
|
||||||
|
if (unload_global)
|
||||||
|
@@ -762,8 +761,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||||
|
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
|
||||||
|
|
||||||
|
/* Notify the debugger those objects are finalized and gone. */
|
||||||
|
- r->r_state = RT_CONSISTENT;
|
||||||
|
- _dl_debug_state ();
|
||||||
|
+ _dl_debug_change_state (r, RT_CONSISTENT);
|
||||||
|
LIBC_PROBE (unmap_complete, 2, nsid, r);
|
||||||
|
|
||||||
|
#ifdef SHARED
|
||||||
|
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
|
||||||
|
index 649386d5a6b885ed..f840a1b92292968d 100644
|
||||||
|
--- a/elf/dl-debug.c
|
||||||
|
+++ b/elf/dl-debug.c
|
||||||
|
@@ -67,6 +67,13 @@ _dl_debug_update (Lmid_t ns)
|
||||||
|
return &r->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
+void
|
||||||
|
+_dl_debug_change_state (struct r_debug *r, int state)
|
||||||
|
+{
|
||||||
|
+ atomic_store_release (&r->r_state, state);
|
||||||
|
+ _dl_debug_state ();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* Initialize _r_debug_extended for the namespace NS. LDBASE is the
|
||||||
|
run-time load address of the dynamic linker, to be put in
|
||||||
|
_r_debug_extended.r_ldbase. Return the address of _r_debug. */
|
||||||
|
diff --git a/elf/dl-load.c b/elf/dl-load.c
|
||||||
|
index 6714807946b60188..c118db811d8899f6 100644
|
||||||
|
--- a/elf/dl-load.c
|
||||||
|
+++ b/elf/dl-load.c
|
||||||
|
@@ -946,8 +946,7 @@ _dl_notify_new_object (int mode, Lmid_t nsid, struct link_map *l)
|
||||||
|
/* Notify the debugger we have added some objects. We need to
|
||||||
|
call _dl_debug_initialize in a static program in case dynamic
|
||||||
|
linking has not been used before. */
|
||||||
|
- r->r_state = RT_ADD;
|
||||||
|
- _dl_debug_state ();
|
||||||
|
+ _dl_debug_change_state (r, RT_ADD);
|
||||||
|
LIBC_PROBE (map_start, 2, nsid, r);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||||
|
index 1e61e402455da666..df6aa55a8842ee62 100644
|
||||||
|
--- a/elf/dl-open.c
|
||||||
|
+++ b/elf/dl-open.c
|
||||||
|
@@ -787,8 +787,7 @@ dl_open_worker (void *a)
|
||||||
|
#ifdef SHARED
|
||||||
|
bool was_not_consistent = r->r_state != RT_CONSISTENT;
|
||||||
|
#endif
|
||||||
|
- r->r_state = RT_CONSISTENT;
|
||||||
|
- _dl_debug_state ();
|
||||||
|
+ _dl_debug_change_state (r, RT_CONSISTENT);
|
||||||
|
LIBC_PROBE (map_complete, 3, nsid, r, args->map);
|
||||||
|
|
||||||
|
#ifdef SHARED
|
||||||
|
@@ -866,7 +865,7 @@ no more namespaces available for dlmopen()"));
|
||||||
|
}
|
||||||
|
|
||||||
|
GL(dl_ns)[nsid].libc_map = NULL;
|
||||||
|
- _dl_debug_update (nsid)->r_state = RT_CONSISTENT;
|
||||||
|
+ _dl_debug_change_state (_dl_debug_update (nsid), RT_CONSISTENT);
|
||||||
|
}
|
||||||
|
/* Never allow loading a DSO in a namespace which is empty. Such
|
||||||
|
direct placements is only causing problems. Also don't allow
|
||||||
|
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||||
|
index cd233174c9d944b2..0fe9986e4c7ed830 100644
|
||||||
|
--- a/elf/rtld.c
|
||||||
|
+++ b/elf/rtld.c
|
||||||
|
@@ -1842,8 +1842,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* We start adding objects. */
|
||||||
|
- r->r_state = RT_ADD;
|
||||||
|
- _dl_debug_state ();
|
||||||
|
+ _dl_debug_change_state (r, RT_ADD);
|
||||||
|
LIBC_PROBE (init_start, 2, LM_ID_BASE, r);
|
||||||
|
|
||||||
|
/* Auditing checkpoint: we are ready to signal that the initial map
|
||||||
|
@@ -2527,8 +2526,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
/* Notify the debugger all new objects are now ready to go. We must re-get
|
||||||
|
the address since by now the variable might be in another object. */
|
||||||
|
r = _dl_debug_update (LM_ID_BASE);
|
||||||
|
- r->r_state = RT_CONSISTENT;
|
||||||
|
- _dl_debug_state ();
|
||||||
|
+ _dl_debug_change_state (r, RT_CONSISTENT);
|
||||||
|
LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
|
||||||
|
|
||||||
|
#ifdef SHARED
|
||||||
|
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||||
|
index 21dbe2d21ed8e605..371c32dd79c3ea2b 100644
|
||||||
|
--- a/sysdeps/generic/ldsodefs.h
|
||||||
|
+++ b/sysdeps/generic/ldsodefs.h
|
||||||
|
@@ -1129,8 +1129,14 @@ extern void _dl_debug_state (void);
|
||||||
|
rtld_hidden_proto (_dl_debug_state)
|
||||||
|
|
||||||
|
/* Initialize `struct r_debug_extended' for the namespace NS. LDBASE
|
||||||
|
- is the run-time load address of the dynamic linker, to be put in the
|
||||||
|
- `r_ldbase' member. Return the address of the structure. */
|
||||||
|
+ is the run-time load address of the dynamic linker, to be put in
|
||||||
|
+ the `r_ldbase' member.
|
||||||
|
+
|
||||||
|
+ Return the address of the r_debug structure for the namespace.
|
||||||
|
+ This is not merely a convenience or optimization, but it is
|
||||||
|
+ necessary for the LIBC_PROBE Systemtap/debugger probes to work
|
||||||
|
+ reliably: direct variable access can create probes that tools
|
||||||
|
+ cannot consume. */
|
||||||
|
extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||||
|
attribute_hidden;
|
||||||
|
|
||||||
|
@@ -1138,6 +1144,10 @@ extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||||
|
of the namespace NS. */
|
||||||
|
extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden;
|
||||||
|
|
||||||
|
+/* Update R->r_state to STATE and notify the debugger by calling
|
||||||
|
+ _dl_debug_state. */
|
||||||
|
+void _dl_debug_change_state (struct r_debug *r, int state) attribute_hidden;
|
||||||
|
+
|
||||||
|
/* Initialize the basic data structure for the search paths. SOURCE
|
||||||
|
is either "LD_LIBRARY_PATH" or "--library-path".
|
||||||
|
GLIBC_HWCAPS_PREPEND adds additional glibc-hwcaps subdirectories to
|
||||||
264
SOURCES/glibc-RHEL-101986-2.patch
Normal file
264
SOURCES/glibc-RHEL-101986-2.patch
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
commit ea85e7d55087075376a29261e722e4fae14ecbe7
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Jul 4 21:46:30 2025 +0200
|
||||||
|
|
||||||
|
elf: Restore support for _r_debug interpositions and copy relocations
|
||||||
|
|
||||||
|
The changes in commit a93d9e03a31ec14405cb3a09aa95413b67067380
|
||||||
|
("Extend struct r_debug to support multiple namespaces [BZ #15971]")
|
||||||
|
break the dyninst dynamic instrumentation tool. It brings its
|
||||||
|
own definition of _r_debug (rather than a declaration).
|
||||||
|
|
||||||
|
Furthermore, it turns out it is rather hard to use the proposed
|
||||||
|
handshake for accessing _r_debug via DT_DEBUG. If applications want
|
||||||
|
to access _r_debug, they can do so directly if the relevant code has
|
||||||
|
been built as PIC. To protect against harm from accidental copy
|
||||||
|
relocations due to linker relaxations, this commit restores copy
|
||||||
|
relocation support by adjusting both copies if interposition or
|
||||||
|
copy relocations are in play. Therefore, it is possible to
|
||||||
|
use a hidden reference in ld.so to access _r_debug.
|
||||||
|
|
||||||
|
Only perform the copy relocation initialization if libc has been
|
||||||
|
loaded. Otherwise, the ld.so search scope can be empty, and the
|
||||||
|
lookup of the _r_debug symbol mail fail.
|
||||||
|
|
||||||
|
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/rtld.c: Adjust for prelink.
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index 721f254d121118c0..3eac746d21042ec9 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -404,6 +404,8 @@ tests += \
|
||||||
|
tst-dlmopen1 \
|
||||||
|
tst-dlmopen3 \
|
||||||
|
tst-dlmopen4 \
|
||||||
|
+ tst-dlmopen4-nonpic \
|
||||||
|
+ tst-dlmopen4-pic \
|
||||||
|
tst-dlopen-auditdup \
|
||||||
|
tst-dlopen-constructor-null \
|
||||||
|
tst-dlopen-self \
|
||||||
|
@@ -1986,6 +1988,13 @@ $(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
|
||||||
|
|
||||||
|
$(objpfx)tst-dlmopen4.out: $(objpfx)tst-dlmopen1mod.so
|
||||||
|
|
||||||
|
+CFLAGS-tst-dlmopen4-pic.c += -fPIC
|
||||||
|
+$(objpfx)tst-dlmopen4-pic.out: $(objpfx)tst-dlmopen1mod.so
|
||||||
|
+
|
||||||
|
+CFLAGS-tst-dlmopen4-nonpic.c += -fno-pie
|
||||||
|
+tst-dlmopen4-nonpic-no-pie = yes
|
||||||
|
+$(objpfx)tst-dlmopen4-nonpic.out: $(objpfx)tst-dlmopen1mod.so
|
||||||
|
+
|
||||||
|
$(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
|
||||||
|
tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||||
|
|
||||||
|
diff --git a/elf/dl-debug-symbols.S b/elf/dl-debug-symbols.S
|
||||||
|
index 28456ab1f237ea87..629b0c0c6b2cd9e1 100644
|
||||||
|
--- a/elf/dl-debug-symbols.S
|
||||||
|
+++ b/elf/dl-debug-symbols.S
|
||||||
|
@@ -38,3 +38,4 @@
|
||||||
|
_r_debug:
|
||||||
|
_r_debug_extended:
|
||||||
|
.zero R_DEBUG_EXTENDED_SIZE
|
||||||
|
+rtld_hidden_def (_r_debug)
|
||||||
|
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
|
||||||
|
index f840a1b92292968d..4388a04cdf828898 100644
|
||||||
|
--- a/elf/dl-debug.c
|
||||||
|
+++ b/elf/dl-debug.c
|
||||||
|
@@ -16,6 +16,7 @@
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
+#include <assert.h>
|
||||||
|
#include <ldsodefs.h>
|
||||||
|
|
||||||
|
|
||||||
|
@@ -37,6 +38,37 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
|
||||||
|
to LM_ID_BASE + 1. See elf/dl-debug-symbols.S. */
|
||||||
|
struct r_debug_extended _r_debug_array[DL_NNS - 1];
|
||||||
|
|
||||||
|
+/* If not null, pointer to the _r_debug in the main executable. */
|
||||||
|
+static struct r_debug *_r_debug_main;
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+_dl_debug_post_relocate (struct link_map *main_map)
|
||||||
|
+{
|
||||||
|
+ /* Perform a full symbol search in all objects, to maintain
|
||||||
|
+ compatibility if interposed _r_debug definitions. The lookup
|
||||||
|
+ cannot fail because there is a definition in ld.so, and this
|
||||||
|
+ function is only called if the ld.so search scope is not empty. */
|
||||||
|
+ const ElfW(Sym) *sym = NULL;
|
||||||
|
+ lookup_t result =_dl_lookup_symbol_x ("_r_debug", main_map, &sym,
|
||||||
|
+ main_map->l_scope, NULL, 0, 0, NULL);
|
||||||
|
+ if (sym->st_size >= sizeof (struct r_debug))
|
||||||
|
+ {
|
||||||
|
+ struct r_debug *main_r_debug = DL_SYMBOL_ADDRESS (result, sym);
|
||||||
|
+ if (main_r_debug != &_r_debug_extended.base)
|
||||||
|
+ {
|
||||||
|
+ /* The extended version of the struct is not available in
|
||||||
|
+ the main executable because a copy relocation has been
|
||||||
|
+ used. r_map etc. have already been copied as part of the
|
||||||
|
+ copy relocation processing. */
|
||||||
|
+ main_r_debug->r_version = 1;
|
||||||
|
+
|
||||||
|
+ /* Record that dual updates of the initial link map are
|
||||||
|
+ required. */
|
||||||
|
+ _r_debug_main = main_r_debug;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* Return the r_debug object for the namespace NS. */
|
||||||
|
static inline struct r_debug_extended *
|
||||||
|
get_rdebug (Lmid_t ns)
|
||||||
|
@@ -71,6 +103,11 @@ void
|
||||||
|
_dl_debug_change_state (struct r_debug *r, int state)
|
||||||
|
{
|
||||||
|
atomic_store_release (&r->r_state, state);
|
||||||
|
+#ifdef SHARED
|
||||||
|
+ if (r == &_r_debug_extended.base && _r_debug_main != NULL)
|
||||||
|
+ /* Update the copy-relocation of _r_debug. */
|
||||||
|
+ atomic_store_release (&_r_debug_main->r_state, state);
|
||||||
|
+#endif
|
||||||
|
_dl_debug_state ();
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -103,7 +140,9 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||||
|
if (ns - 1 == LM_ID_BASE)
|
||||||
|
{
|
||||||
|
atomic_store_release (&_r_debug_extended.r_next, r);
|
||||||
|
- /* Now there are multiple namespaces. */
|
||||||
|
+ /* Now there are multiple namespaces. Note that this
|
||||||
|
+ deliberately does not update the copy in the main
|
||||||
|
+ executable (if it exists). */
|
||||||
|
atomic_store_release (&_r_debug_extended.base.r_version, 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
@@ -116,8 +155,15 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->base.r_map == NULL)
|
||||||
|
- atomic_store_release (&r->base.r_map,
|
||||||
|
- (void *) GL(dl_ns)[ns]._ns_loaded);
|
||||||
|
+ {
|
||||||
|
+ struct link_map_public *l = (void *) GL(dl_ns)[ns]._ns_loaded;
|
||||||
|
+ atomic_store_release (&r->base.r_map, l);
|
||||||
|
+#ifdef SHARED
|
||||||
|
+ if (ns == LM_ID_BASE && _r_debug_main != NULL)
|
||||||
|
+ /* Update the copy-relocation of _r_debug. */
|
||||||
|
+ atomic_store_release (&_r_debug_main->r_map, l);
|
||||||
|
+#endif
|
||||||
|
+ }
|
||||||
|
|
||||||
|
return &r->base;
|
||||||
|
}
|
||||||
|
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||||
|
index 0fe9986e4c7ed830..dac827e249b2fe14 100644
|
||||||
|
--- a/elf/rtld.c
|
||||||
|
+++ b/elf/rtld.c
|
||||||
|
@@ -2395,6 +2395,9 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
/* Likewise for the locking implementation. */
|
||||||
|
__rtld_mutex_init ();
|
||||||
|
|
||||||
|
+ /* Update copy-relocated _r_debug if necessary. */
|
||||||
|
+ _dl_debug_post_relocate (main_map);
|
||||||
|
+
|
||||||
|
/* Mark all the objects so we know they have been already relocated. */
|
||||||
|
for (struct link_map *l = main_map; l != NULL; l = l->l_next)
|
||||||
|
{
|
||||||
|
@@ -2505,6 +2508,9 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
|
||||||
|
__rtld_mutex_init ();
|
||||||
|
__rtld_malloc_init_real (main_map);
|
||||||
|
+
|
||||||
|
+ /* Update copy-relocated _r_debug if necessary. */
|
||||||
|
+ _dl_debug_post_relocate (main_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All ld.so initialization is complete. Apply RELRO. */
|
||||||
|
diff --git a/elf/tst-dlmopen4-nonpic.c b/elf/tst-dlmopen4-nonpic.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..ad4e40995337f4f9
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-dlmopen4-nonpic.c
|
||||||
|
@@ -0,0 +1,2 @@
|
||||||
|
+#define BUILD_FOR_NONPIC
|
||||||
|
+#include "tst-dlmopen4.c"
|
||||||
|
diff --git a/elf/tst-dlmopen4-pic.c b/elf/tst-dlmopen4-pic.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..919fa85c2579fb5d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-dlmopen4-pic.c
|
||||||
|
@@ -0,0 +1,2 @@
|
||||||
|
+#define BUILD_FOR_PIC
|
||||||
|
+#include "tst-dlmopen4.c"
|
||||||
|
diff --git a/elf/tst-dlmopen4.c b/elf/tst-dlmopen4.c
|
||||||
|
index 3fe150e50bc259f0..633addf41978cee8 100644
|
||||||
|
--- a/elf/tst-dlmopen4.c
|
||||||
|
+++ b/elf/tst-dlmopen4.c
|
||||||
|
@@ -53,6 +53,15 @@ do_test (void)
|
||||||
|
TEST_COMPARE (debug->base.r_version, 1);
|
||||||
|
TEST_VERIFY_EXIT (debug->r_next == NULL);
|
||||||
|
|
||||||
|
+#ifdef BUILD_FOR_PIC
|
||||||
|
+ /* In a PIC build, using _r_debug directly should give us the same
|
||||||
|
+ object. */
|
||||||
|
+ TEST_VERIFY (&_r_debug == &debug->base);
|
||||||
|
+#endif
|
||||||
|
+#ifdef BUILD_FOR_NONPIC
|
||||||
|
+ TEST_COMPARE (_r_debug.r_version, 1);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
void *h = xdlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so",
|
||||||
|
RTLD_LAZY);
|
||||||
|
|
||||||
|
@@ -64,6 +73,19 @@ do_test (void)
|
||||||
|
const char *name = basename (debug->r_next->base.r_map->l_name);
|
||||||
|
TEST_COMPARE_STRING (name, "tst-dlmopen1mod.so");
|
||||||
|
|
||||||
|
+#ifdef BUILD_FOR_NONPIC
|
||||||
|
+ /* If a copy relocation is used, it must be at version 1. */
|
||||||
|
+ if (&_r_debug != &debug->base)
|
||||||
|
+ {
|
||||||
|
+ TEST_COMPARE (_r_debug.r_version, 1);
|
||||||
|
+ TEST_COMPARE ((uintptr_t) _r_debug.r_map,
|
||||||
|
+ (uintptr_t) debug->base.r_map);
|
||||||
|
+ TEST_COMPARE (_r_debug.r_brk, debug->base.r_brk);
|
||||||
|
+ TEST_COMPARE (_r_debug.r_state, debug->base.r_state);
|
||||||
|
+ TEST_COMPARE (_r_debug.r_ldbase, debug->base.r_ldbase);
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
xdlclose (h);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
diff --git a/include/link.h b/include/link.h
|
||||||
|
index 0cf130ddb8af2e89..bafac6c9628b183c 100644
|
||||||
|
--- a/include/link.h
|
||||||
|
+++ b/include/link.h
|
||||||
|
@@ -366,6 +366,8 @@ struct auditstate
|
||||||
|
dynamic linker. */
|
||||||
|
extern struct r_debug_extended _r_debug_extended attribute_hidden;
|
||||||
|
|
||||||
|
+rtld_hidden_proto (_r_debug)
|
||||||
|
+
|
||||||
|
#if __ELF_NATIVE_CLASS == 32
|
||||||
|
# define symbind symbind32
|
||||||
|
# define LA_SYMBIND "la_symbind32"
|
||||||
|
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||||
|
index 371c32dd79c3ea2b..484893c2928db8e7 100644
|
||||||
|
--- a/sysdeps/generic/ldsodefs.h
|
||||||
|
+++ b/sysdeps/generic/ldsodefs.h
|
||||||
|
@@ -1140,6 +1140,10 @@ rtld_hidden_proto (_dl_debug_state)
|
||||||
|
extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||||
|
attribute_hidden;
|
||||||
|
|
||||||
|
+/* This is called after relocation processing to handle a potential
|
||||||
|
+ copy relocation for _r_debug. */
|
||||||
|
+void _dl_debug_post_relocate (struct link_map *main_map) attribute_hidden;
|
||||||
|
+
|
||||||
|
/* Update the `r_map' member and return the address of `struct r_debug'
|
||||||
|
of the namespace NS. */
|
||||||
|
extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden;
|
||||||
51
SOURCES/glibc-RHEL-103952.patch
Normal file
51
SOURCES/glibc-RHEL-103952.patch
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
commit cdcf24ee14c27b77744ff52ab3ae852821207eb0
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Thu Jul 17 14:44:05 2025 +0200
|
||||||
|
|
||||||
|
iconv: iconv -o should not create executable files (bug 33164)
|
||||||
|
|
||||||
|
The mistake is that open must use 0666 to pick up the umask,
|
||||||
|
and not 0777 (which is required by mkdir).
|
||||||
|
|
||||||
|
Fixes commit 8ef3cff9d1ceafe369f982d980678d749fb93bd2
|
||||||
|
("iconv: Support in-place conversions (bug 10460, bug 32033)").
|
||||||
|
|
||||||
|
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||||||
|
|
||||||
|
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
|
||||||
|
index e3b051a309ff142b..08ea99d6adf6ea86 100644
|
||||||
|
--- a/iconv/iconv_prog.c
|
||||||
|
+++ b/iconv/iconv_prog.c
|
||||||
|
@@ -437,7 +437,7 @@ input_error (const char *path)
|
||||||
|
static void
|
||||||
|
open_output_direct (void)
|
||||||
|
{
|
||||||
|
- output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_TRUNC, 0777);
|
||||||
|
+ output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||||
|
if (output_fd < 0)
|
||||||
|
output_error ();
|
||||||
|
}
|
||||||
|
@@ -458,7 +458,7 @@ prepare_output_file (char **argv)
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If iconv creates the output file, no overlap is possible. */
|
||||||
|
- output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_EXCL, 0777);
|
||||||
|
+ output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
||||||
|
if (output_fd >= 0)
|
||||||
|
output_buffer_size = copy_buffer_size;
|
||||||
|
else
|
||||||
|
diff --git a/iconv/tst-iconv_prog-buffer.sh b/iconv/tst-iconv_prog-buffer.sh
|
||||||
|
index 23098ac56a344c48..562f90fe513e94d7 100644
|
||||||
|
--- a/iconv/tst-iconv_prog-buffer.sh
|
||||||
|
+++ b/iconv/tst-iconv_prog-buffer.sh
|
||||||
|
@@ -75,6 +75,10 @@ run_iconv () {
|
||||||
|
}
|
||||||
|
|
||||||
|
check_out_expected () {
|
||||||
|
+ if test -x "$tmp/out" ; then
|
||||||
|
+ echo "error: iconv output file is executable"
|
||||||
|
+ failure=true
|
||||||
|
+ fi
|
||||||
|
if ! cmp -s "$tmp/out" "$tmp/expected" ; then
|
||||||
|
echo "error: iconv output difference" >&$logfd
|
||||||
|
echo "*** expected ***" >&$logfd
|
||||||
106
SOURCES/glibc-RHEL-104852-1.patch
Normal file
106
SOURCES/glibc-RHEL-104852-1.patch
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
commit 2cac9559e06044ba520e785c151fbbd25011865f
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Aug 1 10:20:23 2025 +0200
|
||||||
|
|
||||||
|
elf: Extract rtld_setup_phdr function from dl_main
|
||||||
|
|
||||||
|
Remove historic binutils reference from comment and update
|
||||||
|
how this data is used by applications.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/rtld.
|
||||||
|
(missing __ehdr_start cleanup downstream)
|
||||||
|
|
||||||
|
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||||
|
index 667880e18ae816d8..a9073d4e14b07410 100644
|
||||||
|
--- a/elf/rtld.c
|
||||||
|
+++ b/elf/rtld.c
|
||||||
|
@@ -1306,6 +1306,45 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||||
|
return has_interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* Set up the program header information for the dynamic linker
|
||||||
|
+ itself. It can be accessed via _r_debug and dl_iterate_phdr
|
||||||
|
+ callbacks. */
|
||||||
|
+static void
|
||||||
|
+rtld_setup_phdr (void)
|
||||||
|
+{
|
||||||
|
+ const ElfW(Ehdr) *rtld_ehdr;
|
||||||
|
+
|
||||||
|
+ /* Starting from binutils-2.23, the linker will define the magic symbol
|
||||||
|
+ __ehdr_start to point to our own ELF header if it is visible in a
|
||||||
|
+ segment that also includes the phdrs. If that's not available, we use
|
||||||
|
+ the old method that assumes the beginning of the file is part of the
|
||||||
|
+ lowest-addressed PT_LOAD segment. */
|
||||||
|
+#ifdef HAVE_EHDR_START
|
||||||
|
+ extern const ElfW(Ehdr) __ehdr_start __attribute__ ((visibility ("hidden")));
|
||||||
|
+ rtld_ehdr = &__ehdr_start;
|
||||||
|
+#else
|
||||||
|
+ rtld_ehdr = (void *) GL(dl_rtld_map).l_map_start;
|
||||||
|
+#endif
|
||||||
|
+ assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
|
||||||
|
+ assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
|
||||||
|
+
|
||||||
|
+ const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
|
||||||
|
+
|
||||||
|
+ GL(dl_rtld_map).l_phdr = rtld_phdr;
|
||||||
|
+ GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ /* PT_GNU_RELRO is usually the last phdr. */
|
||||||
|
+ size_t cnt = rtld_ehdr->e_phnum;
|
||||||
|
+ while (cnt-- > 0)
|
||||||
|
+ if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
|
||||||
|
+ {
|
||||||
|
+ GL(dl_rtld_map).l_relro_addr = rtld_phdr[cnt].p_vaddr;
|
||||||
|
+ GL(dl_rtld_map).l_relro_size = rtld_phdr[cnt].p_memsz;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* Adjusts the contents of the stack and related globals for the user
|
||||||
|
entry point. The ld.so processed skip_args arguments and bumped
|
||||||
|
_dl_argv and _dl_argc accordingly. Those arguments are removed from
|
||||||
|
@@ -1790,39 +1829,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
if (GLRO(dl_use_load_bias) == (ElfW(Addr)) -2)
|
||||||
|
GLRO(dl_use_load_bias) = main_map->l_addr == 0 ? -1 : 0;
|
||||||
|
|
||||||
|
- /* Set up the program header information for the dynamic linker
|
||||||
|
- itself. It is needed in the dl_iterate_phdr callbacks. */
|
||||||
|
- const ElfW(Ehdr) *rtld_ehdr;
|
||||||
|
-
|
||||||
|
- /* Starting from binutils-2.23, the linker will define the magic symbol
|
||||||
|
- __ehdr_start to point to our own ELF header if it is visible in a
|
||||||
|
- segment that also includes the phdrs. If that's not available, we use
|
||||||
|
- the old method that assumes the beginning of the file is part of the
|
||||||
|
- lowest-addressed PT_LOAD segment. */
|
||||||
|
-#ifdef HAVE_EHDR_START
|
||||||
|
- extern const ElfW(Ehdr) __ehdr_start __attribute__ ((visibility ("hidden")));
|
||||||
|
- rtld_ehdr = &__ehdr_start;
|
||||||
|
-#else
|
||||||
|
- rtld_ehdr = (void *) GL(dl_rtld_map).l_map_start;
|
||||||
|
-#endif
|
||||||
|
- assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
|
||||||
|
- assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
|
||||||
|
-
|
||||||
|
- const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
|
||||||
|
-
|
||||||
|
- GL(dl_rtld_map).l_phdr = rtld_phdr;
|
||||||
|
- GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
|
||||||
|
-
|
||||||
|
-
|
||||||
|
- /* PT_GNU_RELRO is usually the last phdr. */
|
||||||
|
- size_t cnt = rtld_ehdr->e_phnum;
|
||||||
|
- while (cnt-- > 0)
|
||||||
|
- if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
|
||||||
|
- {
|
||||||
|
- GL(dl_rtld_map).l_relro_addr = rtld_phdr[cnt].p_vaddr;
|
||||||
|
- GL(dl_rtld_map).l_relro_size = rtld_phdr[cnt].p_memsz;
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
+ rtld_setup_phdr ();
|
||||||
|
|
||||||
|
/* Add the dynamic linker to the TLS list if it also uses TLS. */
|
||||||
|
if (GL(dl_rtld_map).l_tls_blocksize != 0)
|
||||||
457
SOURCES/glibc-RHEL-104852-2.patch
Normal file
457
SOURCES/glibc-RHEL-104852-2.patch
Normal file
@ -0,0 +1,457 @@
|
|||||||
|
commit 20681be149b9eb1b6c1f4246bf4bd801221c86cd
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Aug 1 10:20:23 2025 +0200
|
||||||
|
|
||||||
|
elf: Handle ld.so with LOAD segment gaps in _dl_find_object (bug 31943)
|
||||||
|
|
||||||
|
Detect if ld.so not contiguous and handle that case in _dl_find_object.
|
||||||
|
Set l_find_object_processed even for initially loaded link maps,
|
||||||
|
otherwise dlopen of an initially loaded object adds it to
|
||||||
|
_dlfo_loaded_mappings (where maps are expected to be contiguous),
|
||||||
|
in addition to _dlfo_nodelete_mappings.
|
||||||
|
|
||||||
|
Test elf/tst-link-map-contiguous-ldso iterates over the loader
|
||||||
|
image, reading every word to make sure memory is actually mapped.
|
||||||
|
It only does that if the l_contiguous flag is set for the link map.
|
||||||
|
Otherwise, it finds gaps with mmap and checks that _dl_find_object
|
||||||
|
does not return the ld.so mapping for them.
|
||||||
|
|
||||||
|
The test elf/tst-link-map-contiguous-main does the same thing for
|
||||||
|
the libc.so shared object. This only works if the kernel loaded
|
||||||
|
the main program because the glibc dynamic loader may fill
|
||||||
|
the gaps with PROT_NONE mappings in some cases, making it contiguous,
|
||||||
|
but accesses to individual words may still fault.
|
||||||
|
|
||||||
|
Test elf/tst-link-map-contiguous-libc is again slightly different
|
||||||
|
because the dynamic loader always fills the gaps with PROT_NONE
|
||||||
|
mappings, so a different form of probing has to be used.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/dl-find_object.h
|
||||||
|
(missing SFrame support downstream. Update
|
||||||
|
l_find_object_processed early due to the possible
|
||||||
|
return from the for loop).
|
||||||
|
elf/dl-find_object.c
|
||||||
|
(missing is_rtld_link_map downstream)
|
||||||
|
elf/rtld.c
|
||||||
|
(missing GL(dl_rtld_map) refactoring downstream)
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index b37636c0f865f4e6..190ee83120c498a3 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -519,6 +519,8 @@ tests-internal += \
|
||||||
|
tst-dl-hwcaps_split \
|
||||||
|
tst-dlmopen2 \
|
||||||
|
tst-hash-collision3 \
|
||||||
|
+ tst-link-map-contiguous-ldso \
|
||||||
|
+ tst-link-map-contiguous-libc \
|
||||||
|
tst-ptrguard1 \
|
||||||
|
tst-stackguard1 \
|
||||||
|
tst-tls-surplus \
|
||||||
|
@@ -531,6 +533,10 @@ tests-internal += \
|
||||||
|
tst-dl_find_object tst-dl_find_object-threads \
|
||||||
|
# tests-internal
|
||||||
|
|
||||||
|
+ifeq ($(build-hardcoded-path-in-tests),yes)
|
||||||
|
+tests-internal += tst-link-map-contiguous-main
|
||||||
|
+endif
|
||||||
|
+
|
||||||
|
tests-container += \
|
||||||
|
tst-dlopen-self-container \
|
||||||
|
tst-dlopen-tlsmodid-container \
|
||||||
|
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
|
||||||
|
index 62a8a61f6b6032cf..128329aa20ef9ed6 100644
|
||||||
|
--- a/elf/dl-find_object.c
|
||||||
|
+++ b/elf/dl-find_object.c
|
||||||
|
@@ -468,6 +468,37 @@ rtld_hidden_def (__dl_find_object_internal)
|
||||||
|
strong_alias (__dl_find_object_internal, _dl_find_object)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+/* Subroutine of _dlfo_process_initial to split out noncontigous link
|
||||||
|
+ maps. NODELETE is the number of used _dlfo_nodelete_mappings
|
||||||
|
+ elements. It is incremented as needed, and the new NODELETE value
|
||||||
|
+ is returned. */
|
||||||
|
+static size_t
|
||||||
|
+_dlfo_process_initial_noncontiguous_map (struct link_map *map,
|
||||||
|
+ size_t nodelete)
|
||||||
|
+{
|
||||||
|
+ struct dl_find_object_internal dlfo;
|
||||||
|
+ _dl_find_object_from_map (map, &dlfo);
|
||||||
|
+
|
||||||
|
+ /* PT_LOAD segments for a non-contiguous link map are added to the
|
||||||
|
+ non-closeable mappings. */
|
||||||
|
+ const ElfW(Phdr) *ph = map->l_phdr;
|
||||||
|
+ const ElfW(Phdr) *ph_end = map->l_phdr + map->l_phnum;
|
||||||
|
+ for (; ph < ph_end; ++ph)
|
||||||
|
+ if (ph->p_type == PT_LOAD)
|
||||||
|
+ {
|
||||||
|
+ if (_dlfo_nodelete_mappings != NULL)
|
||||||
|
+ {
|
||||||
|
+ /* Second pass only. */
|
||||||
|
+ _dlfo_nodelete_mappings[nodelete] = dlfo;
|
||||||
|
+ ElfW(Addr) start = ph->p_vaddr + map->l_addr;
|
||||||
|
+ _dlfo_nodelete_mappings[nodelete].map_start = start;
|
||||||
|
+ _dlfo_nodelete_mappings[nodelete].map_end = start + ph->p_memsz;
|
||||||
|
+ }
|
||||||
|
+ ++nodelete;
|
||||||
|
+ }
|
||||||
|
+ return nodelete;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* _dlfo_process_initial is called twice. First to compute the array
|
||||||
|
sizes from the initial loaded mappings. Second to fill in the
|
||||||
|
bases and infos arrays with the (still unsorted) data. Returns the
|
||||||
|
@@ -479,29 +510,8 @@ _dlfo_process_initial (void)
|
||||||
|
|
||||||
|
size_t nodelete = 0;
|
||||||
|
if (!main_map->l_contiguous)
|
||||||
|
- {
|
||||||
|
- struct dl_find_object_internal dlfo;
|
||||||
|
- _dl_find_object_from_map (main_map, &dlfo);
|
||||||
|
-
|
||||||
|
- /* PT_LOAD segments for a non-contiguous are added to the
|
||||||
|
- non-closeable mappings. */
|
||||||
|
- for (const ElfW(Phdr) *ph = main_map->l_phdr,
|
||||||
|
- *ph_end = main_map->l_phdr + main_map->l_phnum;
|
||||||
|
- ph < ph_end; ++ph)
|
||||||
|
- if (ph->p_type == PT_LOAD)
|
||||||
|
- {
|
||||||
|
- if (_dlfo_nodelete_mappings != NULL)
|
||||||
|
- {
|
||||||
|
- /* Second pass only. */
|
||||||
|
- _dlfo_nodelete_mappings[nodelete] = dlfo;
|
||||||
|
- _dlfo_nodelete_mappings[nodelete].map_start
|
||||||
|
- = ph->p_vaddr + main_map->l_addr;
|
||||||
|
- _dlfo_nodelete_mappings[nodelete].map_end
|
||||||
|
- = _dlfo_nodelete_mappings[nodelete].map_start + ph->p_memsz;
|
||||||
|
- }
|
||||||
|
- ++nodelete;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
+ /* Contiguous case already handled in _dl_find_object_init. */
|
||||||
|
+ nodelete = _dlfo_process_initial_noncontiguous_map (main_map, nodelete);
|
||||||
|
|
||||||
|
size_t loaded = 0;
|
||||||
|
for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
|
||||||
|
@@ -513,11 +523,22 @@ _dlfo_process_initial (void)
|
||||||
|
/* lt_library link maps are implicitly NODELETE. */
|
||||||
|
if (l->l_type == lt_library || l->l_nodelete_active)
|
||||||
|
{
|
||||||
|
- if (_dlfo_nodelete_mappings != NULL)
|
||||||
|
- /* Second pass only. */
|
||||||
|
- _dl_find_object_from_map
|
||||||
|
- (l, _dlfo_nodelete_mappings + nodelete);
|
||||||
|
- ++nodelete;
|
||||||
|
+ /* The kernel may have loaded ld.so with gaps. */
|
||||||
|
+ if (!l->l_contiguous
|
||||||
|
+#ifdef SHARED
|
||||||
|
+ && l == &GL(dl_rtld_map)
|
||||||
|
+#endif
|
||||||
|
+ )
|
||||||
|
+ nodelete
|
||||||
|
+ = _dlfo_process_initial_noncontiguous_map (l, nodelete);
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ if (_dlfo_nodelete_mappings != NULL)
|
||||||
|
+ /* Second pass only. */
|
||||||
|
+ _dl_find_object_from_map
|
||||||
|
+ (l, _dlfo_nodelete_mappings + nodelete);
|
||||||
|
+ ++nodelete;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
else if (l->l_type == lt_loaded)
|
||||||
|
{
|
||||||
|
@@ -767,7 +788,6 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count)
|
||||||
|
/* Prefer newly loaded link map. */
|
||||||
|
assert (loaded_index1 > 0);
|
||||||
|
_dl_find_object_from_map (loaded[loaded_index1 - 1], dlfo);
|
||||||
|
- loaded[loaded_index1 - 1]->l_find_object_processed = 1;
|
||||||
|
--loaded_index1;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/elf/dl-find_object.h b/elf/dl-find_object.h
|
||||||
|
index 11569efc9b7daf9c..fae25747edc6dca0 100644
|
||||||
|
--- a/elf/dl-find_object.h
|
||||||
|
+++ b/elf/dl-find_object.h
|
||||||
|
@@ -87,7 +87,7 @@ _dl_find_object_to_external (struct dl_find_object_internal *internal,
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract the object location data from a link map and writes it to
|
||||||
|
- *RESULT using relaxed MO stores. */
|
||||||
|
+ *RESULT using relaxed MO stores. Set L->l_find_object_processed. */
|
||||||
|
static void __attribute__ ((unused))
|
||||||
|
_dl_find_object_from_map (struct link_map *l,
|
||||||
|
struct dl_find_object_internal *result)
|
||||||
|
@@ -100,6 +100,8 @@ _dl_find_object_from_map (struct link_map *l,
|
||||||
|
atomic_store_relaxed (&result->eh_dbase, (void *) l->l_info[DT_PLTGOT]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+ l->l_find_object_processed = 1;
|
||||||
|
+
|
||||||
|
for (const ElfW(Phdr) *ph = l->l_phdr, *ph_end = l->l_phdr + l->l_phnum;
|
||||||
|
ph < ph_end; ++ph)
|
||||||
|
if (ph->p_type == DLFO_EH_SEGMENT_TYPE)
|
||||||
|
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||||
|
index a9073d4e14b07410..425003e6c8e452ab 100644
|
||||||
|
--- a/elf/rtld.c
|
||||||
|
+++ b/elf/rtld.c
|
||||||
|
@@ -1308,7 +1308,7 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||||
|
|
||||||
|
/* Set up the program header information for the dynamic linker
|
||||||
|
itself. It can be accessed via _r_debug and dl_iterate_phdr
|
||||||
|
- callbacks. */
|
||||||
|
+ callbacks, and it is used by _dl_find_object. */
|
||||||
|
static void
|
||||||
|
rtld_setup_phdr (void)
|
||||||
|
{
|
||||||
|
@@ -1334,6 +1334,29 @@ rtld_setup_phdr (void)
|
||||||
|
GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
|
||||||
|
|
||||||
|
|
||||||
|
+ GL(dl_rtld_map).l_contiguous = 1;
|
||||||
|
+ /* The linker may not have produced a contiguous object. The kernel
|
||||||
|
+ will load the object with actual gaps (unlike the glibc loader
|
||||||
|
+ for shared objects, which always produces a contiguous mapping).
|
||||||
|
+ See similar logic in rtld_setup_main_map above. */
|
||||||
|
+ {
|
||||||
|
+ ElfW(Addr) expected_load_address = 0;
|
||||||
|
+ for (const ElfW(Phdr) *ph = rtld_phdr; ph < &rtld_phdr[rtld_ehdr->e_phnum];
|
||||||
|
+ ++ph)
|
||||||
|
+ if (ph->p_type == PT_LOAD)
|
||||||
|
+ {
|
||||||
|
+ ElfW(Addr) mapstart = ph->p_vaddr & ~(GLRO(dl_pagesize) - 1);
|
||||||
|
+ if (GL(dl_rtld_map).l_contiguous && expected_load_address != 0
|
||||||
|
+ && expected_load_address != mapstart)
|
||||||
|
+ GL(dl_rtld_map).l_contiguous = 0;
|
||||||
|
+ ElfW(Addr) allocend = ph->p_vaddr + ph->p_memsz;
|
||||||
|
+ /* The next expected address is the page following this load
|
||||||
|
+ segment. */
|
||||||
|
+ expected_load_address = ((allocend + GLRO(dl_pagesize) - 1)
|
||||||
|
+ & ~(GLRO(dl_pagesize) - 1));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* PT_GNU_RELRO is usually the last phdr. */
|
||||||
|
size_t cnt = rtld_ehdr->e_phnum;
|
||||||
|
while (cnt-- > 0)
|
||||||
|
diff --git a/elf/tst-link-map-contiguous-ldso.c b/elf/tst-link-map-contiguous-ldso.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..04de808bb234fe38
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-link-map-contiguous-ldso.c
|
||||||
|
@@ -0,0 +1,98 @@
|
||||||
|
+/* Check that _dl_find_object behavior matches up with gaps.
|
||||||
|
+ 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 <dlfcn.h>
|
||||||
|
+#include <gnu/lib-names.h>
|
||||||
|
+#include <link.h>
|
||||||
|
+#include <stdbool.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/xdlfcn.h>
|
||||||
|
+#include <support/xunistd.h>
|
||||||
|
+#include <sys/mman.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ struct link_map *l = xdlopen (LD_SO, RTLD_NOW);
|
||||||
|
+ if (!l->l_contiguous)
|
||||||
|
+ {
|
||||||
|
+ puts ("info: ld.so link map is not contiguous");
|
||||||
|
+
|
||||||
|
+ /* Try to find holes by probing with mmap. */
|
||||||
|
+ int pagesize = getpagesize ();
|
||||||
|
+ bool gap_found = false;
|
||||||
|
+ ElfW(Addr) addr = l->l_map_start;
|
||||||
|
+ TEST_COMPARE (addr % pagesize, 0);
|
||||||
|
+ while (addr < l->l_map_end)
|
||||||
|
+ {
|
||||||
|
+ void *expected = (void *) addr;
|
||||||
|
+ void *ptr = xmmap (expected, 1, PROT_READ | PROT_WRITE,
|
||||||
|
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
|
||||||
|
+ struct dl_find_object dlfo;
|
||||||
|
+ int dlfo_ret = _dl_find_object (expected, &dlfo);
|
||||||
|
+ if (ptr == expected)
|
||||||
|
+ {
|
||||||
|
+ if (dlfo_ret < 0)
|
||||||
|
+ {
|
||||||
|
+ TEST_COMPARE (dlfo_ret, -1);
|
||||||
|
+ printf ("info: hole without mapping data found at %p\n", ptr);
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ FAIL ("object \"%s\" found in gap at %p",
|
||||||
|
+ dlfo.dlfo_link_map->l_name, ptr);
|
||||||
|
+ gap_found = true;
|
||||||
|
+ }
|
||||||
|
+ else if (dlfo_ret == 0)
|
||||||
|
+ {
|
||||||
|
+ if ((void *) dlfo.dlfo_link_map != (void *) l)
|
||||||
|
+ {
|
||||||
|
+ printf ("info: object \"%s\" found at %p\n",
|
||||||
|
+ dlfo.dlfo_link_map->l_name, ptr);
|
||||||
|
+ gap_found = true;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ TEST_COMPARE (dlfo_ret, -1);
|
||||||
|
+ xmunmap (ptr, 1);
|
||||||
|
+ addr += pagesize;
|
||||||
|
+ }
|
||||||
|
+ if (!gap_found)
|
||||||
|
+ FAIL ("no ld.so gap found");
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ puts ("info: ld.so link map is contiguous");
|
||||||
|
+
|
||||||
|
+ /* Assert that ld.so is truly contiguous in memory. */
|
||||||
|
+ volatile long int *p = (volatile long int *) l->l_map_start;
|
||||||
|
+ volatile long int *end = (volatile long int *) l->l_map_end;
|
||||||
|
+ while (p < end)
|
||||||
|
+ {
|
||||||
|
+ *p;
|
||||||
|
+ ++p;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ xdlclose (l);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
|
diff --git a/elf/tst-link-map-contiguous-libc.c b/elf/tst-link-map-contiguous-libc.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..eb5728c765ac3cfb
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-link-map-contiguous-libc.c
|
||||||
|
@@ -0,0 +1,57 @@
|
||||||
|
+/* Check that the entire libc.so program image is readable if contiguous.
|
||||||
|
+ 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 <gnu/lib-names.h>
|
||||||
|
+#include <link.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/xdlfcn.h>
|
||||||
|
+#include <support/xunistd.h>
|
||||||
|
+#include <sys/mman.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ struct link_map *l = xdlopen (LIBC_SO, RTLD_NOW);
|
||||||
|
+
|
||||||
|
+ /* The dynamic loader fills holes with PROT_NONE mappings. */
|
||||||
|
+ if (!l->l_contiguous)
|
||||||
|
+ FAIL_EXIT1 ("libc.so link map is not contiguous");
|
||||||
|
+
|
||||||
|
+ /* Direct probing does not work because not everything is readable
|
||||||
|
+ due to PROT_NONE mappings. */
|
||||||
|
+ int pagesize = getpagesize ();
|
||||||
|
+ ElfW(Addr) addr = l->l_map_start;
|
||||||
|
+ TEST_COMPARE (addr % pagesize, 0);
|
||||||
|
+ while (addr < l->l_map_end)
|
||||||
|
+ {
|
||||||
|
+ void *expected = (void *) addr;
|
||||||
|
+ void *ptr = xmmap (expected, 1, PROT_READ | PROT_WRITE,
|
||||||
|
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
|
||||||
|
+ if (ptr == expected)
|
||||||
|
+ FAIL ("hole in libc.so memory image after %lu bytes",
|
||||||
|
+ (unsigned long int) (addr - l->l_map_start));
|
||||||
|
+ xmunmap (ptr, 1);
|
||||||
|
+ addr += pagesize;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ xdlclose (l);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+#include <support/test-driver.c>
|
||||||
|
diff --git a/elf/tst-link-map-contiguous-main.c b/elf/tst-link-map-contiguous-main.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..2d1a054f0fbb0855
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-link-map-contiguous-main.c
|
||||||
|
@@ -0,0 +1,45 @@
|
||||||
|
+/* Check that the entire main program image is readable if contiguous.
|
||||||
|
+ 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 <link.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/xdlfcn.h>
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ struct link_map *l = xdlopen ("", RTLD_NOW);
|
||||||
|
+ if (!l->l_contiguous)
|
||||||
|
+ FAIL_UNSUPPORTED ("main link map is not contiguous");
|
||||||
|
+
|
||||||
|
+ /* This check only works if the kernel loaded the main program. The
|
||||||
|
+ dynamic loader replaces gaps with PROT_NONE mappings, resulting
|
||||||
|
+ in faults. */
|
||||||
|
+ volatile long int *p = (volatile long int *) l->l_map_start;
|
||||||
|
+ volatile long int *end = (volatile long int *) l->l_map_end;
|
||||||
|
+ while (p < end)
|
||||||
|
+ {
|
||||||
|
+ *p;
|
||||||
|
+ ++p;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ xdlclose (l);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+#include <support/test-driver.c>
|
||||||
234
SOURCES/glibc-RHEL-105327.patch
Normal file
234
SOURCES/glibc-RHEL-105327.patch
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
commit 7ea06e994093fa0bcca0d0ee2c1db271d8d7885d
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Mon Jul 21 21:43:49 2025 +0200
|
||||||
|
|
||||||
|
posix: Fix double-free after allocation failure in regcomp (bug 33185)
|
||||||
|
|
||||||
|
If a memory allocation failure occurs during bracket expression
|
||||||
|
parsing in regcomp, a double-free error may result.
|
||||||
|
|
||||||
|
Reported-by: Anastasia Belova <abelova@astralinux.ru>
|
||||||
|
Co-authored-by: Paul Eggert <eggert@cs.ucla.edu>
|
||||||
|
Reviewed-by: Andreas K. Huettel <dilfridge@gentoo.org>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
posix/Makefile (New test added)
|
||||||
|
|
||||||
|
diff --git a/posix/Makefile b/posix/Makefile
|
||||||
|
index 7b70b4a736bc1215..562e8cb85fdb6f43 100644
|
||||||
|
--- a/posix/Makefile
|
||||||
|
+++ b/posix/Makefile
|
||||||
|
@@ -112,7 +112,8 @@ tests := test-errno tstgetopt testfnm runtests runptests \
|
||||||
|
tst-sched_getaffinity \
|
||||||
|
tst-cpuset-dynamic \
|
||||||
|
tst-cpuset-static \
|
||||||
|
- tst-spawn6
|
||||||
|
+ tst-spawn6 \
|
||||||
|
+ tst-regcomp-bracket-free
|
||||||
|
|
||||||
|
# Test for the glob symbol version that was replaced in glibc 2.27.
|
||||||
|
ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes)
|
||||||
|
diff --git a/posix/regcomp.c b/posix/regcomp.c
|
||||||
|
index 887e5b50684e22f5..005e6459bbe8bd55 100644
|
||||||
|
--- a/posix/regcomp.c
|
||||||
|
+++ b/posix/regcomp.c
|
||||||
|
@@ -3365,6 +3365,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;
|
||||||
|
@@ -3380,7 +3381,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-regcomp-bracket-free.c b/posix/tst-regcomp-bracket-free.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..3c091d8c44ebe56f
|
||||||
|
--- /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 (®, 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 (®, 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>
|
||||||
33
SOURCES/glibc-RHEL-105957.patch
Normal file
33
SOURCES/glibc-RHEL-105957.patch
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
Downstream patch only.
|
||||||
|
|
||||||
|
Revert changes made to elf/dl-readonly-area.c compared to
|
||||||
|
ed6a68bac7cd056abda9008019c71b167f0362dc since `_dl_find_object` has
|
||||||
|
been backported.
|
||||||
|
|
||||||
|
Note: `_dl_find_object` isn't directly made available internally
|
||||||
|
downstream, we can use `__dl_find_object_internal` instead.
|
||||||
|
|
||||||
|
diff --git a/elf/dl-readonly-area.c b/elf/dl-readonly-area.c
|
||||||
|
index 570b99b11527db13..3b39eed06a379ce3 100644
|
||||||
|
--- a/elf/dl-readonly-area.c
|
||||||
|
+++ b/elf/dl-readonly-area.c
|
||||||
|
@@ -40,16 +40,11 @@ check_relro (const struct link_map *l, uintptr_t start, uintptr_t end)
|
||||||
|
enum dl_readonly_area_error_type
|
||||||
|
_dl_readonly_area (const void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
- /* Protect against concurrent loads and unloads. */
|
||||||
|
- __rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||||
|
-
|
||||||
|
- const struct link_map *l = _dl_find_dso_for_object ((ElfW(Addr)) ptr);
|
||||||
|
-
|
||||||
|
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||||
|
-
|
||||||
|
- if (l == NULL)
|
||||||
|
+ struct dl_find_object dlfo;
|
||||||
|
+ if (__dl_find_object_internal ((void *)ptr, &dlfo) != 0)
|
||||||
|
return dl_readonly_area_not_found;
|
||||||
|
|
||||||
|
+ const struct link_map *l = dlfo.dlfo_link_map;
|
||||||
|
uintptr_t ptr_start = (uintptr_t) ptr;
|
||||||
|
uintptr_t ptr_end = ptr_start + size;
|
||||||
|
|
||||||
80
SOURCES/glibc-RHEL-105965.patch
Normal file
80
SOURCES/glibc-RHEL-105965.patch
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
commit 620f0730f311635cd0e175a3ae4d0fc700c76366
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Mon Jul 28 14:16:52 2025 +0200
|
||||||
|
|
||||||
|
elf: Compile _dl_debug_state separately (bug 33224)
|
||||||
|
|
||||||
|
This ensures that the compiler will not inline it, so that
|
||||||
|
debuggers which do not use the Systemtap probes can reliably
|
||||||
|
set a breakpoint on it.
|
||||||
|
|
||||||
|
Reviewed-by: Andreas K. Huettel <dilfridge@gentoo.org>
|
||||||
|
Tested-by: Andreas K. Huettel <dilfridge@gentoo.org>
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index b181150b36773d24..b37636c0f865f4e6 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -56,6 +56,7 @@ dl-routines = \
|
||||||
|
dl-close \
|
||||||
|
dl-debug \
|
||||||
|
dl-debug-symbols \
|
||||||
|
+ dl-debug_state \
|
||||||
|
dl-deps \
|
||||||
|
dl-exception \
|
||||||
|
dl-execstack \
|
||||||
|
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
|
||||||
|
index 4388a04cdf828898..8c1472a84ebfefe7 100644
|
||||||
|
--- a/elf/dl-debug.c
|
||||||
|
+++ b/elf/dl-debug.c
|
||||||
|
@@ -167,14 +167,3 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||||
|
|
||||||
|
return &r->base;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-/* This function exists solely to have a breakpoint set on it by the
|
||||||
|
- debugger. The debugger is supposed to find this function's address by
|
||||||
|
- examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks
|
||||||
|
- for this particular symbol name in the PT_INTERP file. */
|
||||||
|
-void
|
||||||
|
-_dl_debug_state (void)
|
||||||
|
-{
|
||||||
|
-}
|
||||||
|
-rtld_hidden_def (_dl_debug_state)
|
||||||
|
diff --git a/elf/dl-debug_state.c b/elf/dl-debug_state.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..40c134a49e2455f3
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/dl-debug_state.c
|
||||||
|
@@ -0,0 +1,30 @@
|
||||||
|
+/* Debugger hook called after dynamic linker updates.
|
||||||
|
+ Copyright (C) 1996-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 <ldsodefs.h>
|
||||||
|
+
|
||||||
|
+/* This function exists solely to have a breakpoint set on it by the
|
||||||
|
+ debugger. The debugger is supposed to find this function's address by
|
||||||
|
+ examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks
|
||||||
|
+ for this particular symbol name in the PT_INTERP file. Therefore,
|
||||||
|
+ this function must not be inlined. */
|
||||||
|
+void
|
||||||
|
+_dl_debug_state (void)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
+rtld_hidden_def (_dl_debug_state)
|
||||||
34
SOURCES/glibc-RHEL-106206.patch
Normal file
34
SOURCES/glibc-RHEL-106206.patch
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
commit 87afbd7a1ad9c1dd116921817fa97198171045db
|
||||||
|
Author: Sam James <sam@gentoo.org>
|
||||||
|
Date: Mon Jul 28 21:55:30 2025 +0100
|
||||||
|
|
||||||
|
inet-fortified: fix namespace violation (bug 33227)
|
||||||
|
|
||||||
|
We need to use __sz, not sz, as we do elsewhere.
|
||||||
|
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/inet/bits/inet-fortified.h b/inet/bits/inet-fortified.h
|
||||||
|
index 8420a4b7fb41086f..5d16b1f871c49e6f 100644
|
||||||
|
--- a/inet/bits/inet-fortified.h
|
||||||
|
+++ b/inet/bits/inet-fortified.h
|
||||||
|
@@ -38,15 +38,15 @@ __fortify_function int
|
||||||
|
__NTH (inet_pton (int __af, const char *__restrict __src,
|
||||||
|
void * __restrict __dst))
|
||||||
|
{
|
||||||
|
- size_t sz = 0;
|
||||||
|
+ size_t __sz = 0;
|
||||||
|
if (__af == AF_INET)
|
||||||
|
- sz = sizeof (struct in_addr);
|
||||||
|
+ __sz = sizeof (struct in_addr);
|
||||||
|
else if (__af == AF_INET6)
|
||||||
|
- sz = sizeof (struct in6_addr);
|
||||||
|
+ __sz = sizeof (struct in6_addr);
|
||||||
|
else
|
||||||
|
return __inet_pton_alias (__af, __src, __dst);
|
||||||
|
|
||||||
|
- return __glibc_fortify (inet_pton, sz, sizeof (char),
|
||||||
|
+ return __glibc_fortify (inet_pton, __sz, sizeof (char),
|
||||||
|
__glibc_objsize (__dst),
|
||||||
|
__af, __src, __dst);
|
||||||
|
};
|
||||||
39
SOURCES/glibc-RHEL-107518.patch
Normal file
39
SOURCES/glibc-RHEL-107518.patch
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
commit e5363e6f460c2d58809bf10fc96d70fd1ef8b5b2
|
||||||
|
Author: Jens Remus <jremus@linux.ibm.com>
|
||||||
|
Date: Fri Jul 25 15:40:03 2025 +0200
|
||||||
|
|
||||||
|
Use TLS initial-exec model for __libc_tsd_CTYPE_* thread variables [BZ #33234]
|
||||||
|
|
||||||
|
Commit 10a66a8e421b ("Remove <libc-tsd.h>") removed the TLS initial-exec
|
||||||
|
(IE) model attribute from the __libc_tsd_CTYPE_* thread variable declarations
|
||||||
|
and definitions. Commit a894f04d8776 ("Optimize __libc_tsd_* thread
|
||||||
|
variable access") restored it on declarations.
|
||||||
|
|
||||||
|
Restore the TLS initial-exec model attribute on __libc_tsd_CTYPE_* thread
|
||||||
|
variable definitions.
|
||||||
|
|
||||||
|
This resolves test tst-locale1 failure on s390 32-bit, when using a
|
||||||
|
GNU linker without the fix from GNU binutils commit aefebe82dc89
|
||||||
|
("IBM zSystems: Fix offset relative to static TLS").
|
||||||
|
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/ctype/ctype-info.c b/ctype/ctype-info.c
|
||||||
|
index e0752b4a1af6df15..315cedcfaa357ead 100644
|
||||||
|
--- a/ctype/ctype-info.c
|
||||||
|
+++ b/ctype/ctype-info.c
|
||||||
|
@@ -24,11 +24,11 @@
|
||||||
|
__ctype_init before user code runs, but this does not happen for
|
||||||
|
threads in secondary namespaces. With the initializers, secondary
|
||||||
|
namespaces at least get locale data from the C locale. */
|
||||||
|
-__thread const uint16_t * __libc_tsd_CTYPE_B
|
||||||
|
+__thread const uint16_t * __libc_tsd_CTYPE_B attribute_tls_model_ie
|
||||||
|
= (const uint16_t *) _nl_C_LC_CTYPE_class + 128;
|
||||||
|
-__thread const int32_t * __libc_tsd_CTYPE_TOLOWER
|
||||||
|
+__thread const int32_t * __libc_tsd_CTYPE_TOLOWER attribute_tls_model_ie
|
||||||
|
= (const int32_t *) _nl_C_LC_CTYPE_tolower + 128;
|
||||||
|
-__thread const int32_t * __libc_tsd_CTYPE_TOUPPER
|
||||||
|
+__thread const int32_t * __libc_tsd_CTYPE_TOUPPER attribute_tls_model_ie
|
||||||
|
= (const int32_t *) _nl_C_LC_CTYPE_toupper + 128;
|
||||||
|
|
||||||
|
|
||||||
35
SOURCES/glibc-RHEL-107564.patch
Normal file
35
SOURCES/glibc-RHEL-107564.patch
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
Downstream-only patch correcting the GLIBC_PRIVATE ABI preservation
|
||||||
|
change in glibc-RHEL-93320-19.patch.
|
||||||
|
|
||||||
|
This patch adds a symbol alias that supplies the expect external
|
||||||
|
name _dl_find_object within libc.a, where the forwarder in
|
||||||
|
elf/libc-dl_find_object.c no longer exists after the changes
|
||||||
|
in glibc-RHEL-93320-19.patch. It also brings back the
|
||||||
|
tst-dl_find_object-static static linking test.
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index ba11f3a8b81e7218..7b75afda32bcd579 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -281,6 +281,7 @@ tests-static-normal := \
|
||||||
|
# tests-static-normal
|
||||||
|
|
||||||
|
tests-static-internal := \
|
||||||
|
+ tst-dl_find_object-static \
|
||||||
|
tst-ptrguard1-static \
|
||||||
|
tst-stackguard1-static \
|
||||||
|
tst-tls1-static \
|
||||||
|
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
|
||||||
|
index 99797580066cdce8..62a8a61f6b6032cf 100644
|
||||||
|
--- a/elf/dl-find_object.c
|
||||||
|
+++ b/elf/dl-find_object.c
|
||||||
|
@@ -464,6 +464,9 @@ __dl_find_object_internal (void *pc1, struct dl_find_object *result)
|
||||||
|
} /* Transaction retry loop. */
|
||||||
|
}
|
||||||
|
rtld_hidden_def (__dl_find_object_internal)
|
||||||
|
+#ifndef SHARED
|
||||||
|
+strong_alias (__dl_find_object_internal, _dl_find_object)
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
/* _dlfo_process_initial is called twice. First to compute the array
|
||||||
|
sizes from the initial loaded mappings. Second to fill in the
|
||||||
18
SOURCES/glibc-RHEL-108220.patch
Normal file
18
SOURCES/glibc-RHEL-108220.patch
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Downstream-only patch to remove duplicate Makefile target entry for
|
||||||
|
tst-dlmopen1mod.
|
||||||
|
|
||||||
|
Conflict resolution in glibc-RHEL-93320-4.patch led to the duplicate
|
||||||
|
tst-dlmopen1mod entry. Therefore remove it.
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index 190ee83120c498a3..e8587b10c1a8bedd 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -811,7 +811,6 @@ modules-names = \
|
||||||
|
tst-dl_find_object-mod7 \
|
||||||
|
tst-dl_find_object-mod8 \
|
||||||
|
tst-dl_find_object-mod9 \
|
||||||
|
- tst-dlmopen1mod \
|
||||||
|
tst-dlclose-lazy-mod1 \
|
||||||
|
tst-dlclose-lazy-mod2 \
|
||||||
|
tst-dlmopen-dlerror-mod \
|
||||||
36
SOURCES/glibc-RHEL-108221.patch
Normal file
36
SOURCES/glibc-RHEL-108221.patch
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
In glibc-RHEL-93320-9.patch, the elf/tst-dl_find_object test was
|
||||||
|
added. It was later disabled in glibc-RHEL-93320-19.patch,
|
||||||
|
as noted in the patch description. This was missed when the
|
||||||
|
patch was re-added in glibc-RHEL-107564.patch. The test remains
|
||||||
|
valuable because we do not test _dl_find_object in libc.a elsewhere
|
||||||
|
in the glibc build, so this patch disables just the failing subtest,
|
||||||
|
and puts an explanation directly into the test.
|
||||||
|
|
||||||
|
diff --git a/elf/tst-dl_find_object.c b/elf/tst-dl_find_object.c
|
||||||
|
index d8c217545d116453..6bfda7bd23a34c0d 100644
|
||||||
|
--- a/elf/tst-dl_find_object.c
|
||||||
|
+++ b/elf/tst-dl_find_object.c
|
||||||
|
@@ -231,6 +231,7 @@ do_test (void)
|
||||||
|
check (map_start, &expected, __LINE__);
|
||||||
|
check (map_end, &expected, __LINE__);
|
||||||
|
|
||||||
|
+#ifndef FOR_STATIC
|
||||||
|
/* Check that _dl_find_object works from a shared object (mostly for
|
||||||
|
static dlopen). */
|
||||||
|
__typeof (_dl_find_object) *find_object
|
||||||
|
@@ -238,6 +239,15 @@ do_test (void)
|
||||||
|
struct dl_find_object actual;
|
||||||
|
TEST_COMPARE (find_object (&main_program_data, &actual), 0);
|
||||||
|
check (&main_program_data, &actual, __LINE__); /* Reversed check. */
|
||||||
|
+#else
|
||||||
|
+ /* Downstream, _dl_find_object does not work after static dlopen
|
||||||
|
+ because the ld.so copy loaded as part of static dlopen is not
|
||||||
|
+ initialized. Upstream, we redirect _dl_find_object to the
|
||||||
|
+ statically version from the main program by patching a function
|
||||||
|
+ pointer in _rtld_global_ro. Downstream, we have not changed the
|
||||||
|
+ layout of _rtld_global_ro, so this patching is missing. */
|
||||||
|
+ printf ("info: skipping dlopen-based test for static build\n");
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
226
SOURCES/glibc-RHEL-24168-1.patch
Normal file
226
SOURCES/glibc-RHEL-24168-1.patch
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
Downstream-only patch to add arc4random to support/ for use in qsort
|
||||||
|
testing.
|
||||||
|
|
||||||
|
The arc4random implementation is up-to-date with upstream commit
|
||||||
|
2642002380aafb71a1d3b569b6d7ebeab3284816, with minor changes to keep
|
||||||
|
everything self-contained within support infrastructure. Unlike the
|
||||||
|
upstream version, this implementation is a cancellation point.
|
||||||
|
|
||||||
|
diff --git a/support/Makefile b/support/Makefile
|
||||||
|
index d6d03c2ed3af3e6d..bffcb06d7185d674 100644
|
||||||
|
--- a/support/Makefile
|
||||||
|
+++ b/support/Makefile
|
||||||
|
@@ -41,6 +41,8 @@ libsupport-routines = \
|
||||||
|
resolv_response_context_free \
|
||||||
|
resolv_test \
|
||||||
|
set_fortify_handler \
|
||||||
|
+ support-arc4random \
|
||||||
|
+ support-arc4random_uniform \
|
||||||
|
support-open-dev-null-range \
|
||||||
|
support_become_root \
|
||||||
|
support_can_chroot \
|
||||||
|
diff --git a/support/support-arc4random.c b/support/support-arc4random.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..c4462b098c68cef5
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/support/support-arc4random.c
|
||||||
|
@@ -0,0 +1,99 @@
|
||||||
|
+/* Pseudo Random Number Generator
|
||||||
|
+ Copyright (C) 2022-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 <errno.h>
|
||||||
|
+#include <not-cancel.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <sys/mman.h>
|
||||||
|
+#include <sys/param.h>
|
||||||
|
+#include <sys/random.h>
|
||||||
|
+#include <poll.h>
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+arc4random_getrandom_failure (void)
|
||||||
|
+{
|
||||||
|
+ __libc_fatal ("Fatal glibc error: cannot get entropy for arc4random\n");
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+arc4random_buf (void *p, size_t n)
|
||||||
|
+{
|
||||||
|
+ static int seen_initialized;
|
||||||
|
+ ssize_t l;
|
||||||
|
+ int fd;
|
||||||
|
+
|
||||||
|
+ if (n == 0)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ for (;;)
|
||||||
|
+ {
|
||||||
|
+ l = TEMP_FAILURE_RETRY (getrandom (p, n, 0));
|
||||||
|
+ if (l > 0)
|
||||||
|
+ {
|
||||||
|
+ if ((size_t) l == n)
|
||||||
|
+ return; /* Done reading, success. */
|
||||||
|
+ p = (uint8_t *) p + l;
|
||||||
|
+ n -= l;
|
||||||
|
+ continue; /* Interrupted by a signal; keep going. */
|
||||||
|
+ }
|
||||||
|
+ else if (l < 0 && errno == ENOSYS)
|
||||||
|
+ break; /* No syscall, so fallback to /dev/urandom. */
|
||||||
|
+ arc4random_getrandom_failure ();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (atomic_load_relaxed (&seen_initialized) == 0)
|
||||||
|
+ {
|
||||||
|
+ /* Poll /dev/random as an approximation of RNG initialization. */
|
||||||
|
+ struct pollfd pfd = { .events = POLLIN };
|
||||||
|
+ pfd.fd = TEMP_FAILURE_RETRY (
|
||||||
|
+ __open64_nocancel ("/dev/random", O_RDONLY | O_CLOEXEC | O_NOCTTY));
|
||||||
|
+ if (pfd.fd < 0)
|
||||||
|
+ arc4random_getrandom_failure ();
|
||||||
|
+ if (TEMP_FAILURE_RETRY (poll (&pfd, 1, -1)) < 0)
|
||||||
|
+ arc4random_getrandom_failure ();
|
||||||
|
+ if (__close_nocancel (pfd.fd) < 0)
|
||||||
|
+ arc4random_getrandom_failure ();
|
||||||
|
+ atomic_store_relaxed (&seen_initialized, 1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ fd = TEMP_FAILURE_RETRY (
|
||||||
|
+ __open64_nocancel ("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY));
|
||||||
|
+ if (fd < 0)
|
||||||
|
+ arc4random_getrandom_failure ();
|
||||||
|
+ for (;;)
|
||||||
|
+ {
|
||||||
|
+ l = TEMP_FAILURE_RETRY (__read_nocancel (fd, p, n));
|
||||||
|
+ if (l <= 0)
|
||||||
|
+ arc4random_getrandom_failure ();
|
||||||
|
+ if ((size_t) l == n)
|
||||||
|
+ break; /* Done reading, success. */
|
||||||
|
+ p = (uint8_t *) p + l;
|
||||||
|
+ n -= l;
|
||||||
|
+ }
|
||||||
|
+ if (__close_nocancel (fd) < 0)
|
||||||
|
+ arc4random_getrandom_failure ();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+uint32_t
|
||||||
|
+arc4random (void)
|
||||||
|
+{
|
||||||
|
+ uint32_t r;
|
||||||
|
+ arc4random_buf (&r, sizeof (r));
|
||||||
|
+ return r;
|
||||||
|
+}
|
||||||
|
diff --git a/support/support-arc4random_uniform.c b/support/support-arc4random_uniform.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..20108e7409cca81b
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/support/support-arc4random_uniform.c
|
||||||
|
@@ -0,0 +1,70 @@
|
||||||
|
+/* Random pseudo generator number which returns a single 32 bit value
|
||||||
|
+ uniformly distributed but with an upper_bound.
|
||||||
|
+ Copyright (C) 2022-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 <stdlib.h>
|
||||||
|
+#include <sys/param.h>
|
||||||
|
+#include <support/support.h>
|
||||||
|
+
|
||||||
|
+/* Return a uniformly distributed random number less than N. The algorithm
|
||||||
|
+ calculates a mask being the lowest power of two bounding the upper bound
|
||||||
|
+ N, successively queries new random values, and rejects values outside of
|
||||||
|
+ the request range.
|
||||||
|
+
|
||||||
|
+ For reject values, it also tries if the remaining entropy could fit on
|
||||||
|
+ the asked range after range adjustment.
|
||||||
|
+
|
||||||
|
+ The algorithm avoids modulo and divide operations, which might be costly
|
||||||
|
+ depending on the architecture. */
|
||||||
|
+uint32_t
|
||||||
|
+arc4random_uniform (uint32_t n)
|
||||||
|
+{
|
||||||
|
+ if (n <= 1)
|
||||||
|
+ /* There is no valid return value for a zero limit, and 0 is the
|
||||||
|
+ only possible result for limit 1. */
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ /* Powers of two are easy. */
|
||||||
|
+ if (powerof2 (n))
|
||||||
|
+ return arc4random () & (n - 1);
|
||||||
|
+
|
||||||
|
+ /* mask is the smallest power of 2 minus 1 number larger than n. */
|
||||||
|
+ int z = __builtin_clz (n);
|
||||||
|
+ uint32_t mask = ~UINT32_C(0) >> z;
|
||||||
|
+ int bits = CHAR_BIT * sizeof (uint32_t) - z;
|
||||||
|
+
|
||||||
|
+ while (1)
|
||||||
|
+ {
|
||||||
|
+ uint32_t value = arc4random ();
|
||||||
|
+
|
||||||
|
+ /* Return if the lower power of 2 minus 1 satisfy the condition. */
|
||||||
|
+ uint32_t r = value & mask;
|
||||||
|
+ if (r < n)
|
||||||
|
+ return r;
|
||||||
|
+
|
||||||
|
+ /* Otherwise check if remaining bits of entropy provides fits in the
|
||||||
|
+ bound. */
|
||||||
|
+ for (int bits_left = z; bits_left >= bits; bits_left -= bits)
|
||||||
|
+ {
|
||||||
|
+ value >>= bits;
|
||||||
|
+ r = value & mask;
|
||||||
|
+ if (r < n)
|
||||||
|
+ return r;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/support/support.h b/support/support.h
|
||||||
|
index b69f588e2edce6be..ed7862daf9e4120a 100644
|
||||||
|
--- a/support/support.h
|
||||||
|
+++ b/support/support.h
|
||||||
|
@@ -220,6 +220,19 @@ void support_stack_free (struct support_stack *stack);
|
||||||
|
The returned value is the lowest file descriptor number. */
|
||||||
|
int support_open_dev_null_range (int num, int flags, mode_t mode);
|
||||||
|
|
||||||
|
+/* Return a random integer between zero and 2**32-1 (inclusive). */
|
||||||
|
+extern uint32_t arc4random (void)
|
||||||
|
+ __THROW __wur;
|
||||||
|
+
|
||||||
|
+/* Fill the buffer with random data. */
|
||||||
|
+extern void arc4random_buf (void *__buf, size_t __size)
|
||||||
|
+ __THROW __nonnull ((1));
|
||||||
|
+
|
||||||
|
+/* Return a random number between zero (inclusive) and the specified
|
||||||
|
+ limit (exclusive). */
|
||||||
|
+extern uint32_t arc4random_uniform (__uint32_t __upper_bound)
|
||||||
|
+ __THROW __wur;
|
||||||
|
+
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif /* SUPPORT_H */
|
||||||
43
SOURCES/glibc-RHEL-24168-10.patch
Normal file
43
SOURCES/glibc-RHEL-24168-10.patch
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
commit f8cfb6836e8d91bb789b2e7fd65338d6f5bd459c
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Wed Nov 8 15:18:02 2023 +0100
|
||||||
|
|
||||||
|
stdlib: Avoid element self-comparisons in qsort
|
||||||
|
|
||||||
|
This improves compatibility with applications which assume that qsort
|
||||||
|
does not invoke the comparison function with equal pointer arguments.
|
||||||
|
|
||||||
|
The newly introduced branches should be predictable, as leading to a
|
||||||
|
call to the comparison function. If the prediction fails, we avoid
|
||||||
|
calling the function.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index cb1619aa0ae7de72..2ee39e2c492f792e 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -137,7 +137,7 @@ siftdown (void *base, size_t size, size_t k, size_t n,
|
||||||
|
if (j < n && cmp (base + (j * size), base + ((j + 1) * size), arg) < 0)
|
||||||
|
j++;
|
||||||
|
|
||||||
|
- if (cmp (base + (k * size), base + (j * size), arg) >= 0)
|
||||||
|
+ if (j == k || cmp (base + (k * size), base + (j * size), arg) >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
do_swap (base + (size * j), base + (k * size), size, swap_type);
|
||||||
|
@@ -333,10 +333,12 @@ __qsort_r (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
that this algorithm runs much faster than others. */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
- while ((*cmp) ((void *) left_ptr, (void *) mid, arg) < 0)
|
||||||
|
+ while (left_ptr != mid
|
||||||
|
+ && (*cmp) ((void *) left_ptr, (void *) mid, arg) < 0)
|
||||||
|
left_ptr += size;
|
||||||
|
|
||||||
|
- while ((*cmp) ((void *) mid, (void *) right_ptr, arg) < 0)
|
||||||
|
+ while (right_ptr != mid
|
||||||
|
+ && (*cmp) ((void *) mid, (void *) right_ptr, arg) < 0)
|
||||||
|
right_ptr -= size;
|
||||||
|
|
||||||
|
if (left_ptr < right_ptr)
|
||||||
25
SOURCES/glibc-RHEL-24168-11.patch
Normal file
25
SOURCES/glibc-RHEL-24168-11.patch
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
commit e4d8117b82065dc72e8df80097360e7c05a349b9
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Tue Nov 21 16:45:35 2023 +0100
|
||||||
|
|
||||||
|
stdlib: Avoid another self-comparison in qsort
|
||||||
|
|
||||||
|
In the insertion phase, we could run off the start of the array if the
|
||||||
|
comparison function never runs zero. In that case, it never finds the
|
||||||
|
initial element that terminates the iteration.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index 2ee39e2c492f792e..0d5f8b92e8072965 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -218,7 +218,7 @@ insertion_sort_qsort_partitions (void *const pbase, size_t total_elems,
|
||||||
|
while ((run_ptr += size) <= end_ptr)
|
||||||
|
{
|
||||||
|
tmp_ptr = run_ptr - size;
|
||||||
|
- while (cmp (run_ptr, tmp_ptr, arg) < 0)
|
||||||
|
+ while (run_ptr != tmp_ptr && cmp (run_ptr, tmp_ptr, arg) < 0)
|
||||||
|
tmp_ptr -= size;
|
||||||
|
|
||||||
|
tmp_ptr += size;
|
||||||
273
SOURCES/glibc-RHEL-24168-12.patch
Normal file
273
SOURCES/glibc-RHEL-24168-12.patch
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
commit 55364e1f7dfab372f0710513c4d1c967c4965f71
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Tue Nov 21 16:45:35 2023 +0100
|
||||||
|
|
||||||
|
stdlib: Handle various corner cases in the fallback heapsort for qsort
|
||||||
|
|
||||||
|
The previous implementation did not consistently apply the rule that
|
||||||
|
the child nodes of node K are at 2 * K + 1 and 2 * K + 2, or
|
||||||
|
that the parent node is at (K - 1) / 2.
|
||||||
|
|
||||||
|
Add an internal test that targets the heapsort implementation
|
||||||
|
directly.
|
||||||
|
|
||||||
|
Reported-by: Stepan Golosunov <stepan@golosunov.pp.ru>
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||||||
|
index 4039e5395eeea2b0..ee005ce8caa48abe 100644
|
||||||
|
--- a/stdlib/Makefile
|
||||||
|
+++ b/stdlib/Makefile
|
||||||
|
@@ -254,6 +254,7 @@ tests := \
|
||||||
|
# tests
|
||||||
|
|
||||||
|
tests-internal := \
|
||||||
|
+ tst-qsort4 \
|
||||||
|
tst-strtod1i \
|
||||||
|
tst-strtod3 \
|
||||||
|
tst-strtod4 \
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index 0d5f8b92e8072965..b207c12d2f0a38cc 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -126,29 +126,44 @@ pop (stack_node *top, char **lo, char **hi, size_t *depth)
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* NB: N is inclusive bound for BASE. */
|
||||||
|
+/* Establish the heap condition at index K, that is, the key at K will
|
||||||
|
+ not be less than either of its children, at 2 * K + 1 and 2 * K + 2
|
||||||
|
+ (if they exist). N is the last valid index. */
|
||||||
|
static inline void
|
||||||
|
siftdown (void *base, size_t size, size_t k, size_t n,
|
||||||
|
enum swap_type_t swap_type, __compar_d_fn_t cmp, void *arg)
|
||||||
|
{
|
||||||
|
- while (k <= n / 2)
|
||||||
|
+ /* There can only be a heap condition violation if there are
|
||||||
|
+ children. */
|
||||||
|
+ while (2 * k + 1 <= n)
|
||||||
|
{
|
||||||
|
- size_t j = 2 * k;
|
||||||
|
+ /* Left child. */
|
||||||
|
+ size_t j = 2 * k + 1;
|
||||||
|
+ /* If the right child is larger, use it. */
|
||||||
|
if (j < n && cmp (base + (j * size), base + ((j + 1) * size), arg) < 0)
|
||||||
|
j++;
|
||||||
|
|
||||||
|
+ /* If k is already >= to its children, we are done. */
|
||||||
|
if (j == k || cmp (base + (k * size), base + (j * size), arg) >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
+ /* Heal the violation. */
|
||||||
|
do_swap (base + (size * j), base + (k * size), size, swap_type);
|
||||||
|
+
|
||||||
|
+ /* Swapping with j may have introduced a violation at j. Fix
|
||||||
|
+ it in the next loop iteration. */
|
||||||
|
k = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* Establish the heap condition for the indices 0 to N (inclusive). */
|
||||||
|
static inline void
|
||||||
|
heapify (void *base, size_t size, size_t n, enum swap_type_t swap_type,
|
||||||
|
__compar_d_fn_t cmp, void *arg)
|
||||||
|
{
|
||||||
|
+ /* If n is odd, k = n / 2 has a left child at n, so this is the
|
||||||
|
+ largest index that can have a heap condition violation regarding
|
||||||
|
+ its children. */
|
||||||
|
size_t k = n / 2;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
@@ -158,32 +173,38 @@ heapify (void *base, size_t size, size_t n, enum swap_type_t swap_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* A non-recursive heapsort, used on introsort implementation as a fallback
|
||||||
|
- routine with worst-case performance of O(nlog n) and worst-case space
|
||||||
|
- complexity of O(1). It sorts the array starting at BASE and ending at
|
||||||
|
- END, with each element of SIZE bytes. The SWAP_TYPE is the callback
|
||||||
|
- function used to swap elements, and CMP is the function used to compare
|
||||||
|
- elements. */
|
||||||
|
+/* A non-recursive heapsort, used on introsort implementation as a
|
||||||
|
+ fallback routine with worst-case performance of O(nlog n) and
|
||||||
|
+ worst-case space complexity of O(1). It sorts the array starting
|
||||||
|
+ at BASE and ending at END (inclusive), with each element of SIZE
|
||||||
|
+ bytes. The SWAP_TYPE is the callback function used to swap
|
||||||
|
+ elements, and CMP is the function used to compare elements. */
|
||||||
|
static void
|
||||||
|
heapsort_r (void *base, void *end, size_t size, enum swap_type_t swap_type,
|
||||||
|
__compar_d_fn_t cmp, void *arg)
|
||||||
|
{
|
||||||
|
- const size_t count = ((uintptr_t) end - (uintptr_t) base) / size;
|
||||||
|
-
|
||||||
|
- if (count < 2)
|
||||||
|
+ size_t n = ((uintptr_t) end - (uintptr_t) base) / size;
|
||||||
|
+ if (n <= 1)
|
||||||
|
+ /* Handled by insertion sort. */
|
||||||
|
return;
|
||||||
|
|
||||||
|
- size_t n = count - 1;
|
||||||
|
-
|
||||||
|
/* Build the binary heap, largest value at the base[0]. */
|
||||||
|
heapify (base, size, n, swap_type, cmp, arg);
|
||||||
|
|
||||||
|
- /* On each iteration base[0:n] is the binary heap, while base[n:count]
|
||||||
|
- is sorted. */
|
||||||
|
- while (n > 0)
|
||||||
|
+ while (true)
|
||||||
|
{
|
||||||
|
+ /* Indices 0 .. n contain the binary heap. Extract the largest
|
||||||
|
+ element put it into the final position in the array. */
|
||||||
|
do_swap (base, base + (n * size), size, swap_type);
|
||||||
|
+
|
||||||
|
+ /* The heap is now one element shorter. */
|
||||||
|
n--;
|
||||||
|
+ if (n == 0)
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ /* By swapping in elements 0 and the previous value of n (now at
|
||||||
|
+ n + 1), we likely introduced a heap condition violation. Fix
|
||||||
|
+ it for the reduced heap. */
|
||||||
|
siftdown (base, size, 0, n, swap_type, cmp, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/stdlib/tst-qsort4.c b/stdlib/tst-qsort4.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..a7abaa1a37461666
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdlib/tst-qsort4.c
|
||||||
|
@@ -0,0 +1,134 @@
|
||||||
|
+/* Test the heapsort implementation behind qsort.
|
||||||
|
+ Copyright (C) 2023 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
|
||||||
|
+ <http://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include "qsort.c"
|
||||||
|
+
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/support.h>
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+cmp (const void *a1, const void *b1, void *closure)
|
||||||
|
+{
|
||||||
|
+ const signed char *a = a1;
|
||||||
|
+ const signed char *b = b1;
|
||||||
|
+ return *a - *b;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Wrapper around heapsort_r that set ups the required variables. */
|
||||||
|
+static void
|
||||||
|
+heapsort_wrapper (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
+ __compar_d_fn_t cmp, void *arg)
|
||||||
|
+{
|
||||||
|
+ char *base_ptr = (char *) pbase;
|
||||||
|
+ char *lo = base_ptr;
|
||||||
|
+ char *hi = &lo[size * (total_elems - 1)];
|
||||||
|
+
|
||||||
|
+ if (total_elems <= 1)
|
||||||
|
+ /* Avoid lossage with unsigned arithmetic below. */
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ enum swap_type_t swap_type;
|
||||||
|
+ if (is_aligned (pbase, size, 8))
|
||||||
|
+ swap_type = SWAP_WORDS_64;
|
||||||
|
+ else if (is_aligned (pbase, size, 4))
|
||||||
|
+ swap_type = SWAP_WORDS_32;
|
||||||
|
+ else
|
||||||
|
+ swap_type = SWAP_BYTES;
|
||||||
|
+ heapsort_r (lo, hi, size, swap_type, cmp, arg);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+check_one_sort (signed char *array, int length)
|
||||||
|
+{
|
||||||
|
+ signed char *copy = xmalloc (length);
|
||||||
|
+ memcpy (copy, array, length);
|
||||||
|
+ heapsort_wrapper (copy, length, 1, cmp, NULL);
|
||||||
|
+
|
||||||
|
+ /* Verify that the result is sorted. */
|
||||||
|
+ for (int i = 1; i < length; ++i)
|
||||||
|
+ if (copy[i] < copy[i - 1])
|
||||||
|
+ {
|
||||||
|
+ support_record_failure ();
|
||||||
|
+ printf ("error: sorting failure for length %d at offset %d\n",
|
||||||
|
+ length, i - 1);
|
||||||
|
+ printf ("input:");
|
||||||
|
+ for (int i = 0; i < length; ++i)
|
||||||
|
+ printf (" %d", array[i]);
|
||||||
|
+ printf ("\noutput:");
|
||||||
|
+ for (int i = 0; i < length; ++i)
|
||||||
|
+ printf (" %d", copy[i]);
|
||||||
|
+ putchar ('\n');
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Verify that no elements went away or were added. */
|
||||||
|
+ {
|
||||||
|
+ int expected_counts[256];
|
||||||
|
+ for (int i = 0; i < length; ++i)
|
||||||
|
+ ++expected_counts[array[i] & 0xff];
|
||||||
|
+ int actual_counts[256];
|
||||||
|
+ for (int i = 0; i < length; ++i)
|
||||||
|
+ ++actual_counts[copy[i] & 0xff];
|
||||||
|
+ for (int i = 0; i < 256; ++i)
|
||||||
|
+ TEST_COMPARE (expected_counts[i], expected_counts[i]);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ free (copy);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Enumerate all possible combinations of LENGTH elements. */
|
||||||
|
+static void
|
||||||
|
+check_combinations (int length, signed char *start, int offset)
|
||||||
|
+{
|
||||||
|
+ if (offset == length)
|
||||||
|
+ check_one_sort (start, length);
|
||||||
|
+ else
|
||||||
|
+ for (int i = 0; i < length; ++i)
|
||||||
|
+ {
|
||||||
|
+ start[offset] = i;
|
||||||
|
+ check_combinations(length, start, offset + 1);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ /* A random permutation of 20 values. */
|
||||||
|
+ check_one_sort ((signed char[20]) {5, 12, 16, 10, 14, 11, 9, 13, 8, 15,
|
||||||
|
+ 0, 17, 3, 7, 1, 18, 2, 19, 4, 6}, 20);
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ /* A permutation that appeared during adversarial testing for the
|
||||||
|
+ quicksort pass. */
|
||||||
|
+ check_one_sort ((signed char[16]) {15, 3, 4, 2, 1, 0, 8, 7, 6, 5, 14,
|
||||||
|
+ 13, 12, 11, 10, 9}, 16);
|
||||||
|
+
|
||||||
|
+ /* Array lengths 2 and less are not handled by heapsort_r and
|
||||||
|
+ deferred to insertion sort. */
|
||||||
|
+ for (int i = 3; i <= 8; ++i)
|
||||||
|
+ {
|
||||||
|
+ signed char *buf = xmalloc (i);
|
||||||
|
+ check_combinations (i, buf, 0);
|
||||||
|
+ free (buf);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
248
SOURCES/glibc-RHEL-24168-13.patch
Normal file
248
SOURCES/glibc-RHEL-24168-13.patch
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
commit 64e4acf24da15c11cb83f933947df3b2e8a700cd
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Tue Nov 21 16:45:35 2023 +0100
|
||||||
|
|
||||||
|
stdlib: The qsort implementation needs to use heapsort in more cases
|
||||||
|
|
||||||
|
The existing logic avoided internal stack overflow. To avoid
|
||||||
|
a denial-of-service condition with adversarial input, it is necessary
|
||||||
|
to fall over to heapsort if tail-recursing deeply, too, which does
|
||||||
|
not result in a deep stack of pending partitions.
|
||||||
|
|
||||||
|
The new test stdlib/tst-qsort5 is based on Douglas McIlroy's paper
|
||||||
|
on this subject.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
stdlib/Makefile: Adjust for getenv tests in glibc-RHEL-67692-4.patch.
|
||||||
|
|
||||||
|
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||||||
|
index ee005ce8caa48abe..a1a511da37f0c18e 100644
|
||||||
|
--- a/stdlib/Makefile
|
||||||
|
+++ b/stdlib/Makefile
|
||||||
|
@@ -212,6 +212,7 @@ tests := \
|
||||||
|
tst-qsort \
|
||||||
|
tst-qsort2 \
|
||||||
|
tst-qsort3 \
|
||||||
|
+ tst-qsort5 \
|
||||||
|
tst-quick_exit \
|
||||||
|
tst-rand48 \
|
||||||
|
tst-rand48-2 \
|
||||||
|
@@ -483,6 +484,7 @@ $(objpfx)tst-setcontext3.out: tst-setcontext3.sh $(objpfx)tst-setcontext3
|
||||||
|
$(common-objpfx)stdlib/; \
|
||||||
|
$(evaluate-test)
|
||||||
|
|
||||||
|
+$(objpfx)tst-qsort5: $(libm)
|
||||||
|
$(objpfx)tst-getenv-signal: $(shared-thread-library)
|
||||||
|
$(objpfx)tst-getenv-thread: $(shared-thread-library)
|
||||||
|
$(objpfx)tst-getenv-unsetenv: $(shared-thread-library)
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index b207c12d2f0a38cc..df8d0012c759e509 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -390,14 +390,23 @@ __qsort_r (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
{
|
||||||
|
if ((size_t) (hi - left_ptr) <= max_thresh)
|
||||||
|
/* Ignore both small partitions. */
|
||||||
|
- top = pop (top, &lo, &hi, &depth);
|
||||||
|
+ {
|
||||||
|
+ top = pop (top, &lo, &hi, &depth);
|
||||||
|
+ --depth;
|
||||||
|
+ }
|
||||||
|
else
|
||||||
|
- /* Ignore small left partition. */
|
||||||
|
- lo = left_ptr;
|
||||||
|
+ {
|
||||||
|
+ /* Ignore small left partition. */
|
||||||
|
+ lo = left_ptr;
|
||||||
|
+ --depth;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
else if ((size_t) (hi - left_ptr) <= max_thresh)
|
||||||
|
/* Ignore small right partition. */
|
||||||
|
- hi = right_ptr;
|
||||||
|
+ {
|
||||||
|
+ hi = right_ptr;
|
||||||
|
+ --depth;
|
||||||
|
+ }
|
||||||
|
else if ((right_ptr - lo) > (hi - left_ptr))
|
||||||
|
{
|
||||||
|
/* Push larger left partition indices. */
|
||||||
|
diff --git a/stdlib/tst-qsort5.c b/stdlib/tst-qsort5.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..d3a88c30f8ffb135
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdlib/tst-qsort5.c
|
||||||
|
@@ -0,0 +1,171 @@
|
||||||
|
+/* Adversarial test for qsort_r.
|
||||||
|
+ Copyright (C) 2023 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
|
||||||
|
+ <http://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+/* The approach follows Douglas McIlroy, A Killer Adversary for
|
||||||
|
+ Quicksort. Software—Practice and Experience 29 (1999) 341-344.
|
||||||
|
+ Downloaded <http://www.cs.dartmouth.edu/~doug/mdmspe.pdf>
|
||||||
|
+ (2023-11-17). */
|
||||||
|
+
|
||||||
|
+#include <math.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/support.h>
|
||||||
|
+
|
||||||
|
+struct context
|
||||||
|
+{
|
||||||
|
+ /* Called the gas value in the paper. This value is larger than all
|
||||||
|
+ other values (length minus one will do), so comparison with any
|
||||||
|
+ decided value has a known result. */
|
||||||
|
+ int undecided_value;
|
||||||
|
+
|
||||||
|
+ /* If comparing undecided values, one of them as to be assigned a
|
||||||
|
+ value to ensure consistency with future comparisons. This is the
|
||||||
|
+ value that will be used. Starts out at zero. */
|
||||||
|
+ int next_decided;
|
||||||
|
+
|
||||||
|
+ /* Used to trick pivot selection. Deciding the value for the last
|
||||||
|
+ seen undcided value in a decided/undecided comparison happens
|
||||||
|
+ to trick the many qsort implementations. */
|
||||||
|
+ int last_undecided_index;
|
||||||
|
+
|
||||||
|
+ /* This array contains the actually asigned values. The call to
|
||||||
|
+ qsort_r sorts a different array that contains indices into this
|
||||||
|
+ array. */
|
||||||
|
+ int *decided_values;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+compare_opponent (const void *l1, const void *r1, void *ctx1)
|
||||||
|
+{
|
||||||
|
+ const int *l = l1;
|
||||||
|
+ const int *r = r1;
|
||||||
|
+ struct context *ctx = ctx1;
|
||||||
|
+ int rvalue = ctx->decided_values[*r];
|
||||||
|
+ int lvalue = ctx->decided_values[*l];
|
||||||
|
+
|
||||||
|
+ if (lvalue == ctx->undecided_value)
|
||||||
|
+ {
|
||||||
|
+ if (rvalue == ctx->undecided_value)
|
||||||
|
+ {
|
||||||
|
+ /* Both values are undecided. In this case, make a decision
|
||||||
|
+ for the last-used undecided value. This is tweak is very
|
||||||
|
+ specific to quicksort. */
|
||||||
|
+ if (*l == ctx->last_undecided_index)
|
||||||
|
+ {
|
||||||
|
+ ctx->decided_values[*l] = ctx->next_decided;
|
||||||
|
+ ++ctx->next_decided;
|
||||||
|
+ /* The undecided value or *r is greater. */
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ ctx->decided_values[*r] = ctx->next_decided;
|
||||||
|
+ ++ctx->next_decided;
|
||||||
|
+ /* The undecided value for *l is greater. */
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ ctx->last_undecided_index = *l;
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ /* *l is a decided value. */
|
||||||
|
+ if (rvalue == ctx->undecided_value)
|
||||||
|
+ {
|
||||||
|
+ ctx->last_undecided_index = *r;
|
||||||
|
+ /* The undecided value for *r is greater. */
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ return lvalue - rvalue;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Return a pointer to the adversarial permutation of length N. */
|
||||||
|
+static int *
|
||||||
|
+create_permutation (size_t n)
|
||||||
|
+{
|
||||||
|
+ struct context ctx =
|
||||||
|
+ {
|
||||||
|
+ .undecided_value = n - 1, /* Larger than all other values. */
|
||||||
|
+ .decided_values = xcalloc (n, sizeof (int)),
|
||||||
|
+ };
|
||||||
|
+ for (size_t i = 0; i < n; ++i)
|
||||||
|
+ ctx.decided_values[i] = ctx.undecided_value;
|
||||||
|
+ int *scratch = xcalloc (n, sizeof (int));
|
||||||
|
+ for (size_t i = 0; i < n; ++i)
|
||||||
|
+ scratch[i] = i;
|
||||||
|
+ qsort_r (scratch, n, sizeof (*scratch), compare_opponent, &ctx);
|
||||||
|
+ free (scratch);
|
||||||
|
+ return ctx.decided_values;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Callback function for qsort which counts the number of invocations
|
||||||
|
+ in *CLOSURE. */
|
||||||
|
+static int
|
||||||
|
+compare_counter (const void *l1, const void *r1, void *closure)
|
||||||
|
+{
|
||||||
|
+ const int *l = l1;
|
||||||
|
+ const int *r = r1;
|
||||||
|
+ unsigned long long int *counter = closure;
|
||||||
|
+ ++*counter;
|
||||||
|
+ return *l - *r;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Count the comparisons required for an adversarial permutation of
|
||||||
|
+ length N. */
|
||||||
|
+static unsigned long long int
|
||||||
|
+count_comparisons (size_t n)
|
||||||
|
+{
|
||||||
|
+ int *array = create_permutation (n);
|
||||||
|
+ unsigned long long int counter = 0;
|
||||||
|
+ qsort_r (array, n, sizeof (*array), compare_counter, &counter);
|
||||||
|
+ free (array);
|
||||||
|
+ return counter;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Check the scaling factor for one adversarial permutation of length
|
||||||
|
+ N, and report some statistics. */
|
||||||
|
+static void
|
||||||
|
+check_one_n (size_t n)
|
||||||
|
+{
|
||||||
|
+ unsigned long long int count = count_comparisons (n);
|
||||||
|
+ double factor = count / (n * log (count));
|
||||||
|
+ printf ("info: length %zu: %llu comparisons ~ %f * n * log (n)\n",
|
||||||
|
+ n, count, factor);
|
||||||
|
+ /* This is an arbitrary factor which is true for the current
|
||||||
|
+ implementation across a wide range of sizes. */
|
||||||
|
+ TEST_VERIFY (factor <= 4.5);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ check_one_n (100);
|
||||||
|
+ check_one_n (1000);
|
||||||
|
+ for (int i = 1; i <= 15; ++i)
|
||||||
|
+ check_one_n (i * 10 * 1000);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
105
SOURCES/glibc-RHEL-24168-14.patch
Normal file
105
SOURCES/glibc-RHEL-24168-14.patch
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
commit b9390ba93676c4b1e87e218af5e7e4bb596312ac
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Mon Dec 4 06:35:56 2023 +0100
|
||||||
|
|
||||||
|
stdlib: Fix array bounds protection in insertion sort phase of qsort
|
||||||
|
|
||||||
|
The previous check did not do anything because tmp_ptr already
|
||||||
|
points before run_ptr due to the way it is initialized.
|
||||||
|
|
||||||
|
Fixes commit e4d8117b82065dc72e8df80097360e7c05a349b9
|
||||||
|
("stdlib: Avoid another self-comparison in qsort").
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||||||
|
index a1a511da37f0c18e..82d9d909890853b7 100644
|
||||||
|
--- a/stdlib/Makefile
|
||||||
|
+++ b/stdlib/Makefile
|
||||||
|
@@ -213,6 +213,7 @@ tests := \
|
||||||
|
tst-qsort2 \
|
||||||
|
tst-qsort3 \
|
||||||
|
tst-qsort5 \
|
||||||
|
+ tst-qsort6 \
|
||||||
|
tst-quick_exit \
|
||||||
|
tst-rand48 \
|
||||||
|
tst-rand48-2 \
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index df8d0012c759e509..3d5405705862ddf0 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -239,7 +239,7 @@ insertion_sort_qsort_partitions (void *const pbase, size_t total_elems,
|
||||||
|
while ((run_ptr += size) <= end_ptr)
|
||||||
|
{
|
||||||
|
tmp_ptr = run_ptr - size;
|
||||||
|
- while (run_ptr != tmp_ptr && cmp (run_ptr, tmp_ptr, arg) < 0)
|
||||||
|
+ while (tmp_ptr != base_ptr && cmp (run_ptr, tmp_ptr, arg) < 0)
|
||||||
|
tmp_ptr -= size;
|
||||||
|
|
||||||
|
tmp_ptr += size;
|
||||||
|
diff --git a/stdlib/tst-qsort6.c b/stdlib/tst-qsort6.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..8ec0a6b633bc8398
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdlib/tst-qsort6.c
|
||||||
|
@@ -0,0 +1,60 @@
|
||||||
|
+/* Test qsort with invalid comparison functions.
|
||||||
|
+ Copyright (C) 2023 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
|
||||||
|
+ <http://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <array_length.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+
|
||||||
|
+/* Invalid comparison function that always returns -1. */
|
||||||
|
+static int
|
||||||
|
+invalid_compare_1 (const void *a1, const void *b1)
|
||||||
|
+{
|
||||||
|
+ const int *a = a1;
|
||||||
|
+ const int *b = b1;
|
||||||
|
+ /* Check that the marker value matches, which means that we are
|
||||||
|
+ likely within the array. */
|
||||||
|
+ TEST_COMPARE (*a, 842523635);
|
||||||
|
+ TEST_COMPARE (*b, 842523635);
|
||||||
|
+ TEST_VERIFY_EXIT (*a == 842523635);
|
||||||
|
+ TEST_VERIFY_EXIT (*b == 842523635);
|
||||||
|
+ return -1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Invalid comparison function that always returns 1. */
|
||||||
|
+static int
|
||||||
|
+invalid_compare_2 (const void *a1, const void *b1)
|
||||||
|
+{
|
||||||
|
+ const int *a = a1;
|
||||||
|
+ const int *b = b1;
|
||||||
|
+ TEST_COMPARE (*a, 842523635);
|
||||||
|
+ TEST_COMPARE (*b, 842523635);
|
||||||
|
+ TEST_VERIFY_EXIT (*a == 842523635);
|
||||||
|
+ TEST_VERIFY_EXIT (*b == 842523635);
|
||||||
|
+ return 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ int array[] = {842523635, 842523635, 842523635, 842523635, 842523635};
|
||||||
|
+ qsort (array, array_length (array), sizeof (array[0]), invalid_compare_1);
|
||||||
|
+ qsort (array, array_length (array), sizeof (array[0]), invalid_compare_2);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
876
SOURCES/glibc-RHEL-24168-15.patch
Normal file
876
SOURCES/glibc-RHEL-24168-15.patch
Normal file
@ -0,0 +1,876 @@
|
|||||||
|
commit 709fbd3ec3595f2d1076b4fec09a739327459288
|
||||||
|
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
Date: Mon Jan 15 11:07:21 2024 -0300
|
||||||
|
|
||||||
|
stdlib: Reinstate stable mergesort implementation on qsort
|
||||||
|
|
||||||
|
The mergesort removal from qsort implementation (commit 03bf8357e8)
|
||||||
|
had the side-effect of making sorting nonstable. Although neither
|
||||||
|
POSIX nor C standard specify that qsort should be stable, it seems
|
||||||
|
that it has become an instance of Hyrum's law where multiple programs
|
||||||
|
expect it.
|
||||||
|
|
||||||
|
Also, the resulting introsort implementation is not faster than
|
||||||
|
the previous mergesort (which makes the change even less appealing).
|
||||||
|
|
||||||
|
This patch restores the previous mergesort implementation, with the
|
||||||
|
exception of machinery that checks the resulting allocation against
|
||||||
|
the _SC_PHYS_PAGES (it only adds complexity and the heuristic not
|
||||||
|
always make sense depending on the system configuration and load).
|
||||||
|
The alloca usage was replaced with a fixed-size buffer.
|
||||||
|
|
||||||
|
For the fallback mechanism, the implementation uses heapsort. It is
|
||||||
|
simpler than quicksort, and it does not suffer from adversarial
|
||||||
|
inputs. With memory overcommit, it should be rarely triggered.
|
||||||
|
|
||||||
|
The drawback is mergesort requires O(n) extra space, and since it is
|
||||||
|
allocated with malloc the function is AS-signal-unsafe. It should be
|
||||||
|
feasible to change it to use mmap, although I am not sure how urgent
|
||||||
|
it is. The heapsort is also nonstable, so programs that require a
|
||||||
|
stable sort would still be subject to this latent issue.
|
||||||
|
|
||||||
|
The tst-qsort5 is removed since it will not create quicksort adversarial
|
||||||
|
inputs with the current qsort_r implementation.
|
||||||
|
|
||||||
|
Checked on x86_64-linux-gnu and aarch64-linux-gnu.
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
stdlib/tst-qsort5.c: Deletion had conflicts due to copyright update.
|
||||||
|
|
||||||
|
diff --git a/manual/argp.texi b/manual/argp.texi
|
||||||
|
index b77ad68285ecb732..0023441812d4e584 100644
|
||||||
|
--- a/manual/argp.texi
|
||||||
|
+++ b/manual/argp.texi
|
||||||
|
@@ -735,7 +735,7 @@ for options, bad phase of the moon, etc.
|
||||||
|
@c hol_set_group ok
|
||||||
|
@c hol_find_entry ok
|
||||||
|
@c hol_sort @mtslocale @acucorrupt
|
||||||
|
-@c qsort dup
|
||||||
|
+@c qsort dup @acucorrupt
|
||||||
|
@c hol_entry_qcmp @mtslocale
|
||||||
|
@c hol_entry_cmp @mtslocale
|
||||||
|
@c group_cmp ok
|
||||||
|
diff --git a/manual/locale.texi b/manual/locale.texi
|
||||||
|
index f6afa5dc44a2a016..1b3f97839bb5d068 100644
|
||||||
|
--- a/manual/locale.texi
|
||||||
|
+++ b/manual/locale.texi
|
||||||
|
@@ -253,7 +253,7 @@ The symbols in this section are defined in the header file @file{locale.h}.
|
||||||
|
@c calculate_head_size ok
|
||||||
|
@c __munmap ok
|
||||||
|
@c compute_hashval ok
|
||||||
|
-@c qsort dup
|
||||||
|
+@c qsort dup @acucorrupt
|
||||||
|
@c rangecmp ok
|
||||||
|
@c malloc @ascuheap @acsmem
|
||||||
|
@c strdup @ascuheap @acsmem
|
||||||
|
diff --git a/manual/search.texi b/manual/search.texi
|
||||||
|
index a550858478f7fc83..ffaadc46f51b18f9 100644
|
||||||
|
--- a/manual/search.texi
|
||||||
|
+++ b/manual/search.texi
|
||||||
|
@@ -159,7 +159,7 @@ To sort an array using an arbitrary comparison function, use the
|
||||||
|
|
||||||
|
@deftypefun void qsort (void *@var{array}, size_t @var{count}, size_t @var{size}, comparison_fn_t @var{compare})
|
||||||
|
@standards{ISO, stdlib.h}
|
||||||
|
-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
|
||||||
|
+@safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}}
|
||||||
|
The @code{qsort} function sorts the array @var{array}. The array
|
||||||
|
contains @var{count} elements, each of which is of size @var{size}.
|
||||||
|
|
||||||
|
@@ -199,8 +199,9 @@ Functions}):
|
||||||
|
The @code{qsort} function derives its name from the fact that it was
|
||||||
|
originally implemented using the ``quick sort'' algorithm.
|
||||||
|
|
||||||
|
-The implementation of @code{qsort} in this library is an in-place sort
|
||||||
|
-and uses a constant extra space (allocated on the stack).
|
||||||
|
+The implementation of @code{qsort} attempts to allocate auxiliary storage
|
||||||
|
+and use the merge sort algorithm, without violating C standard requirement
|
||||||
|
+that arguments passed to the comparison function point within the array.
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
@node Search/Sort Example
|
||||||
|
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||||||
|
index 82d9d909890853b7..a9d91a57c08ac506 100644
|
||||||
|
--- a/stdlib/Makefile
|
||||||
|
+++ b/stdlib/Makefile
|
||||||
|
@@ -212,7 +212,6 @@ tests := \
|
||||||
|
tst-qsort \
|
||||||
|
tst-qsort2 \
|
||||||
|
tst-qsort3 \
|
||||||
|
- tst-qsort5 \
|
||||||
|
tst-qsort6 \
|
||||||
|
tst-quick_exit \
|
||||||
|
tst-rand48 \
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index 3d5405705862ddf0..b95889047ba31193 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -20,6 +20,7 @@
|
||||||
|
Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
|
||||||
|
Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */
|
||||||
|
|
||||||
|
+#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <memswap.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
@@ -33,9 +34,13 @@ enum swap_type_t
|
||||||
|
{
|
||||||
|
SWAP_WORDS_64,
|
||||||
|
SWAP_WORDS_32,
|
||||||
|
+ SWAP_VOID_ARG,
|
||||||
|
SWAP_BYTES
|
||||||
|
};
|
||||||
|
|
||||||
|
+typedef uint32_t __attribute__ ((__may_alias__)) u32_alias_t;
|
||||||
|
+typedef uint64_t __attribute__ ((__may_alias__)) u64_alias_t;
|
||||||
|
+
|
||||||
|
/* If this function returns true, elements can be safely copied using word
|
||||||
|
loads and stores. Otherwise, it might not be safe. BASE (as an integer)
|
||||||
|
must be a multiple of the word alignment. SIZE must be a multiple of
|
||||||
|
@@ -52,7 +57,6 @@ is_aligned (const void *base, size_t size, size_t wordsize)
|
||||||
|
static inline void
|
||||||
|
swap_words_64 (void * restrict a, void * restrict b, size_t n)
|
||||||
|
{
|
||||||
|
- typedef uint64_t __attribute__ ((__may_alias__)) u64_alias_t;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
n -= 8;
|
||||||
|
@@ -65,7 +69,6 @@ swap_words_64 (void * restrict a, void * restrict b, size_t n)
|
||||||
|
static inline void
|
||||||
|
swap_words_32 (void * restrict a, void * restrict b, size_t n)
|
||||||
|
{
|
||||||
|
- typedef uint32_t __attribute__ ((__may_alias__)) u32_alias_t;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
n -= 4;
|
||||||
|
@@ -89,43 +92,6 @@ do_swap (void * restrict a, void * restrict b, size_t size,
|
||||||
|
__memswap (a, b, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* Discontinue quicksort algorithm when partition gets below this size.
|
||||||
|
- This particular magic number was chosen to work best on a Sun 4/260. */
|
||||||
|
-#define MAX_THRESH 4
|
||||||
|
-
|
||||||
|
-/* Stack node declarations used to store unfulfilled partition obligations. */
|
||||||
|
-typedef struct
|
||||||
|
- {
|
||||||
|
- char *lo;
|
||||||
|
- char *hi;
|
||||||
|
- size_t depth;
|
||||||
|
- } stack_node;
|
||||||
|
-
|
||||||
|
-/* The stack needs log (total_elements) entries (we could even subtract
|
||||||
|
- log(MAX_THRESH)). Since total_elements has type size_t, we get as
|
||||||
|
- upper bound for log (total_elements):
|
||||||
|
- bits per byte (CHAR_BIT) * sizeof(size_t). */
|
||||||
|
-enum { STACK_SIZE = CHAR_BIT * sizeof (size_t) };
|
||||||
|
-
|
||||||
|
-static inline stack_node *
|
||||||
|
-push (stack_node *top, char *lo, char *hi, size_t depth)
|
||||||
|
-{
|
||||||
|
- top->lo = lo;
|
||||||
|
- top->hi = hi;
|
||||||
|
- top->depth = depth;
|
||||||
|
- return ++top;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-static inline stack_node *
|
||||||
|
-pop (stack_node *top, char **lo, char **hi, size_t *depth)
|
||||||
|
-{
|
||||||
|
- --top;
|
||||||
|
- *lo = top->lo;
|
||||||
|
- *hi = top->hi;
|
||||||
|
- *depth = top->depth;
|
||||||
|
- return top;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
/* Establish the heap condition at index K, that is, the key at K will
|
||||||
|
not be less than either of its children, at 2 * K + 1 and 2 * K + 2
|
||||||
|
(if they exist). N is the last valid index. */
|
||||||
|
@@ -173,21 +139,35 @@ heapify (void *base, size_t size, size_t n, enum swap_type_t swap_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* A non-recursive heapsort, used on introsort implementation as a
|
||||||
|
- fallback routine with worst-case performance of O(nlog n) and
|
||||||
|
- worst-case space complexity of O(1). It sorts the array starting
|
||||||
|
- at BASE and ending at END (inclusive), with each element of SIZE
|
||||||
|
- bytes. The SWAP_TYPE is the callback function used to swap
|
||||||
|
- elements, and CMP is the function used to compare elements. */
|
||||||
|
+static enum swap_type_t
|
||||||
|
+get_swap_type (void *const pbase, size_t size)
|
||||||
|
+{
|
||||||
|
+ if ((size & (sizeof (uint32_t) - 1)) == 0
|
||||||
|
+ && ((uintptr_t) pbase) % __alignof__ (uint32_t) == 0)
|
||||||
|
+ {
|
||||||
|
+ if (size == sizeof (uint32_t))
|
||||||
|
+ return SWAP_WORDS_32;
|
||||||
|
+ else if (size == sizeof (uint64_t)
|
||||||
|
+ && ((uintptr_t) pbase) % __alignof__ (uint64_t) == 0)
|
||||||
|
+ return SWAP_WORDS_64;
|
||||||
|
+ }
|
||||||
|
+ return SWAP_BYTES;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+/* A non-recursive heapsort with worst-case performance of O(nlog n) and
|
||||||
|
+ worst-case space complexity of O(1). It sorts the array starting at
|
||||||
|
+ BASE with n + 1 elements of SIZE bytes. The SWAP_TYPE is the callback
|
||||||
|
+ function used to swap elements, and CMP is the function used to compare
|
||||||
|
+ elements. */
|
||||||
|
static void
|
||||||
|
-heapsort_r (void *base, void *end, size_t size, enum swap_type_t swap_type,
|
||||||
|
- __compar_d_fn_t cmp, void *arg)
|
||||||
|
+heapsort_r (void *base, size_t n, size_t size, __compar_d_fn_t cmp, void *arg)
|
||||||
|
{
|
||||||
|
- size_t n = ((uintptr_t) end - (uintptr_t) base) / size;
|
||||||
|
if (n <= 1)
|
||||||
|
- /* Handled by insertion sort. */
|
||||||
|
return;
|
||||||
|
|
||||||
|
+ enum swap_type_t swap_type = get_swap_type (base, size);
|
||||||
|
+
|
||||||
|
/* Build the binary heap, largest value at the base[0]. */
|
||||||
|
heapify (base, size, n, swap_type, cmp, arg);
|
||||||
|
|
||||||
|
@@ -209,226 +189,226 @@ heapsort_r (void *base, void *end, size_t size, enum swap_type_t swap_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-static inline void
|
||||||
|
-insertion_sort_qsort_partitions (void *const pbase, size_t total_elems,
|
||||||
|
- size_t size, enum swap_type_t swap_type,
|
||||||
|
- __compar_d_fn_t cmp, void *arg)
|
||||||
|
+/* The maximum size in bytes required by mergesort that will be provided
|
||||||
|
+ through a buffer allocated in the stack. */
|
||||||
|
+#define QSORT_STACK_SIZE 1024
|
||||||
|
+
|
||||||
|
+/* Elements larger than this value will be sorted through indirect sorting
|
||||||
|
+ to minimize the need to memory swap calls. */
|
||||||
|
+#define INDIRECT_SORT_SIZE_THRES 32
|
||||||
|
+
|
||||||
|
+struct msort_param
|
||||||
|
{
|
||||||
|
- char *base_ptr = (char *) pbase;
|
||||||
|
- char *const end_ptr = &base_ptr[size * (total_elems - 1)];
|
||||||
|
- char *tmp_ptr = base_ptr;
|
||||||
|
-#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||||
|
- const size_t max_thresh = MAX_THRESH * size;
|
||||||
|
- char *thresh = min(end_ptr, base_ptr + max_thresh);
|
||||||
|
- char *run_ptr;
|
||||||
|
+ size_t s;
|
||||||
|
+ enum swap_type_t var;
|
||||||
|
+ __compar_d_fn_t cmp;
|
||||||
|
+ void *arg;
|
||||||
|
+ char *t;
|
||||||
|
+};
|
||||||
|
|
||||||
|
- /* Find smallest element in first threshold and place it at the
|
||||||
|
- array's beginning. This is the smallest array element,
|
||||||
|
- and the operation speeds up insertion sort's inner loop. */
|
||||||
|
+static void
|
||||||
|
+msort_with_tmp (const struct msort_param *p, void *b, size_t n)
|
||||||
|
+{
|
||||||
|
+ char *b1, *b2;
|
||||||
|
+ size_t n1, n2;
|
||||||
|
|
||||||
|
- for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
|
||||||
|
- if (cmp (run_ptr, tmp_ptr, arg) < 0)
|
||||||
|
- tmp_ptr = run_ptr;
|
||||||
|
+ if (n <= 1)
|
||||||
|
+ return;
|
||||||
|
|
||||||
|
- if (tmp_ptr != base_ptr)
|
||||||
|
- do_swap (tmp_ptr, base_ptr, size, swap_type);
|
||||||
|
+ n1 = n / 2;
|
||||||
|
+ n2 = n - n1;
|
||||||
|
+ b1 = b;
|
||||||
|
+ b2 = (char *) b + (n1 * p->s);
|
||||||
|
|
||||||
|
- /* Insertion sort, running from left-hand-side up to right-hand-side. */
|
||||||
|
+ msort_with_tmp (p, b1, n1);
|
||||||
|
+ msort_with_tmp (p, b2, n2);
|
||||||
|
|
||||||
|
- run_ptr = base_ptr + size;
|
||||||
|
- while ((run_ptr += size) <= end_ptr)
|
||||||
|
+ char *tmp = p->t;
|
||||||
|
+ const size_t s = p->s;
|
||||||
|
+ __compar_d_fn_t cmp = p->cmp;
|
||||||
|
+ void *arg = p->arg;
|
||||||
|
+ switch (p->var)
|
||||||
|
{
|
||||||
|
- tmp_ptr = run_ptr - size;
|
||||||
|
- while (tmp_ptr != base_ptr && cmp (run_ptr, tmp_ptr, arg) < 0)
|
||||||
|
- tmp_ptr -= size;
|
||||||
|
-
|
||||||
|
- tmp_ptr += size;
|
||||||
|
- if (tmp_ptr != run_ptr)
|
||||||
|
- {
|
||||||
|
- char *trav;
|
||||||
|
-
|
||||||
|
- trav = run_ptr + size;
|
||||||
|
- while (--trav >= run_ptr)
|
||||||
|
- {
|
||||||
|
- char c = *trav;
|
||||||
|
- char *hi, *lo;
|
||||||
|
-
|
||||||
|
- for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
|
||||||
|
- *hi = *lo;
|
||||||
|
- *hi = c;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
+ case SWAP_WORDS_32:
|
||||||
|
+ while (n1 > 0 && n2 > 0)
|
||||||
|
+ {
|
||||||
|
+ if (cmp (b1, b2, arg) <= 0)
|
||||||
|
+ {
|
||||||
|
+ *(u32_alias_t *) tmp = *(u32_alias_t *) b1;
|
||||||
|
+ b1 += sizeof (u32_alias_t);
|
||||||
|
+ --n1;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ *(u32_alias_t *) tmp = *(u32_alias_t *) b2;
|
||||||
|
+ b2 += sizeof (u32_alias_t);
|
||||||
|
+ --n2;
|
||||||
|
+ }
|
||||||
|
+ tmp += sizeof (u32_alias_t);
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ case SWAP_WORDS_64:
|
||||||
|
+ while (n1 > 0 && n2 > 0)
|
||||||
|
+ {
|
||||||
|
+ if (cmp (b1, b2, arg) <= 0)
|
||||||
|
+ {
|
||||||
|
+ *(u64_alias_t *) tmp = *(u64_alias_t *) b1;
|
||||||
|
+ b1 += sizeof (u64_alias_t);
|
||||||
|
+ --n1;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ *(u64_alias_t *) tmp = *(u64_alias_t *) b2;
|
||||||
|
+ b2 += sizeof (u64_alias_t);
|
||||||
|
+ --n2;
|
||||||
|
+ }
|
||||||
|
+ tmp += sizeof (u64_alias_t);
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ case SWAP_VOID_ARG:
|
||||||
|
+ while (n1 > 0 && n2 > 0)
|
||||||
|
+ {
|
||||||
|
+ if ((*cmp) (*(const void **) b1, *(const void **) b2, arg) <= 0)
|
||||||
|
+ {
|
||||||
|
+ *(void **) tmp = *(void **) b1;
|
||||||
|
+ b1 += sizeof (void *);
|
||||||
|
+ --n1;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ *(void **) tmp = *(void **) b2;
|
||||||
|
+ b2 += sizeof (void *);
|
||||||
|
+ --n2;
|
||||||
|
+ }
|
||||||
|
+ tmp += sizeof (void *);
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ while (n1 > 0 && n2 > 0)
|
||||||
|
+ {
|
||||||
|
+ if (cmp (b1, b2, arg) <= 0)
|
||||||
|
+ {
|
||||||
|
+ tmp = (char *) __mempcpy (tmp, b1, s);
|
||||||
|
+ b1 += s;
|
||||||
|
+ --n1;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ tmp = (char *) __mempcpy (tmp, b2, s);
|
||||||
|
+ b2 += s;
|
||||||
|
+ --n2;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/* Order size using quicksort. This implementation incorporates
|
||||||
|
- four optimizations discussed in Sedgewick:
|
||||||
|
|
||||||
|
- 1. Non-recursive, using an explicit stack of pointer that store the
|
||||||
|
- next array partition to sort. To save time, this maximum amount
|
||||||
|
- of space required to store an array of SIZE_MAX is allocated on the
|
||||||
|
- stack. Assuming a 32-bit (64 bit) integer for size_t, this needs
|
||||||
|
- only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
|
||||||
|
- Pretty cheap, actually.
|
||||||
|
-
|
||||||
|
- 2. Chose the pivot element using a median-of-three decision tree.
|
||||||
|
- This reduces the probability of selecting a bad pivot value and
|
||||||
|
- eliminates certain extraneous comparisons.
|
||||||
|
+ if (n1 > 0)
|
||||||
|
+ memcpy (tmp, b1, n1 * s);
|
||||||
|
+ memcpy (b, p->t, (n - n2) * s);
|
||||||
|
+}
|
||||||
|
|
||||||
|
- 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
|
||||||
|
- insertion sort to order the MAX_THRESH items within each partition.
|
||||||
|
- This is a big win, since insertion sort is faster for small, mostly
|
||||||
|
- sorted array segments.
|
||||||
|
+static void
|
||||||
|
+__attribute_used__
|
||||||
|
+indirect_msort_with_tmp (const struct msort_param *p, void *b, size_t n,
|
||||||
|
+ size_t s)
|
||||||
|
+{
|
||||||
|
+ /* Indirect sorting. */
|
||||||
|
+ char *ip = (char *) b;
|
||||||
|
+ void **tp = (void **) (p->t + n * sizeof (void *));
|
||||||
|
+ void **t = tp;
|
||||||
|
+ void *tmp_storage = (void *) (tp + n);
|
||||||
|
|
||||||
|
- 4. The larger of the two sub-partitions is always pushed onto the
|
||||||
|
- stack first, with the algorithm then concentrating on the
|
||||||
|
- smaller partition. This *guarantees* no more than log (total_elems)
|
||||||
|
- stack size is needed (actually O(1) in this case)! */
|
||||||
|
+ while ((void *) t < tmp_storage)
|
||||||
|
+ {
|
||||||
|
+ *t++ = ip;
|
||||||
|
+ ip += s;
|
||||||
|
+ }
|
||||||
|
+ msort_with_tmp (p, p->t + n * sizeof (void *), n);
|
||||||
|
+
|
||||||
|
+ /* tp[0] .. tp[n - 1] is now sorted, copy around entries of
|
||||||
|
+ the original array. Knuth vol. 3 (2nd ed.) exercise 5.2-10. */
|
||||||
|
+ char *kp;
|
||||||
|
+ size_t i;
|
||||||
|
+ for (i = 0, ip = (char *) b; i < n; i++, ip += s)
|
||||||
|
+ if ((kp = tp[i]) != ip)
|
||||||
|
+ {
|
||||||
|
+ size_t j = i;
|
||||||
|
+ char *jp = ip;
|
||||||
|
+ memcpy (tmp_storage, ip, s);
|
||||||
|
+
|
||||||
|
+ do
|
||||||
|
+ {
|
||||||
|
+ size_t k = (kp - (char *) b) / s;
|
||||||
|
+ tp[j] = jp;
|
||||||
|
+ memcpy (jp, kp, s);
|
||||||
|
+ j = k;
|
||||||
|
+ jp = kp;
|
||||||
|
+ kp = tp[k];
|
||||||
|
+ }
|
||||||
|
+ while (kp != ip);
|
||||||
|
+
|
||||||
|
+ tp[j] = jp;
|
||||||
|
+ memcpy (jp, tmp_storage, s);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
|
||||||
|
void
|
||||||
|
__qsort_r (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
__compar_d_fn_t cmp, void *arg)
|
||||||
|
{
|
||||||
|
- char *base_ptr = (char *) pbase;
|
||||||
|
-
|
||||||
|
- const size_t max_thresh = MAX_THRESH * size;
|
||||||
|
-
|
||||||
|
if (total_elems <= 1)
|
||||||
|
- /* Avoid lossage with unsigned arithmetic below. */
|
||||||
|
return;
|
||||||
|
|
||||||
|
- enum swap_type_t swap_type;
|
||||||
|
- if (is_aligned (pbase, size, 8))
|
||||||
|
- swap_type = SWAP_WORDS_64;
|
||||||
|
- else if (is_aligned (pbase, size, 4))
|
||||||
|
- swap_type = SWAP_WORDS_32;
|
||||||
|
- else
|
||||||
|
- swap_type = SWAP_BYTES;
|
||||||
|
+ /* Align to the maximum size used by the swap optimization. */
|
||||||
|
+ _Alignas (uint64_t) char tmp[QSORT_STACK_SIZE];
|
||||||
|
+ size_t total_size = total_elems * size;
|
||||||
|
+ char *buf;
|
||||||
|
|
||||||
|
- /* Maximum depth before quicksort switches to heapsort. */
|
||||||
|
- size_t depth = 2 * (sizeof (size_t) * CHAR_BIT - 1
|
||||||
|
- - __builtin_clzl (total_elems));
|
||||||
|
+ if (size > INDIRECT_SORT_SIZE_THRES)
|
||||||
|
+ total_size = 2 * total_elems * sizeof (void *) + size;
|
||||||
|
|
||||||
|
- if (total_elems > MAX_THRESH)
|
||||||
|
+ if (total_size < sizeof buf)
|
||||||
|
+ buf = tmp;
|
||||||
|
+ else
|
||||||
|
{
|
||||||
|
- char *lo = base_ptr;
|
||||||
|
- char *hi = &lo[size * (total_elems - 1)];
|
||||||
|
- stack_node stack[STACK_SIZE];
|
||||||
|
- stack_node *top = push (stack, NULL, NULL, depth);
|
||||||
|
-
|
||||||
|
- while (stack < top)
|
||||||
|
- {
|
||||||
|
- if (depth == 0)
|
||||||
|
- {
|
||||||
|
- heapsort_r (lo, hi, size, swap_type, cmp, arg);
|
||||||
|
- top = pop (top, &lo, &hi, &depth);
|
||||||
|
- continue;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- char *left_ptr;
|
||||||
|
- char *right_ptr;
|
||||||
|
-
|
||||||
|
- /* Select median value from among LO, MID, and HI. Rearrange
|
||||||
|
- LO and HI so the three values are sorted. This lowers the
|
||||||
|
- probability of picking a pathological pivot value and
|
||||||
|
- skips a comparison for both the LEFT_PTR and RIGHT_PTR in
|
||||||
|
- the while loops. */
|
||||||
|
-
|
||||||
|
- char *mid = lo + size * ((hi - lo) / size >> 1);
|
||||||
|
-
|
||||||
|
- if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
|
||||||
|
- do_swap (mid, lo, size, swap_type);
|
||||||
|
- if ((*cmp) ((void *) hi, (void *) mid, arg) < 0)
|
||||||
|
- do_swap (mid, hi, size, swap_type);
|
||||||
|
- else
|
||||||
|
- goto jump_over;
|
||||||
|
- if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
|
||||||
|
- do_swap (mid, lo, size, swap_type);
|
||||||
|
- jump_over:;
|
||||||
|
-
|
||||||
|
- left_ptr = lo + size;
|
||||||
|
- right_ptr = hi - size;
|
||||||
|
-
|
||||||
|
- /* Here's the famous ``collapse the walls'' section of quicksort.
|
||||||
|
- Gotta like those tight inner loops! They are the main reason
|
||||||
|
- that this algorithm runs much faster than others. */
|
||||||
|
- do
|
||||||
|
- {
|
||||||
|
- while (left_ptr != mid
|
||||||
|
- && (*cmp) ((void *) left_ptr, (void *) mid, arg) < 0)
|
||||||
|
- left_ptr += size;
|
||||||
|
-
|
||||||
|
- while (right_ptr != mid
|
||||||
|
- && (*cmp) ((void *) mid, (void *) right_ptr, arg) < 0)
|
||||||
|
- right_ptr -= size;
|
||||||
|
-
|
||||||
|
- if (left_ptr < right_ptr)
|
||||||
|
- {
|
||||||
|
- do_swap (left_ptr, right_ptr, size, swap_type);
|
||||||
|
- if (mid == left_ptr)
|
||||||
|
- mid = right_ptr;
|
||||||
|
- else if (mid == right_ptr)
|
||||||
|
- mid = left_ptr;
|
||||||
|
- left_ptr += size;
|
||||||
|
- right_ptr -= size;
|
||||||
|
- }
|
||||||
|
- else if (left_ptr == right_ptr)
|
||||||
|
- {
|
||||||
|
- left_ptr += size;
|
||||||
|
- right_ptr -= size;
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- while (left_ptr <= right_ptr);
|
||||||
|
-
|
||||||
|
- /* Set up pointers for next iteration. First determine whether
|
||||||
|
- left and right partitions are below the threshold size. If so,
|
||||||
|
- ignore one or both. Otherwise, push the larger partition's
|
||||||
|
- bounds on the stack and continue sorting the smaller one. */
|
||||||
|
-
|
||||||
|
- if ((size_t) (right_ptr - lo) <= max_thresh)
|
||||||
|
- {
|
||||||
|
- if ((size_t) (hi - left_ptr) <= max_thresh)
|
||||||
|
- /* Ignore both small partitions. */
|
||||||
|
- {
|
||||||
|
- top = pop (top, &lo, &hi, &depth);
|
||||||
|
- --depth;
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- /* Ignore small left partition. */
|
||||||
|
- lo = left_ptr;
|
||||||
|
- --depth;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- else if ((size_t) (hi - left_ptr) <= max_thresh)
|
||||||
|
- /* Ignore small right partition. */
|
||||||
|
- {
|
||||||
|
- hi = right_ptr;
|
||||||
|
- --depth;
|
||||||
|
- }
|
||||||
|
- else if ((right_ptr - lo) > (hi - left_ptr))
|
||||||
|
- {
|
||||||
|
- /* Push larger left partition indices. */
|
||||||
|
- top = push (top, lo, right_ptr, depth - 1);
|
||||||
|
- lo = left_ptr;
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- /* Push larger right partition indices. */
|
||||||
|
- top = push (top, left_ptr, hi, depth - 1);
|
||||||
|
- hi = right_ptr;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
+ int save = errno;
|
||||||
|
+ buf = malloc (total_size);
|
||||||
|
+ __set_errno (save);
|
||||||
|
+ if (buf == NULL)
|
||||||
|
+ {
|
||||||
|
+ /* Fallback to heapsort in case of memory failure. */
|
||||||
|
+ heapsort_r (pbase, total_elems - 1, size, cmp, arg);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (size > INDIRECT_SORT_SIZE_THRES)
|
||||||
|
+ {
|
||||||
|
+ const struct msort_param msort_param =
|
||||||
|
+ {
|
||||||
|
+ .s = sizeof (void *),
|
||||||
|
+ .cmp = cmp,
|
||||||
|
+ .arg = arg,
|
||||||
|
+ .var = SWAP_VOID_ARG,
|
||||||
|
+ .t = buf,
|
||||||
|
+ };
|
||||||
|
+ indirect_msort_with_tmp (&msort_param, pbase, total_elems, size);
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ const struct msort_param msort_param =
|
||||||
|
+ {
|
||||||
|
+ .s = size,
|
||||||
|
+ .cmp = cmp,
|
||||||
|
+ .arg = arg,
|
||||||
|
+ .var = get_swap_type (pbase, size),
|
||||||
|
+ .t = buf,
|
||||||
|
+ };
|
||||||
|
+ msort_with_tmp (&msort_param, pbase, total_elems);
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* Once the BASE_PTR array is partially sorted by quicksort the rest
|
||||||
|
- is completely sorted using insertion sort, since this is efficient
|
||||||
|
- for partitions below MAX_THRESH size. BASE_PTR points to the beginning
|
||||||
|
- of the array to sort, and END_PTR points at the very last element in
|
||||||
|
- the array (*not* one beyond it!). */
|
||||||
|
- insertion_sort_qsort_partitions (pbase, total_elems, size, swap_type, cmp,
|
||||||
|
- arg);
|
||||||
|
+ if (buf != tmp)
|
||||||
|
+ free (buf);
|
||||||
|
}
|
||||||
|
libc_hidden_def (__qsort_r)
|
||||||
|
weak_alias (__qsort_r, qsort_r)
|
||||||
|
diff --git a/stdlib/tst-qsort4.c b/stdlib/tst-qsort4.c
|
||||||
|
index a7abaa1a37461666..4cf373f22e28fade 100644
|
||||||
|
--- a/stdlib/tst-qsort4.c
|
||||||
|
+++ b/stdlib/tst-qsort4.c
|
||||||
|
@@ -30,35 +30,12 @@ cmp (const void *a1, const void *b1, void *closure)
|
||||||
|
return *a - *b;
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* Wrapper around heapsort_r that set ups the required variables. */
|
||||||
|
-static void
|
||||||
|
-heapsort_wrapper (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
- __compar_d_fn_t cmp, void *arg)
|
||||||
|
-{
|
||||||
|
- char *base_ptr = (char *) pbase;
|
||||||
|
- char *lo = base_ptr;
|
||||||
|
- char *hi = &lo[size * (total_elems - 1)];
|
||||||
|
-
|
||||||
|
- if (total_elems <= 1)
|
||||||
|
- /* Avoid lossage with unsigned arithmetic below. */
|
||||||
|
- return;
|
||||||
|
-
|
||||||
|
- enum swap_type_t swap_type;
|
||||||
|
- if (is_aligned (pbase, size, 8))
|
||||||
|
- swap_type = SWAP_WORDS_64;
|
||||||
|
- else if (is_aligned (pbase, size, 4))
|
||||||
|
- swap_type = SWAP_WORDS_32;
|
||||||
|
- else
|
||||||
|
- swap_type = SWAP_BYTES;
|
||||||
|
- heapsort_r (lo, hi, size, swap_type, cmp, arg);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static void
|
||||||
|
check_one_sort (signed char *array, int length)
|
||||||
|
{
|
||||||
|
signed char *copy = xmalloc (length);
|
||||||
|
memcpy (copy, array, length);
|
||||||
|
- heapsort_wrapper (copy, length, 1, cmp, NULL);
|
||||||
|
+ heapsort_r (copy, length - 1, 1, cmp, NULL);
|
||||||
|
|
||||||
|
/* Verify that the result is sorted. */
|
||||||
|
for (int i = 1; i < length; ++i)
|
||||||
|
diff --git a/stdlib/tst-qsort5.c b/stdlib/tst-qsort5.c
|
||||||
|
deleted file mode 100644
|
||||||
|
index d3a88c30f8ffb135..0000000000000000
|
||||||
|
--- a/stdlib/tst-qsort5.c
|
||||||
|
+++ /dev/null
|
||||||
|
@@ -1,171 +0,0 @@
|
||||||
|
-/* Adversarial test for qsort_r.
|
||||||
|
- Copyright (C) 2023 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
|
||||||
|
- <http://www.gnu.org/licenses/>. */
|
||||||
|
-
|
||||||
|
-/* The approach follows Douglas McIlroy, A Killer Adversary for
|
||||||
|
- Quicksort. Software—Practice and Experience 29 (1999) 341-344.
|
||||||
|
- Downloaded <http://www.cs.dartmouth.edu/~doug/mdmspe.pdf>
|
||||||
|
- (2023-11-17). */
|
||||||
|
-
|
||||||
|
-#include <math.h>
|
||||||
|
-#include <stdlib.h>
|
||||||
|
-#include <stdio.h>
|
||||||
|
-#include <support/check.h>
|
||||||
|
-#include <support/support.h>
|
||||||
|
-
|
||||||
|
-struct context
|
||||||
|
-{
|
||||||
|
- /* Called the gas value in the paper. This value is larger than all
|
||||||
|
- other values (length minus one will do), so comparison with any
|
||||||
|
- decided value has a known result. */
|
||||||
|
- int undecided_value;
|
||||||
|
-
|
||||||
|
- /* If comparing undecided values, one of them as to be assigned a
|
||||||
|
- value to ensure consistency with future comparisons. This is the
|
||||||
|
- value that will be used. Starts out at zero. */
|
||||||
|
- int next_decided;
|
||||||
|
-
|
||||||
|
- /* Used to trick pivot selection. Deciding the value for the last
|
||||||
|
- seen undcided value in a decided/undecided comparison happens
|
||||||
|
- to trick the many qsort implementations. */
|
||||||
|
- int last_undecided_index;
|
||||||
|
-
|
||||||
|
- /* This array contains the actually asigned values. The call to
|
||||||
|
- qsort_r sorts a different array that contains indices into this
|
||||||
|
- array. */
|
||||||
|
- int *decided_values;
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
-static int
|
||||||
|
-compare_opponent (const void *l1, const void *r1, void *ctx1)
|
||||||
|
-{
|
||||||
|
- const int *l = l1;
|
||||||
|
- const int *r = r1;
|
||||||
|
- struct context *ctx = ctx1;
|
||||||
|
- int rvalue = ctx->decided_values[*r];
|
||||||
|
- int lvalue = ctx->decided_values[*l];
|
||||||
|
-
|
||||||
|
- if (lvalue == ctx->undecided_value)
|
||||||
|
- {
|
||||||
|
- if (rvalue == ctx->undecided_value)
|
||||||
|
- {
|
||||||
|
- /* Both values are undecided. In this case, make a decision
|
||||||
|
- for the last-used undecided value. This is tweak is very
|
||||||
|
- specific to quicksort. */
|
||||||
|
- if (*l == ctx->last_undecided_index)
|
||||||
|
- {
|
||||||
|
- ctx->decided_values[*l] = ctx->next_decided;
|
||||||
|
- ++ctx->next_decided;
|
||||||
|
- /* The undecided value or *r is greater. */
|
||||||
|
- return -1;
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- ctx->decided_values[*r] = ctx->next_decided;
|
||||||
|
- ++ctx->next_decided;
|
||||||
|
- /* The undecided value for *l is greater. */
|
||||||
|
- return 1;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- ctx->last_undecided_index = *l;
|
||||||
|
- return 1;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- /* *l is a decided value. */
|
||||||
|
- if (rvalue == ctx->undecided_value)
|
||||||
|
- {
|
||||||
|
- ctx->last_undecided_index = *r;
|
||||||
|
- /* The undecided value for *r is greater. */
|
||||||
|
- return -1;
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- return lvalue - rvalue;
|
||||||
|
- }
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/* Return a pointer to the adversarial permutation of length N. */
|
||||||
|
-static int *
|
||||||
|
-create_permutation (size_t n)
|
||||||
|
-{
|
||||||
|
- struct context ctx =
|
||||||
|
- {
|
||||||
|
- .undecided_value = n - 1, /* Larger than all other values. */
|
||||||
|
- .decided_values = xcalloc (n, sizeof (int)),
|
||||||
|
- };
|
||||||
|
- for (size_t i = 0; i < n; ++i)
|
||||||
|
- ctx.decided_values[i] = ctx.undecided_value;
|
||||||
|
- int *scratch = xcalloc (n, sizeof (int));
|
||||||
|
- for (size_t i = 0; i < n; ++i)
|
||||||
|
- scratch[i] = i;
|
||||||
|
- qsort_r (scratch, n, sizeof (*scratch), compare_opponent, &ctx);
|
||||||
|
- free (scratch);
|
||||||
|
- return ctx.decided_values;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/* Callback function for qsort which counts the number of invocations
|
||||||
|
- in *CLOSURE. */
|
||||||
|
-static int
|
||||||
|
-compare_counter (const void *l1, const void *r1, void *closure)
|
||||||
|
-{
|
||||||
|
- const int *l = l1;
|
||||||
|
- const int *r = r1;
|
||||||
|
- unsigned long long int *counter = closure;
|
||||||
|
- ++*counter;
|
||||||
|
- return *l - *r;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/* Count the comparisons required for an adversarial permutation of
|
||||||
|
- length N. */
|
||||||
|
-static unsigned long long int
|
||||||
|
-count_comparisons (size_t n)
|
||||||
|
-{
|
||||||
|
- int *array = create_permutation (n);
|
||||||
|
- unsigned long long int counter = 0;
|
||||||
|
- qsort_r (array, n, sizeof (*array), compare_counter, &counter);
|
||||||
|
- free (array);
|
||||||
|
- return counter;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/* Check the scaling factor for one adversarial permutation of length
|
||||||
|
- N, and report some statistics. */
|
||||||
|
-static void
|
||||||
|
-check_one_n (size_t n)
|
||||||
|
-{
|
||||||
|
- unsigned long long int count = count_comparisons (n);
|
||||||
|
- double factor = count / (n * log (count));
|
||||||
|
- printf ("info: length %zu: %llu comparisons ~ %f * n * log (n)\n",
|
||||||
|
- n, count, factor);
|
||||||
|
- /* This is an arbitrary factor which is true for the current
|
||||||
|
- implementation across a wide range of sizes. */
|
||||||
|
- TEST_VERIFY (factor <= 4.5);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-static int
|
||||||
|
-do_test (void)
|
||||||
|
-{
|
||||||
|
- check_one_n (100);
|
||||||
|
- check_one_n (1000);
|
||||||
|
- for (int i = 1; i <= 15; ++i)
|
||||||
|
- check_one_n (i * 10 * 1000);
|
||||||
|
- return 0;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-#include <support/test-driver.c>
|
||||||
27
SOURCES/glibc-RHEL-24168-16.patch
Normal file
27
SOURCES/glibc-RHEL-24168-16.patch
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
commit 74d2731a5fb2676b64092bc25e7f193db1b17b2b
|
||||||
|
Author: Kuan-Wei Chiu <visitorckw@gmail.com>
|
||||||
|
Date: Tue Jan 16 10:16:56 2024 +0800
|
||||||
|
|
||||||
|
stdlib: Fix heapsort for cases with exactly two elements
|
||||||
|
|
||||||
|
When malloc fails to allocate a buffer and falls back to heapsort, the
|
||||||
|
current heapsort implementation does not perform sorting when there are
|
||||||
|
exactly two elements. Heapsort is now skipped only when there is
|
||||||
|
exactly one element.
|
||||||
|
|
||||||
|
Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index b95889047ba31193..7b6c7e1f79974157 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -163,7 +163,7 @@ get_swap_type (void *const pbase, size_t size)
|
||||||
|
static void
|
||||||
|
heapsort_r (void *base, size_t n, size_t size, __compar_d_fn_t cmp, void *arg)
|
||||||
|
{
|
||||||
|
- if (n <= 1)
|
||||||
|
+ if (n == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
enum swap_type_t swap_type = get_swap_type (base, size);
|
||||||
27
SOURCES/glibc-RHEL-24168-17.patch
Normal file
27
SOURCES/glibc-RHEL-24168-17.patch
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
commit 1bb28b7b4f01709b841c86850e1bb83b554feafe
|
||||||
|
Author: Kuan-Wei Chiu <visitorckw@gmail.com>
|
||||||
|
Date: Tue Jan 16 10:16:57 2024 +0800
|
||||||
|
|
||||||
|
stdlib: Verify heapsort for two-element cases
|
||||||
|
|
||||||
|
Adjust the testing approach to start from scenarios with only 2
|
||||||
|
elements, as insertion sort no longer handles such cases.
|
||||||
|
|
||||||
|
Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/stdlib/tst-qsort4.c b/stdlib/tst-qsort4.c
|
||||||
|
index 4cf373f22e28fade..7909793d9eb3edc7 100644
|
||||||
|
--- a/stdlib/tst-qsort4.c
|
||||||
|
+++ b/stdlib/tst-qsort4.c
|
||||||
|
@@ -96,9 +96,7 @@ do_test (void)
|
||||||
|
check_one_sort ((signed char[16]) {15, 3, 4, 2, 1, 0, 8, 7, 6, 5, 14,
|
||||||
|
13, 12, 11, 10, 9}, 16);
|
||||||
|
|
||||||
|
- /* Array lengths 2 and less are not handled by heapsort_r and
|
||||||
|
- deferred to insertion sort. */
|
||||||
|
- for (int i = 3; i <= 8; ++i)
|
||||||
|
+ for (int i = 2; i <= 8; ++i)
|
||||||
|
{
|
||||||
|
signed char *buf = xmalloc (i);
|
||||||
|
check_combinations (i, buf, 0);
|
||||||
32
SOURCES/glibc-RHEL-24168-18.patch
Normal file
32
SOURCES/glibc-RHEL-24168-18.patch
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
commit 31bd548650673e8b5ae1a31f1c596ff8305a5d4c
|
||||||
|
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
Date: Wed Jan 17 08:08:01 2024 -0300
|
||||||
|
|
||||||
|
stdlib: Remove unused is_aligned function from qsort.c
|
||||||
|
|
||||||
|
Checked on x86_64-linux-gnu.
|
||||||
|
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index 7b6c7e1f79974157..8db8a81d182dd1fc 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -41,19 +41,6 @@ enum swap_type_t
|
||||||
|
typedef uint32_t __attribute__ ((__may_alias__)) u32_alias_t;
|
||||||
|
typedef uint64_t __attribute__ ((__may_alias__)) u64_alias_t;
|
||||||
|
|
||||||
|
-/* If this function returns true, elements can be safely copied using word
|
||||||
|
- loads and stores. Otherwise, it might not be safe. BASE (as an integer)
|
||||||
|
- must be a multiple of the word alignment. SIZE must be a multiple of
|
||||||
|
- WORDSIZE. Since WORDSIZE must be a multiple of the word alignment, and
|
||||||
|
- WORDSIZE is a power of two on all supported platforms, this function for
|
||||||
|
- speed merely checks that BASE and SIZE are both multiples of the word
|
||||||
|
- size. */
|
||||||
|
-static inline bool
|
||||||
|
-is_aligned (const void *base, size_t size, size_t wordsize)
|
||||||
|
-{
|
||||||
|
- return (((uintptr_t) base | size) & (wordsize - 1)) == 0;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static inline void
|
||||||
|
swap_words_64 (void * restrict a, void * restrict b, size_t n)
|
||||||
|
{
|
||||||
51
SOURCES/glibc-RHEL-24168-19.patch
Normal file
51
SOURCES/glibc-RHEL-24168-19.patch
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
commit dfa3394a605c8f6f25e4f827789bc89eca1d206c
|
||||||
|
Author: Xi Ruoyao <xry111@xry111.site>
|
||||||
|
Date: Tue Jan 23 04:29:18 2024 +0800
|
||||||
|
|
||||||
|
qsort: Fix a typo causing unnecessary malloc/free (BZ 31276)
|
||||||
|
|
||||||
|
In qsort_r we allocate a buffer sized QSORT_STACK_SIZE (1024) on stack
|
||||||
|
and we intend to use it if all elements can fit into it. But there is a
|
||||||
|
typo:
|
||||||
|
|
||||||
|
if (total_size < sizeof buf)
|
||||||
|
buf = tmp;
|
||||||
|
else
|
||||||
|
/* allocate a buffer on heap and use it ... */
|
||||||
|
|
||||||
|
Here "buf" is a pointer, thus sizeof buf is just 4 or 8, instead of
|
||||||
|
1024. There is also a minor issue that we should use "<=" instead of
|
||||||
|
"<".
|
||||||
|
|
||||||
|
This bug is detected debugging some strange heap corruption running the
|
||||||
|
Ruby-3.3.0 test suite (on an experimental Linux From Scratch build using
|
||||||
|
Binutils-2.41.90 and Glibc trunk, and also Fedora Rawhide [1]). It
|
||||||
|
seems Ruby is doing some wild "optimization" by jumping into somewhere
|
||||||
|
in qsort_r instead of calling it normally, resulting in a double free of
|
||||||
|
buf if we allocate it on heap. The issue can be reproduced
|
||||||
|
deterministically with:
|
||||||
|
|
||||||
|
LD_PRELOAD=/usr/lib/libc_malloc_debug.so MALLOC_CHECK_=3 \
|
||||||
|
LD_LIBRARY_PATH=. ./ruby test/runner.rb test/ruby/test_enum.rb
|
||||||
|
|
||||||
|
in Ruby-3.3.0 tree after building it. This change would hide the issue
|
||||||
|
for Ruby, but Ruby is likely still buggy (if using this "optimization"
|
||||||
|
sorting larger arrays).
|
||||||
|
|
||||||
|
[1]:https://kojipkgs.fedoraproject.org/work/tasks/9729/111889729/build.log
|
||||||
|
|
||||||
|
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
|
||||||
|
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index 8db8a81d182dd1fc..2cdd5c1fe790f55c 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -354,7 +354,7 @@ __qsort_r (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
if (size > INDIRECT_SORT_SIZE_THRES)
|
||||||
|
total_size = 2 * total_elems * sizeof (void *) + size;
|
||||||
|
|
||||||
|
- if (total_size < sizeof buf)
|
||||||
|
+ if (total_size <= sizeof tmp)
|
||||||
|
buf = tmp;
|
||||||
|
else
|
||||||
|
{
|
||||||
344
SOURCES/glibc-RHEL-24168-2.patch
Normal file
344
SOURCES/glibc-RHEL-24168-2.patch
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
commit d275970ab56f8ba6a3ca598aba75db4daabe5924
|
||||||
|
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
Date: Fri Apr 8 09:57:57 2022 -0300
|
||||||
|
|
||||||
|
stdlib: Reflow and sort most variable assignments
|
||||||
|
|
||||||
|
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||||||
|
index fe43bec0f9d581d5..03f8478c64408ed3 100644
|
||||||
|
--- a/stdlib/Makefile
|
||||||
|
+++ b/stdlib/Makefile
|
||||||
|
@@ -22,49 +22,145 @@ subdir := stdlib
|
||||||
|
|
||||||
|
include ../Makeconfig
|
||||||
|
|
||||||
|
-headers := stdlib.h bits/stdlib.h bits/stdlib-ldbl.h bits/stdlib-float.h \
|
||||||
|
- monetary.h bits/monetary-ldbl.h \
|
||||||
|
- inttypes.h stdint.h bits/wordsize.h bits/timesize.h \
|
||||||
|
- errno.h sys/errno.h bits/errno.h bits/types/error_t.h \
|
||||||
|
- ucontext.h sys/ucontext.h bits/indirect-return.h \
|
||||||
|
- alloca.h fmtmsg.h \
|
||||||
|
- bits/stdlib-bsearch.h sys/random.h bits/stdint-intn.h \
|
||||||
|
- bits/stdint-uintn.h bits/time64.h \
|
||||||
|
-
|
||||||
|
-routines := \
|
||||||
|
- atof atoi atol atoll \
|
||||||
|
- abort \
|
||||||
|
- bsearch qsort msort \
|
||||||
|
- getenv putenv setenv secure-getenv \
|
||||||
|
- exit on_exit atexit cxa_atexit cxa_finalize old_atexit \
|
||||||
|
- quick_exit at_quick_exit cxa_at_quick_exit cxa_thread_atexit_impl \
|
||||||
|
- abs labs llabs \
|
||||||
|
- div ldiv lldiv \
|
||||||
|
- mblen mbstowcs mbtowc wcstombs wctomb \
|
||||||
|
- random random_r rand rand_r \
|
||||||
|
- drand48 erand48 lrand48 nrand48 mrand48 jrand48 \
|
||||||
|
- srand48 seed48 lcong48 \
|
||||||
|
- drand48_r erand48_r lrand48_r nrand48_r mrand48_r jrand48_r \
|
||||||
|
- srand48_r seed48_r lcong48_r \
|
||||||
|
- drand48-iter getrandom getentropy \
|
||||||
|
- strfromf strfromd strfroml \
|
||||||
|
- strtol strtoul strtoll strtoull \
|
||||||
|
- strtol_l strtoul_l strtoll_l strtoull_l \
|
||||||
|
- strtof strtod strtold \
|
||||||
|
- strtof_l strtod_l strtold_l \
|
||||||
|
- strtof_nan strtod_nan strtold_nan \
|
||||||
|
- system canonicalize \
|
||||||
|
- a64l l64a \
|
||||||
|
- rpmatch strfmon strfmon_l getsubopt xpg_basename fmtmsg \
|
||||||
|
- getcontext setcontext makecontext swapcontext
|
||||||
|
-aux = grouping groupingwc tens_in_limb
|
||||||
|
+headers := \
|
||||||
|
+ alloca.h \
|
||||||
|
+ bits/errno.h \
|
||||||
|
+ bits/indirect-return.h \
|
||||||
|
+ bits/monetary-ldbl.h \
|
||||||
|
+ bits/stdint-intn.h \
|
||||||
|
+ bits/stdint-uintn.h \
|
||||||
|
+ bits/stdlib-bsearch.h \
|
||||||
|
+ bits/stdlib-float.h \
|
||||||
|
+ bits/stdlib.h \
|
||||||
|
+ bits/stdlib-ldbl.h \
|
||||||
|
+ bits/time64.h \
|
||||||
|
+ bits/timesize.h \
|
||||||
|
+ bits/types/error_t.h \
|
||||||
|
+ bits/wordsize.h \
|
||||||
|
+ errno.h \
|
||||||
|
+ fmtmsg.h \
|
||||||
|
+ inttypes.h \
|
||||||
|
+ monetary.h \
|
||||||
|
+ stdint.h \
|
||||||
|
+ stdlib.h \
|
||||||
|
+ sys/errno.h \
|
||||||
|
+ sys/random.h \
|
||||||
|
+ sys/ucontext.h \
|
||||||
|
+ ucontext.h \
|
||||||
|
+ # headers
|
||||||
|
+
|
||||||
|
+routines := \
|
||||||
|
+ a64l \
|
||||||
|
+ abort \
|
||||||
|
+ abs \
|
||||||
|
+ at_quick_exit \
|
||||||
|
+ atof \
|
||||||
|
+ atoi \
|
||||||
|
+ atol\
|
||||||
|
+ atoll \
|
||||||
|
+ bsearch \
|
||||||
|
+ canonicalize \
|
||||||
|
+ cxa_at_quick_exit \
|
||||||
|
+ cxa_atexit \
|
||||||
|
+ cxa_finalize \
|
||||||
|
+ cxa_thread_atexit_impl \
|
||||||
|
+ div \
|
||||||
|
+ drand48 \
|
||||||
|
+ drand48-iter \
|
||||||
|
+ drand48_r \
|
||||||
|
+ erand48 \
|
||||||
|
+ erand48_r \
|
||||||
|
+ exit \
|
||||||
|
+ fmtmsg \
|
||||||
|
+ getcontext \
|
||||||
|
+ getentropy \
|
||||||
|
+ getenv \
|
||||||
|
+ getrandom \
|
||||||
|
+ getsubopt \
|
||||||
|
+ jrand48 \
|
||||||
|
+ jrand48_r \
|
||||||
|
+ l64a \
|
||||||
|
+ labs \
|
||||||
|
+ lcong48 \
|
||||||
|
+ lcong48_r \
|
||||||
|
+ ldiv \
|
||||||
|
+ llabs \
|
||||||
|
+ lldiv \
|
||||||
|
+ lrand48 \
|
||||||
|
+ lrand48_r \
|
||||||
|
+ makecontext \
|
||||||
|
+ mblen \
|
||||||
|
+ mbstowcs \
|
||||||
|
+ mbtowc \
|
||||||
|
+ mrand48 \
|
||||||
|
+ mrand48_r \
|
||||||
|
+ msort \
|
||||||
|
+ nrand48 \
|
||||||
|
+ nrand48_r \
|
||||||
|
+ old_atexit \
|
||||||
|
+ on_exit atexit \
|
||||||
|
+ putenv \
|
||||||
|
+ qsort \
|
||||||
|
+ quick_exit \
|
||||||
|
+ rand \
|
||||||
|
+ rand_r \
|
||||||
|
+ random \
|
||||||
|
+ random_r \
|
||||||
|
+ rpmatch \
|
||||||
|
+ secure-getenv \
|
||||||
|
+ seed48 \
|
||||||
|
+ seed48_r \
|
||||||
|
+ setcontext \
|
||||||
|
+ setenv \
|
||||||
|
+ srand48 \
|
||||||
|
+ srand48_r \
|
||||||
|
+ strfmon \
|
||||||
|
+ strfmon_l \
|
||||||
|
+ strfromd \
|
||||||
|
+ strfromf \
|
||||||
|
+ strfroml \
|
||||||
|
+ strtod \
|
||||||
|
+ strtod_l \
|
||||||
|
+ strtod_nan \
|
||||||
|
+ strtof \
|
||||||
|
+ strtof_l \
|
||||||
|
+ strtof_nan \
|
||||||
|
+ strtol \
|
||||||
|
+ strtol_l \
|
||||||
|
+ strtold \
|
||||||
|
+ strtold_l \
|
||||||
|
+ strtold_nan \
|
||||||
|
+ strtoll \
|
||||||
|
+ strtoll_l \
|
||||||
|
+ strtoul \
|
||||||
|
+ strtoul_l \
|
||||||
|
+ strtoull \
|
||||||
|
+ strtoull_l \
|
||||||
|
+ swapcontext \
|
||||||
|
+ system \
|
||||||
|
+ wcstombs \
|
||||||
|
+ wctomb \
|
||||||
|
+ xpg_basename \
|
||||||
|
+ # routines
|
||||||
|
+
|
||||||
|
+aux = \
|
||||||
|
+ grouping \
|
||||||
|
+ groupingwc \
|
||||||
|
+ tens_in_limb \
|
||||||
|
+ # aux
|
||||||
|
|
||||||
|
# These routines will be omitted from the libc shared object.
|
||||||
|
# Instead the static object files will be included in a special archive
|
||||||
|
# linked against when the shared library will be used.
|
||||||
|
-static-only-routines = atexit at_quick_exit
|
||||||
|
+static-only-routines = \
|
||||||
|
+ atexit \
|
||||||
|
+ at_quick_exit \
|
||||||
|
+ # static-only-routines
|
||||||
|
+
|
||||||
|
+test-srcs := \
|
||||||
|
+ tst-fmtmsg \
|
||||||
|
+ #test-srcs
|
||||||
|
|
||||||
|
-test-srcs := tst-fmtmsg
|
||||||
|
tests := \
|
||||||
|
bug-fmtmsg1 \
|
||||||
|
bug-getcontext \
|
||||||
|
@@ -155,15 +251,29 @@ tests := \
|
||||||
|
tst-width \
|
||||||
|
tst-width-stdint \
|
||||||
|
tst-xpg-basename \
|
||||||
|
-# tests
|
||||||
|
+ # tests
|
||||||
|
+
|
||||||
|
+tests-internal := \
|
||||||
|
+ tst-strtod1i \
|
||||||
|
+ tst-strtod3 \
|
||||||
|
+ tst-strtod4 \
|
||||||
|
+ tst-strtod5i \
|
||||||
|
+ tst-tls-atexit \
|
||||||
|
+ tst-tls-atexit-nodelete \
|
||||||
|
+ # tests-internal
|
||||||
|
+
|
||||||
|
+tests-static := \
|
||||||
|
+ tst-secure-getenv \
|
||||||
|
+ # tests-static
|
||||||
|
|
||||||
|
-tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \
|
||||||
|
- tst-tls-atexit tst-tls-atexit-nodelete
|
||||||
|
-tests-static := tst-secure-getenv
|
||||||
|
-tests-container := tst-system
|
||||||
|
+tests-container := \
|
||||||
|
+ tst-system \
|
||||||
|
+ #tests-container
|
||||||
|
|
||||||
|
ifeq ($(build-hardcoded-path-in-tests),yes)
|
||||||
|
-tests += tst-empty-env
|
||||||
|
+tests += \
|
||||||
|
+ tst-empty-env \
|
||||||
|
+ # tests
|
||||||
|
endif
|
||||||
|
|
||||||
|
LDLIBS-test-atexit-race = $(shared-thread-library)
|
||||||
|
@@ -188,30 +298,76 @@ CFLAGS-tst-thread-quick_exit.o = -std=c++11
|
||||||
|
LDLIBS-tst-thread-quick_exit = -lstdc++
|
||||||
|
$(objpfx)tst-thread-quick_exit: $(shared-thread-library)
|
||||||
|
else
|
||||||
|
-tests-unsupported += tst-quick_exit tst-thread-quick_exit
|
||||||
|
+tests-unsupported += \
|
||||||
|
+ tst-quick_exit \
|
||||||
|
+ tst-thread-quick_exit \
|
||||||
|
+ # tests-unsupported
|
||||||
|
endif
|
||||||
|
|
||||||
|
-modules-names = tst-tls-atexit-lib test-dlclose-exit-race-helper
|
||||||
|
+modules-names = \
|
||||||
|
+ test-dlclose-exit-race-helper \
|
||||||
|
+ tst-tls-atexit-lib \
|
||||||
|
+ # modules-names
|
||||||
|
extra-test-objs += $(addsuffix .os, $(modules-names))
|
||||||
|
|
||||||
|
ifeq ($(build-shared),yes)
|
||||||
|
-tests += tst-putenv
|
||||||
|
+tests += \
|
||||||
|
+ tst-putenv \
|
||||||
|
+ # tests
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Several mpn functions from GNU MP are used by the strtod function.
|
||||||
|
-mpn-routines := inlines add_n addmul_1 cmp divmod_1 divrem udiv_qrnnd \
|
||||||
|
- lshift rshift mod_1 mul mul_1 mul_n sub_n submul_1
|
||||||
|
-mpn-headers = longlong.h gmp.h gmp-impl.h gmp-mparam.h asm-syntax.h
|
||||||
|
-
|
||||||
|
-routines := $(strip $(routines) $(mpn-routines)) \
|
||||||
|
- dbl2mpn ldbl2mpn \
|
||||||
|
- mpn2flt mpn2dbl mpn2ldbl
|
||||||
|
-aux += fpioconst mp_clz_tab
|
||||||
|
-
|
||||||
|
-tests-extras += tst-putenvmod
|
||||||
|
-extra-test-objs += tst-putenvmod.os
|
||||||
|
-
|
||||||
|
-generated += isomac isomac.out tst-putenvmod.so
|
||||||
|
+mpn-routines := \
|
||||||
|
+ add_n \
|
||||||
|
+ addmul_1 \
|
||||||
|
+ cmp \
|
||||||
|
+ divmod_1 \
|
||||||
|
+ divrem \
|
||||||
|
+ inlines \
|
||||||
|
+ lshift \
|
||||||
|
+ mod_1 \
|
||||||
|
+ mul \
|
||||||
|
+ mul_1 \
|
||||||
|
+ mul_n \
|
||||||
|
+ rshift \
|
||||||
|
+ sub_n \
|
||||||
|
+ submul_1 \
|
||||||
|
+ udiv_qrnnd \
|
||||||
|
+ # mpn-routines
|
||||||
|
+mpn-headers = \
|
||||||
|
+ asm-syntax.h \
|
||||||
|
+ gmp-impl.h \
|
||||||
|
+ gmp-mparam.h \
|
||||||
|
+ gmp.h \
|
||||||
|
+ longlong.h \
|
||||||
|
+ # mpn-headers
|
||||||
|
+
|
||||||
|
+routines := \
|
||||||
|
+ $(strip $(routines) $(mpn-routines)) \
|
||||||
|
+ dbl2mpn \
|
||||||
|
+ ldbl2mpn \
|
||||||
|
+ mpn2dbl \
|
||||||
|
+ mpn2flt \
|
||||||
|
+ mpn2ldbl \
|
||||||
|
+ # routines
|
||||||
|
+aux += \
|
||||||
|
+ fpioconst \
|
||||||
|
+ mp_clz_tab \
|
||||||
|
+ # aux
|
||||||
|
+
|
||||||
|
+tests-extras += \
|
||||||
|
+ tst-putenvmod \
|
||||||
|
+ # tests-extras
|
||||||
|
+
|
||||||
|
+extra-test-objs += \
|
||||||
|
+ tst-putenvmod.os \
|
||||||
|
+ # extra-test-objs
|
||||||
|
+
|
||||||
|
+generated += \
|
||||||
|
+ isomac \
|
||||||
|
+ isomac.out \
|
||||||
|
+ tst-putenvmod.so \
|
||||||
|
+ # generated
|
||||||
|
|
||||||
|
CFLAGS-bsearch.c += $(uses-callbacks)
|
||||||
|
CFLAGS-msort.c += $(uses-callbacks)
|
||||||
|
@@ -247,9 +403,17 @@ endif
|
||||||
|
include ../Rules
|
||||||
|
|
||||||
|
ifeq ($(run-built-tests),yes)
|
||||||
|
-LOCALES := cs_CZ.UTF-8 de_DE.UTF-8 en_US.ISO-8859-1 tr_TR.UTF-8 \
|
||||||
|
- tr_TR.ISO-8859-9 tg_TJ.UTF-8 hr_HR.UTF-8 hi_IN.UTF-8 \
|
||||||
|
- el_GR.UTF-8
|
||||||
|
+LOCALES := \
|
||||||
|
+ cs_CZ.UTF-8 \
|
||||||
|
+ de_DE.UTF-8 \
|
||||||
|
+ el_GR.UTF-8 \
|
||||||
|
+ en_US.ISO-8859-1 \
|
||||||
|
+ hi_IN.UTF-8 \
|
||||||
|
+ hr_HR.UTF-8 \
|
||||||
|
+ tg_TJ.UTF-8 \
|
||||||
|
+ tr_TR.ISO-8859-9 \
|
||||||
|
+ tr_TR.UTF-8 \
|
||||||
|
+ # LOCALES
|
||||||
|
include ../gen-locales.mk
|
||||||
|
|
||||||
|
$(objpfx)bug-strtod2.out: $(gen-locales)
|
||||||
65
SOURCES/glibc-RHEL-24168-20.patch
Normal file
65
SOURCES/glibc-RHEL-24168-20.patch
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
commit e7b90e6e605cf236d4bd79e4930cd6a46f9932c7
|
||||||
|
Author: Paul Eggert <eggert@cs.ucla.edu>
|
||||||
|
Date: Thu Feb 1 11:52:46 2024 -0800
|
||||||
|
|
||||||
|
stdlib: fix qsort example in manual
|
||||||
|
|
||||||
|
* manual/search.texi (Comparison Functions, Array Sort Function):
|
||||||
|
Sort an array of long ints, not doubles, to avoid hassles
|
||||||
|
with NaNs.
|
||||||
|
|
||||||
|
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||||
|
|
||||||
|
diff --git a/manual/search.texi b/manual/search.texi
|
||||||
|
index ffaadc46f51b18f9..db577a5332651c36 100644
|
||||||
|
--- a/manual/search.texi
|
||||||
|
+++ b/manual/search.texi
|
||||||
|
@@ -35,19 +35,22 @@ second, zero if they are ``equal'', and positive if the first argument
|
||||||
|
is ``greater''.
|
||||||
|
|
||||||
|
Here is an example of a comparison function which works with an array of
|
||||||
|
-numbers of type @code{double}:
|
||||||
|
+numbers of type @code{long int}:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
int
|
||||||
|
-compare_doubles (const void *a, const void *b)
|
||||||
|
+compare_long_ints (const void *a, const void *b)
|
||||||
|
@{
|
||||||
|
- const double *da = (const double *) a;
|
||||||
|
- const double *db = (const double *) b;
|
||||||
|
+ const long int *la = a;
|
||||||
|
+ const long int *lb = b;
|
||||||
|
|
||||||
|
- return (*da > *db) - (*da < *db);
|
||||||
|
+ return (*la > *lb) - (*la < *lb);
|
||||||
|
@}
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
+(The code would have to be more complicated for an array of @code{double},
|
||||||
|
+to handle NaNs correctly.)
|
||||||
|
+
|
||||||
|
The header file @file{stdlib.h} defines a name for the data type of
|
||||||
|
comparison functions. This type is a GNU extension.
|
||||||
|
|
||||||
|
@@ -183,16 +186,16 @@ in the array before making some comparisons. The only way to perform
|
||||||
|
a stable sort with @code{qsort} is to first augment the objects with a
|
||||||
|
monotonic counter of some kind.
|
||||||
|
|
||||||
|
-Here is a simple example of sorting an array of doubles in numerical
|
||||||
|
+Here is a simple example of sorting an array of @code{long int} in numerical
|
||||||
|
order, using the comparison function defined above (@pxref{Comparison
|
||||||
|
Functions}):
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
@{
|
||||||
|
- double *array;
|
||||||
|
- int size;
|
||||||
|
+ long int *array;
|
||||||
|
+ size_t nmemb;
|
||||||
|
@dots{}
|
||||||
|
- qsort (array, size, sizeof (double), compare_doubles);
|
||||||
|
+ qsort (array, nmemb, sizeof *array, compare_long_ints);
|
||||||
|
@}
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
142
SOURCES/glibc-RHEL-24168-21.patch
Normal file
142
SOURCES/glibc-RHEL-24168-21.patch
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
commit 57581acd9559217e859fdac693145ce6399f4d70
|
||||||
|
Author: Paul Eggert <eggert@cs.ucla.edu>
|
||||||
|
Date: Sat Apr 6 08:44:01 2024 -0700
|
||||||
|
|
||||||
|
Fix bsearch, qsort doc to match POSIX better
|
||||||
|
|
||||||
|
* manual/search.texi (Array Search Function):
|
||||||
|
Correct the statement about lfind’s mean runtime:
|
||||||
|
it is proportional to a number (not that number),
|
||||||
|
and this is true only if random elements are searched for.
|
||||||
|
Relax the constraint on bsearch’s array argument:
|
||||||
|
POSIX says it need not be sorted, only partially sorted.
|
||||||
|
Say that the first arg passed to bsearch’s comparison function
|
||||||
|
is the key, and the second arg is an array element, as
|
||||||
|
POSIX requires. For bsearch and qsort, say that the
|
||||||
|
comparison function should not alter the array, as POSIX
|
||||||
|
requires. For qsort, say that the comparison function
|
||||||
|
must define a total order, as POSIX requires, that
|
||||||
|
it should not depend on element addresses, that
|
||||||
|
the original array index can be used for stable sorts,
|
||||||
|
and that if qsort still works if memory allocation fails.
|
||||||
|
Be more consistent in calling the array elements
|
||||||
|
“elements” rather than “objects”.
|
||||||
|
|
||||||
|
Co-authored-by: Zack Weinberg <zack@owlfolio.org>
|
||||||
|
|
||||||
|
diff --git a/manual/search.texi b/manual/search.texi
|
||||||
|
index db577a5332651c36..cb08c494092ef77f 100644
|
||||||
|
--- a/manual/search.texi
|
||||||
|
+++ b/manual/search.texi
|
||||||
|
@@ -84,8 +84,9 @@ The return value is a pointer to the matching element in the array
|
||||||
|
starting at @var{base} if it is found. If no matching element is
|
||||||
|
available @code{NULL} is returned.
|
||||||
|
|
||||||
|
-The mean runtime of this function is @code{*@var{nmemb}}/2. This
|
||||||
|
-function should only be used if elements often get added to or deleted from
|
||||||
|
+The mean runtime of this function is proportional to @code{*@var{nmemb}/2},
|
||||||
|
+assuming random elements of the array are searched for. This
|
||||||
|
+function should be used only if elements often get added to or deleted from
|
||||||
|
the array in which case it might not be useful to sort the array before
|
||||||
|
searching.
|
||||||
|
@end deftypefun
|
||||||
|
@@ -122,26 +123,34 @@ bytes. If one is sure the element is in the array it is better to use
|
||||||
|
calling @code{lsearch}.
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
-To search a sorted array for an element matching the key, use the
|
||||||
|
-@code{bsearch} function. The prototype for this function is in
|
||||||
|
+To search a sorted or partially sorted array for an element matching the key,
|
||||||
|
+use the @code{bsearch} function. The prototype for this function is in
|
||||||
|
the header file @file{stdlib.h}.
|
||||||
|
@pindex stdlib.h
|
||||||
|
|
||||||
|
@deftypefun {void *} bsearch (const void *@var{key}, const void *@var{array}, size_t @var{count}, size_t @var{size}, comparison_fn_t @var{compare})
|
||||||
|
@standards{ISO, stdlib.h}
|
||||||
|
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
|
||||||
|
-The @code{bsearch} function searches the sorted array @var{array} for an object
|
||||||
|
+The @code{bsearch} function searches @var{array} for an element
|
||||||
|
that is equivalent to @var{key}. The array contains @var{count} elements,
|
||||||
|
each of which is of size @var{size} bytes.
|
||||||
|
|
||||||
|
The @var{compare} function is used to perform the comparison. This
|
||||||
|
-function is called with two pointer arguments and should return an
|
||||||
|
+function is called with arguments that point to the key and to an
|
||||||
|
+array element, in that order, and should return an
|
||||||
|
integer less than, equal to, or greater than zero corresponding to
|
||||||
|
-whether its first argument is considered less than, equal to, or greater
|
||||||
|
-than its second argument. The elements of the @var{array} must already
|
||||||
|
-be sorted in ascending order according to this comparison function.
|
||||||
|
-
|
||||||
|
-The return value is a pointer to the matching array element, or a null
|
||||||
|
+whether the key is considered less than, equal to, or greater than
|
||||||
|
+the array element. The function should not alter the array's contents,
|
||||||
|
+and the same array element should always compare the same way with the key.
|
||||||
|
+
|
||||||
|
+Although the array need not be completely sorted, it should be
|
||||||
|
+partially sorted with respect to @var{key}. That is, the array should
|
||||||
|
+begin with elements that compare less than @var{key}, followed by
|
||||||
|
+elements that compare equal to @var{key}, and ending with elements
|
||||||
|
+that compare greater than @var{key}. Any or all of these element
|
||||||
|
+sequences can be empty.
|
||||||
|
+
|
||||||
|
+The return value is a pointer to a matching array element, or a null
|
||||||
|
pointer if no match is found. If the array contains more than one element
|
||||||
|
that matches, the one that is returned is unspecified.
|
||||||
|
|
||||||
|
@@ -171,20 +180,22 @@ array elements. This function is called with two pointer arguments and
|
||||||
|
should return an integer less than, equal to, or greater than zero
|
||||||
|
corresponding to whether its first argument is considered less than,
|
||||||
|
equal to, or greater than its second argument.
|
||||||
|
+The function must not alter the array's contents, and must define a
|
||||||
|
+total ordering on the array elements, including any unusual values
|
||||||
|
+such as floating-point NaN (@pxref{Infinity and NaN}).
|
||||||
|
+Because the sorting process can move elements,
|
||||||
|
+the function's return value must not depend on the element addresses
|
||||||
|
+or the relative positions of elements within the array,
|
||||||
|
+as these are meaningless while @code{qsort} is running.
|
||||||
|
|
||||||
|
@cindex stable sorting
|
||||||
|
-@strong{Warning:} If two objects compare as equal, their order after
|
||||||
|
+@strong{Warning:} If two elements compare equal, their order after
|
||||||
|
sorting is unpredictable. That is to say, the sorting is not stable.
|
||||||
|
This can make a difference when the comparison considers only part of
|
||||||
|
-the elements. Two elements with the same sort key may differ in other
|
||||||
|
-respects.
|
||||||
|
-
|
||||||
|
-Although the object addresses passed to the comparison function lie
|
||||||
|
-within the array, they need not correspond with the original locations
|
||||||
|
-of those objects because the sorting algorithm may swap around objects
|
||||||
|
-in the array before making some comparisons. The only way to perform
|
||||||
|
-a stable sort with @code{qsort} is to first augment the objects with a
|
||||||
|
-monotonic counter of some kind.
|
||||||
|
+the elements and two elements that compare equal may differ in other
|
||||||
|
+respects. To ensure a stable sort in this situation, you can augment
|
||||||
|
+each element with an appropriate tie-breaking value, such as its
|
||||||
|
+original array index.
|
||||||
|
|
||||||
|
Here is a simple example of sorting an array of @code{long int} in numerical
|
||||||
|
order, using the comparison function defined above (@pxref{Comparison
|
||||||
|
@@ -202,18 +213,19 @@ Functions}):
|
||||||
|
The @code{qsort} function derives its name from the fact that it was
|
||||||
|
originally implemented using the ``quick sort'' algorithm.
|
||||||
|
|
||||||
|
-The implementation of @code{qsort} attempts to allocate auxiliary storage
|
||||||
|
+The implementation of @code{qsort} attempts to allocate auxiliary memory
|
||||||
|
and use the merge sort algorithm, without violating C standard requirement
|
||||||
|
that arguments passed to the comparison function point within the array.
|
||||||
|
+If the memory allocation fails, @code{qsort} resorts to a slower algorithm.
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
@node Search/Sort Example
|
||||||
|
@section Searching and Sorting Example
|
||||||
|
|
||||||
|
Here is an example showing the use of @code{qsort} and @code{bsearch}
|
||||||
|
-with an array of structures. The objects in the array are sorted
|
||||||
|
+with an array of structures. The elements of the array are sorted
|
||||||
|
by comparing their @code{name} fields with the @code{strcmp} function.
|
||||||
|
-Then, we can look up individual objects based on their names.
|
||||||
|
+Then, we can look up individual elements based on their names.
|
||||||
|
|
||||||
|
@comment This example is dedicated to the memory of Jim Henson. RIP.
|
||||||
|
@smallexample
|
||||||
26
SOURCES/glibc-RHEL-24168-22.patch
Normal file
26
SOURCES/glibc-RHEL-24168-22.patch
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
commit 7eed691cc2b6c5dbb6066ee1251606a744c7f05c
|
||||||
|
Author: Arjun Shankar <arjun@redhat.com>
|
||||||
|
Date: Wed Jul 2 17:11:32 2025 +0200
|
||||||
|
|
||||||
|
stdlib/Makefile: Remove deleted test's libm dependency
|
||||||
|
|
||||||
|
tst-qsort5 was deleted in 709fbd3ec3595f2d1076b4fec09a739327459288.
|
||||||
|
Therefore remove its redundant libm dependency.
|
||||||
|
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
stdlib/Makefile: Context line mismatch due to missing tests.
|
||||||
|
|
||||||
|
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||||||
|
index a9d91a57c08ac506..e517e306b868c432 100644
|
||||||
|
--- a/stdlib/Makefile
|
||||||
|
+++ b/stdlib/Makefile
|
||||||
|
@@ -484,7 +484,6 @@ $(objpfx)tst-setcontext3.out: tst-setcontext3.sh $(objpfx)tst-setcontext3
|
||||||
|
$(common-objpfx)stdlib/; \
|
||||||
|
$(evaluate-test)
|
||||||
|
|
||||||
|
-$(objpfx)tst-qsort5: $(libm)
|
||||||
|
$(objpfx)tst-getenv-signal: $(shared-thread-library)
|
||||||
|
$(objpfx)tst-getenv-thread: $(shared-thread-library)
|
||||||
|
$(objpfx)tst-getenv-unsetenv: $(shared-thread-library)
|
||||||
286
SOURCES/glibc-RHEL-24168-3.patch
Normal file
286
SOURCES/glibc-RHEL-24168-3.patch
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
commit fccf38c51746e0817c2409bb361398f9465e0760
|
||||||
|
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
Date: Tue Oct 3 09:22:45 2023 -0300
|
||||||
|
|
||||||
|
string: Add internal memswap implementation
|
||||||
|
|
||||||
|
The prototype is:
|
||||||
|
|
||||||
|
void __memswap (void *restrict p1, void *restrict p2, size_t n)
|
||||||
|
|
||||||
|
The function swaps the content of two memory blocks P1 and P2 of
|
||||||
|
len N. Memory overlap is NOT handled.
|
||||||
|
|
||||||
|
It will be used on qsort optimization.
|
||||||
|
|
||||||
|
Checked on x86_64-linux-gnu and aarch64-linux-gnu.
|
||||||
|
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||||
|
|
||||||
|
diff --git a/string/Makefile b/string/Makefile
|
||||||
|
index 3e4331113f08424c..3ebf7597aad75bfe 100644
|
||||||
|
--- a/string/Makefile
|
||||||
|
+++ b/string/Makefile
|
||||||
|
@@ -66,6 +66,18 @@ tests := tester inl-tester noinl-tester testcopy test-ffs \
|
||||||
|
test-sig_np tst-strerror-fail \
|
||||||
|
test-strdup test-strndup
|
||||||
|
|
||||||
|
+tests-static-internal := \
|
||||||
|
+ test-memswap \
|
||||||
|
+# tests-static-internal
|
||||||
|
+
|
||||||
|
+tests-internal := \
|
||||||
|
+ $(tests-static-internal) \
|
||||||
|
+ # tests-internal
|
||||||
|
+
|
||||||
|
+tests-static := \
|
||||||
|
+ $(tests-static-internal) \
|
||||||
|
+ # tests-static
|
||||||
|
+
|
||||||
|
# Both tests require the .mo translation files generated by msgfmt.
|
||||||
|
tests-translation := tst-strsignal \
|
||||||
|
tst-strerror
|
||||||
|
diff --git a/string/test-memswap.c b/string/test-memswap.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..162beb91e3e96c23
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/string/test-memswap.c
|
||||||
|
@@ -0,0 +1,192 @@
|
||||||
|
+/* Test and measure memcpy functions.
|
||||||
|
+ Copyright (C) 2023 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 <string.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <memswap.h>
|
||||||
|
+
|
||||||
|
+#define TEST_MAIN
|
||||||
|
+#define BUF1PAGES 3
|
||||||
|
+#include "test-string.h"
|
||||||
|
+
|
||||||
|
+static unsigned char *ref1;
|
||||||
|
+static unsigned char *ref2;
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+do_one_test (unsigned char *p1, unsigned char *ref1, unsigned char *p2,
|
||||||
|
+ unsigned char *ref2, size_t len)
|
||||||
|
+{
|
||||||
|
+ __memswap (p1, p2, len);
|
||||||
|
+
|
||||||
|
+ TEST_COMPARE_BLOB (p1, len, ref2, len);
|
||||||
|
+ TEST_COMPARE_BLOB (p2, len, ref1, len);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void
|
||||||
|
+do_test (size_t align1, size_t align2, size_t len)
|
||||||
|
+{
|
||||||
|
+ align1 &= page_size;
|
||||||
|
+ if (align1 + len >= page_size)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ align2 &= page_size;
|
||||||
|
+ if (align2 + len >= page_size)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ unsigned char *p1 = buf1 + align1;
|
||||||
|
+ unsigned char *p2 = buf2 + align2;
|
||||||
|
+ for (size_t repeats = 0; repeats < 2; ++repeats)
|
||||||
|
+ {
|
||||||
|
+ size_t i, j;
|
||||||
|
+ for (i = 0, j = 1; i < len; i++, j += 23)
|
||||||
|
+ {
|
||||||
|
+ ref1[i] = p1[i] = j;
|
||||||
|
+ ref2[i] = p2[i] = UCHAR_MAX - j;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ do_one_test (p1, ref1, p2, ref2, len);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+do_random_tests (void)
|
||||||
|
+{
|
||||||
|
+ for (size_t n = 0; n < ITERATIONS; n++)
|
||||||
|
+ {
|
||||||
|
+ size_t len, size, size1, size2, align1, align2;
|
||||||
|
+
|
||||||
|
+ if (n == 0)
|
||||||
|
+ {
|
||||||
|
+ len = getpagesize ();
|
||||||
|
+ size = len + 512;
|
||||||
|
+ size1 = size;
|
||||||
|
+ size2 = size;
|
||||||
|
+ align1 = 512;
|
||||||
|
+ align2 = 512;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ if ((random () & 255) == 0)
|
||||||
|
+ size = 65536;
|
||||||
|
+ else
|
||||||
|
+ size = 768;
|
||||||
|
+ if (size > page_size)
|
||||||
|
+ size = page_size;
|
||||||
|
+ size1 = size;
|
||||||
|
+ size2 = size;
|
||||||
|
+ size_t i = random ();
|
||||||
|
+ if (i & 3)
|
||||||
|
+ size -= 256;
|
||||||
|
+ if (i & 1)
|
||||||
|
+ size1 -= 256;
|
||||||
|
+ if (i & 2)
|
||||||
|
+ size2 -= 256;
|
||||||
|
+ if (i & 4)
|
||||||
|
+ {
|
||||||
|
+ len = random () % size;
|
||||||
|
+ align1 = size1 - len - (random () & 31);
|
||||||
|
+ align2 = size2 - len - (random () & 31);
|
||||||
|
+ if (align1 > size1)
|
||||||
|
+ align1 = 0;
|
||||||
|
+ if (align2 > size2)
|
||||||
|
+ align2 = 0;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ align1 = random () & 63;
|
||||||
|
+ align2 = random () & 63;
|
||||||
|
+ len = random () % size;
|
||||||
|
+ if (align1 + len > size1)
|
||||||
|
+ align1 = size1 - len;
|
||||||
|
+ if (align2 + len > size2)
|
||||||
|
+ align2 = size2 - len;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ unsigned char *p1 = buf1 + page_size - size1;
|
||||||
|
+ unsigned char *p2 = buf2 + page_size - size2;
|
||||||
|
+ size_t j = align1 + len + 256;
|
||||||
|
+ if (j > size1)
|
||||||
|
+ j = size1;
|
||||||
|
+ for (size_t i = 0; i < j; ++i)
|
||||||
|
+ ref1[i] = p1[i] = random () & 255;
|
||||||
|
+
|
||||||
|
+ j = align2 + len + 256;
|
||||||
|
+ if (j > size2)
|
||||||
|
+ j = size2;
|
||||||
|
+
|
||||||
|
+ for (size_t i = 0; i < j; ++i)
|
||||||
|
+ ref2[i] = p2[i] = random () & 255;
|
||||||
|
+
|
||||||
|
+ do_one_test (p1 + align1, ref1 + align1, p2 + align2, ref2 + align2, len);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+test_main (void)
|
||||||
|
+{
|
||||||
|
+ test_init ();
|
||||||
|
+ /* Use the start of buf1 for reference buffers. */
|
||||||
|
+ ref1 = buf1;
|
||||||
|
+ ref2 = buf1 + page_size;
|
||||||
|
+ buf1 = ref2 + page_size;
|
||||||
|
+
|
||||||
|
+ printf ("%23s", "");
|
||||||
|
+ printf ("\t__memswap\n");
|
||||||
|
+
|
||||||
|
+ for (size_t i = 0; i < 18; ++i)
|
||||||
|
+ {
|
||||||
|
+ do_test (0, 0, 1 << i);
|
||||||
|
+ do_test (i, 0, 1 << i);
|
||||||
|
+ do_test (0, i, 1 << i);
|
||||||
|
+ do_test (i, i, 1 << i);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (size_t i = 0; i < 32; ++i)
|
||||||
|
+ {
|
||||||
|
+ do_test (0, 0, i);
|
||||||
|
+ do_test (i, 0, i);
|
||||||
|
+ do_test (0, i, i);
|
||||||
|
+ do_test (i, i, i);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (size_t i = 3; i < 32; ++i)
|
||||||
|
+ {
|
||||||
|
+ if ((i & (i - 1)) == 0)
|
||||||
|
+ continue;
|
||||||
|
+ do_test (0, 0, 16 * i);
|
||||||
|
+ do_test (i, 0, 16 * i);
|
||||||
|
+ do_test (0, i, 16 * i);
|
||||||
|
+ do_test (i, i, 16 * i);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (size_t i = 19; i <= 25; ++i)
|
||||||
|
+ {
|
||||||
|
+ do_test (255, 0, 1 << i);
|
||||||
|
+ do_test (0, 4000, 1 << i);
|
||||||
|
+ do_test (0, 255, i);
|
||||||
|
+ do_test (0, 4000, i);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ do_test (0, 0, getpagesize ());
|
||||||
|
+
|
||||||
|
+ do_random_tests ();
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
|
diff --git a/sysdeps/generic/memswap.h b/sysdeps/generic/memswap.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..f09dae1ebbc2ec0f
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/sysdeps/generic/memswap.h
|
||||||
|
@@ -0,0 +1,41 @@
|
||||||
|
+/* Swap the content of two memory blocks, overlap is NOT handled.
|
||||||
|
+ Copyright (C) 2023 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 <string.h>
|
||||||
|
+
|
||||||
|
+static inline void
|
||||||
|
+__memswap (void *__restrict p1, void *__restrict p2, size_t n)
|
||||||
|
+{
|
||||||
|
+ /* Use multiple small memcpys with constant size to enable inlining on most
|
||||||
|
+ targets. */
|
||||||
|
+ enum { SWAP_GENERIC_SIZE = 32 };
|
||||||
|
+ unsigned char tmp[SWAP_GENERIC_SIZE];
|
||||||
|
+ while (n > SWAP_GENERIC_SIZE)
|
||||||
|
+ {
|
||||||
|
+ memcpy (tmp, p1, SWAP_GENERIC_SIZE);
|
||||||
|
+ p1 = __mempcpy (p1, p2, SWAP_GENERIC_SIZE);
|
||||||
|
+ p2 = __mempcpy (p2, tmp, SWAP_GENERIC_SIZE);
|
||||||
|
+ n -= SWAP_GENERIC_SIZE;
|
||||||
|
+ }
|
||||||
|
+ while (n > 0)
|
||||||
|
+ {
|
||||||
|
+ unsigned char t = ((unsigned char *)p1)[--n];
|
||||||
|
+ ((unsigned char *)p1)[n] = ((unsigned char *)p2)[n];
|
||||||
|
+ ((unsigned char *)p2)[n] = t;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
157
SOURCES/glibc-RHEL-24168-4.patch
Normal file
157
SOURCES/glibc-RHEL-24168-4.patch
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
commit 21d30c774c7f9f5878f0bf9438736c702b0a58a3
|
||||||
|
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
Date: Tue Oct 3 09:22:46 2023 -0300
|
||||||
|
|
||||||
|
stdlib: Optimization qsort{_r} swap implementation
|
||||||
|
|
||||||
|
The optimization takes in consideration both the most common elements
|
||||||
|
are either 32 or 64 bit in size and inputs are aligned to the word
|
||||||
|
boundary. This is similar to what msort does.
|
||||||
|
|
||||||
|
For large buffer the swap operation uses memcpy/mempcpy with a
|
||||||
|
small fixed size buffer (so compiler might inline the operations).
|
||||||
|
|
||||||
|
Checked on x86_64-linux-gnu.
|
||||||
|
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||||
|
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index 23f2d283147073ac..59b220ba1c375ca3 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -22,22 +22,73 @@
|
||||||
|
|
||||||
|
#include <alloca.h>
|
||||||
|
#include <limits.h>
|
||||||
|
+#include <memswap.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
+#include <stdbool.h>
|
||||||
|
|
||||||
|
-/* Byte-wise swap two items of size SIZE. */
|
||||||
|
-#define SWAP(a, b, size) \
|
||||||
|
- do \
|
||||||
|
- { \
|
||||||
|
- size_t __size = (size); \
|
||||||
|
- char *__a = (a), *__b = (b); \
|
||||||
|
- do \
|
||||||
|
- { \
|
||||||
|
- char __tmp = *__a; \
|
||||||
|
- *__a++ = *__b; \
|
||||||
|
- *__b++ = __tmp; \
|
||||||
|
- } while (--__size > 0); \
|
||||||
|
- } while (0)
|
||||||
|
+/* Swap SIZE bytes between addresses A and B. These helpers are provided
|
||||||
|
+ along the generic one as an optimization. */
|
||||||
|
+
|
||||||
|
+enum swap_type_t
|
||||||
|
+ {
|
||||||
|
+ SWAP_WORDS_64,
|
||||||
|
+ SWAP_WORDS_32,
|
||||||
|
+ SWAP_BYTES
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+/* If this function returns true, elements can be safely copied using word
|
||||||
|
+ loads and stores. Otherwise, it might not be safe. BASE (as an integer)
|
||||||
|
+ must be a multiple of the word alignment. SIZE must be a multiple of
|
||||||
|
+ WORDSIZE. Since WORDSIZE must be a multiple of the word alignment, and
|
||||||
|
+ WORDSIZE is a power of two on all supported platforms, this function for
|
||||||
|
+ speed merely checks that BASE and SIZE are both multiples of the word
|
||||||
|
+ size. */
|
||||||
|
+static inline bool
|
||||||
|
+is_aligned (const void *base, size_t size, size_t wordsize)
|
||||||
|
+{
|
||||||
|
+ return (((uintptr_t) base | size) & (wordsize - 1)) == 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void
|
||||||
|
+swap_words_64 (void * restrict a, void * restrict b, size_t n)
|
||||||
|
+{
|
||||||
|
+ typedef uint64_t __attribute__ ((__may_alias__)) u64_alias_t;
|
||||||
|
+ do
|
||||||
|
+ {
|
||||||
|
+ n -= 8;
|
||||||
|
+ u64_alias_t t = *(u64_alias_t *)(a + n);
|
||||||
|
+ *(u64_alias_t *)(a + n) = *(u64_alias_t *)(b + n);
|
||||||
|
+ *(u64_alias_t *)(b + n) = t;
|
||||||
|
+ } while (n);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void
|
||||||
|
+swap_words_32 (void * restrict a, void * restrict b, size_t n)
|
||||||
|
+{
|
||||||
|
+ typedef uint32_t __attribute__ ((__may_alias__)) u32_alias_t;
|
||||||
|
+ do
|
||||||
|
+ {
|
||||||
|
+ n -= 4;
|
||||||
|
+ u32_alias_t t = *(u32_alias_t *)(a + n);
|
||||||
|
+ *(u32_alias_t *)(a + n) = *(u32_alias_t *)(b + n);
|
||||||
|
+ *(u32_alias_t *)(b + n) = t;
|
||||||
|
+ } while (n);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Replace the indirect call with a serie of if statements. It should help
|
||||||
|
+ the branch predictor. */
|
||||||
|
+static void
|
||||||
|
+do_swap (void * restrict a, void * restrict b, size_t size,
|
||||||
|
+ enum swap_type_t swap_type)
|
||||||
|
+{
|
||||||
|
+ if (swap_type == SWAP_WORDS_64)
|
||||||
|
+ swap_words_64 (a, b, size);
|
||||||
|
+ else if (swap_type == SWAP_WORDS_32)
|
||||||
|
+ swap_words_32 (a, b, size);
|
||||||
|
+ else
|
||||||
|
+ __memswap (a, b, size);
|
||||||
|
+}
|
||||||
|
|
||||||
|
/* Discontinue quicksort algorithm when partition gets below this size.
|
||||||
|
This particular magic number was chosen to work best on a Sun 4/260. */
|
||||||
|
@@ -97,6 +148,14 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
/* Avoid lossage with unsigned arithmetic below. */
|
||||||
|
return;
|
||||||
|
|
||||||
|
+ enum swap_type_t swap_type;
|
||||||
|
+ if (is_aligned (pbase, size, 8))
|
||||||
|
+ swap_type = SWAP_WORDS_64;
|
||||||
|
+ else if (is_aligned (pbase, size, 4))
|
||||||
|
+ swap_type = SWAP_WORDS_32;
|
||||||
|
+ else
|
||||||
|
+ swap_type = SWAP_BYTES;
|
||||||
|
+
|
||||||
|
if (total_elems > MAX_THRESH)
|
||||||
|
{
|
||||||
|
char *lo = base_ptr;
|
||||||
|
@@ -120,13 +179,13 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
char *mid = lo + size * ((hi - lo) / size >> 1);
|
||||||
|
|
||||||
|
if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
|
||||||
|
- SWAP (mid, lo, size);
|
||||||
|
+ do_swap (mid, lo, size, swap_type);
|
||||||
|
if ((*cmp) ((void *) hi, (void *) mid, arg) < 0)
|
||||||
|
- SWAP (mid, hi, size);
|
||||||
|
+ do_swap (mid, hi, size, swap_type);
|
||||||
|
else
|
||||||
|
goto jump_over;
|
||||||
|
if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
|
||||||
|
- SWAP (mid, lo, size);
|
||||||
|
+ do_swap (mid, lo, size, swap_type);
|
||||||
|
jump_over:;
|
||||||
|
|
||||||
|
left_ptr = lo + size;
|
||||||
|
@@ -145,7 +204,7 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
|
||||||
|
if (left_ptr < right_ptr)
|
||||||
|
{
|
||||||
|
- SWAP (left_ptr, right_ptr, size);
|
||||||
|
+ do_swap (left_ptr, right_ptr, size, swap_type);
|
||||||
|
if (mid == left_ptr)
|
||||||
|
mid = right_ptr;
|
||||||
|
else if (mid == right_ptr)
|
||||||
|
@@ -217,7 +276,7 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
tmp_ptr = run_ptr;
|
||||||
|
|
||||||
|
if (tmp_ptr != base_ptr)
|
||||||
|
- SWAP (tmp_ptr, base_ptr, size);
|
||||||
|
+ do_swap (tmp_ptr, base_ptr, size, swap_type);
|
||||||
|
|
||||||
|
/* Insertion sort, running from left-hand-side up to right-hand-side. */
|
||||||
|
|
||||||
125
SOURCES/glibc-RHEL-24168-5.patch
Normal file
125
SOURCES/glibc-RHEL-24168-5.patch
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
commit a035a9857e11faf16ed021b5e80faf215262afd1
|
||||||
|
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
Date: Tue Oct 3 09:22:47 2023 -0300
|
||||||
|
|
||||||
|
stdlib: Move insertion sort out qsort
|
||||||
|
|
||||||
|
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||||
|
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index 59b220ba1c375ca3..35020e4c00e5fce3 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -112,6 +112,58 @@ typedef struct
|
||||||
|
#define STACK_NOT_EMPTY (stack < top)
|
||||||
|
|
||||||
|
|
||||||
|
+static inline void
|
||||||
|
+insertion_sort_qsort_partitions (void *const pbase, size_t total_elems,
|
||||||
|
+ size_t size, enum swap_type_t swap_type,
|
||||||
|
+ __compar_d_fn_t cmp, void *arg)
|
||||||
|
+{
|
||||||
|
+ char *base_ptr = (char *) pbase;
|
||||||
|
+ char *const end_ptr = &base_ptr[size * (total_elems - 1)];
|
||||||
|
+ char *tmp_ptr = base_ptr;
|
||||||
|
+#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||||
|
+ const size_t max_thresh = MAX_THRESH * size;
|
||||||
|
+ char *thresh = min(end_ptr, base_ptr + max_thresh);
|
||||||
|
+ char *run_ptr;
|
||||||
|
+
|
||||||
|
+ /* Find smallest element in first threshold and place it at the
|
||||||
|
+ array's beginning. This is the smallest array element,
|
||||||
|
+ and the operation speeds up insertion sort's inner loop. */
|
||||||
|
+
|
||||||
|
+ for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
|
||||||
|
+ if (cmp (run_ptr, tmp_ptr, arg) < 0)
|
||||||
|
+ tmp_ptr = run_ptr;
|
||||||
|
+
|
||||||
|
+ if (tmp_ptr != base_ptr)
|
||||||
|
+ do_swap (tmp_ptr, base_ptr, size, swap_type);
|
||||||
|
+
|
||||||
|
+ /* Insertion sort, running from left-hand-side up to right-hand-side. */
|
||||||
|
+
|
||||||
|
+ run_ptr = base_ptr + size;
|
||||||
|
+ while ((run_ptr += size) <= end_ptr)
|
||||||
|
+ {
|
||||||
|
+ tmp_ptr = run_ptr - size;
|
||||||
|
+ while (cmp (run_ptr, tmp_ptr, arg) < 0)
|
||||||
|
+ tmp_ptr -= size;
|
||||||
|
+
|
||||||
|
+ tmp_ptr += size;
|
||||||
|
+ if (tmp_ptr != run_ptr)
|
||||||
|
+ {
|
||||||
|
+ char *trav;
|
||||||
|
+
|
||||||
|
+ trav = run_ptr + size;
|
||||||
|
+ while (--trav >= run_ptr)
|
||||||
|
+ {
|
||||||
|
+ char c = *trav;
|
||||||
|
+ char *hi, *lo;
|
||||||
|
+
|
||||||
|
+ for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
|
||||||
|
+ *hi = *lo;
|
||||||
|
+ *hi = c;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* Order size using quicksort. This implementation incorporates
|
||||||
|
four optimizations discussed in Sedgewick:
|
||||||
|
|
||||||
|
@@ -258,51 +310,6 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
for partitions below MAX_THRESH size. BASE_PTR points to the beginning
|
||||||
|
of the array to sort, and END_PTR points at the very last element in
|
||||||
|
the array (*not* one beyond it!). */
|
||||||
|
-
|
||||||
|
-#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||||
|
-
|
||||||
|
- {
|
||||||
|
- char *const end_ptr = &base_ptr[size * (total_elems - 1)];
|
||||||
|
- char *tmp_ptr = base_ptr;
|
||||||
|
- char *thresh = min(end_ptr, base_ptr + max_thresh);
|
||||||
|
- char *run_ptr;
|
||||||
|
-
|
||||||
|
- /* Find smallest element in first threshold and place it at the
|
||||||
|
- array's beginning. This is the smallest array element,
|
||||||
|
- and the operation speeds up insertion sort's inner loop. */
|
||||||
|
-
|
||||||
|
- for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
|
||||||
|
- if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
|
||||||
|
- tmp_ptr = run_ptr;
|
||||||
|
-
|
||||||
|
- if (tmp_ptr != base_ptr)
|
||||||
|
- do_swap (tmp_ptr, base_ptr, size, swap_type);
|
||||||
|
-
|
||||||
|
- /* Insertion sort, running from left-hand-side up to right-hand-side. */
|
||||||
|
-
|
||||||
|
- run_ptr = base_ptr + size;
|
||||||
|
- while ((run_ptr += size) <= end_ptr)
|
||||||
|
- {
|
||||||
|
- tmp_ptr = run_ptr - size;
|
||||||
|
- while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
|
||||||
|
- tmp_ptr -= size;
|
||||||
|
-
|
||||||
|
- tmp_ptr += size;
|
||||||
|
- if (tmp_ptr != run_ptr)
|
||||||
|
- {
|
||||||
|
- char *trav;
|
||||||
|
-
|
||||||
|
- trav = run_ptr + size;
|
||||||
|
- while (--trav >= run_ptr)
|
||||||
|
- {
|
||||||
|
- char c = *trav;
|
||||||
|
- char *hi, *lo;
|
||||||
|
-
|
||||||
|
- for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
|
||||||
|
- *hi = *lo;
|
||||||
|
- *hi = c;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
+ insertion_sort_qsort_partitions (pbase, total_elems, size, swap_type, cmp,
|
||||||
|
+ arg);
|
||||||
|
}
|
||||||
85
SOURCES/glibc-RHEL-24168-6.patch
Normal file
85
SOURCES/glibc-RHEL-24168-6.patch
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
commit d097f3c79be55d646d86efb7ce876bf84d5ebe4e
|
||||||
|
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
Date: Tue Oct 3 09:22:48 2023 -0300
|
||||||
|
|
||||||
|
stdlib: qsort: Move some macros to inline function
|
||||||
|
|
||||||
|
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||||
|
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index 35020e4c00e5fce3..821a87420638c5a5 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -101,15 +101,28 @@ typedef struct
|
||||||
|
char *hi;
|
||||||
|
} stack_node;
|
||||||
|
|
||||||
|
-/* The next 4 #defines implement a very fast in-line stack abstraction. */
|
||||||
|
/* The stack needs log (total_elements) entries (we could even subtract
|
||||||
|
log(MAX_THRESH)). Since total_elements has type size_t, we get as
|
||||||
|
upper bound for log (total_elements):
|
||||||
|
bits per byte (CHAR_BIT) * sizeof(size_t). */
|
||||||
|
-#define STACK_SIZE (CHAR_BIT * sizeof (size_t))
|
||||||
|
-#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
|
||||||
|
-#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
|
||||||
|
-#define STACK_NOT_EMPTY (stack < top)
|
||||||
|
+enum { STACK_SIZE = CHAR_BIT * sizeof (size_t) };
|
||||||
|
+
|
||||||
|
+static inline stack_node *
|
||||||
|
+push (stack_node *top, char *lo, char *hi)
|
||||||
|
+{
|
||||||
|
+ top->lo = lo;
|
||||||
|
+ top->hi = hi;
|
||||||
|
+ return ++top;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline stack_node *
|
||||||
|
+pop (stack_node *top, char **lo, char **hi)
|
||||||
|
+{
|
||||||
|
+ --top;
|
||||||
|
+ *lo = top->lo;
|
||||||
|
+ *hi = top->hi;
|
||||||
|
+ return top;
|
||||||
|
+}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
@@ -213,11 +226,9 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
char *lo = base_ptr;
|
||||||
|
char *hi = &lo[size * (total_elems - 1)];
|
||||||
|
stack_node stack[STACK_SIZE];
|
||||||
|
- stack_node *top = stack;
|
||||||
|
-
|
||||||
|
- PUSH (NULL, NULL);
|
||||||
|
+ stack_node *top = stack + 1;
|
||||||
|
|
||||||
|
- while (STACK_NOT_EMPTY)
|
||||||
|
+ while (stack < top)
|
||||||
|
{
|
||||||
|
char *left_ptr;
|
||||||
|
char *right_ptr;
|
||||||
|
@@ -282,7 +293,7 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
{
|
||||||
|
if ((size_t) (hi - left_ptr) <= max_thresh)
|
||||||
|
/* Ignore both small partitions. */
|
||||||
|
- POP (lo, hi);
|
||||||
|
+ top = pop (top, &lo, &hi);
|
||||||
|
else
|
||||||
|
/* Ignore small left partition. */
|
||||||
|
lo = left_ptr;
|
||||||
|
@@ -293,13 +304,13 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
else if ((right_ptr - lo) > (hi - left_ptr))
|
||||||
|
{
|
||||||
|
/* Push larger left partition indices. */
|
||||||
|
- PUSH (lo, right_ptr);
|
||||||
|
+ top = push (top, lo, right_ptr);
|
||||||
|
lo = left_ptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Push larger right partition indices. */
|
||||||
|
- PUSH (left_ptr, hi);
|
||||||
|
+ top = push (top, left_ptr, hi);
|
||||||
|
hi = right_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
176
SOURCES/glibc-RHEL-24168-7.patch
Normal file
176
SOURCES/glibc-RHEL-24168-7.patch
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
commit 274a46c9b25ab733a1fb9fb1497f1beecae30193
|
||||||
|
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
Date: Tue Oct 3 09:22:49 2023 -0300
|
||||||
|
|
||||||
|
stdlib: Implement introsort for qsort (BZ 19305)
|
||||||
|
|
||||||
|
This patch makes the quicksort implementation to acts as introsort, to
|
||||||
|
avoid worse-case performance (and thus making it O(nlog n)). It switch
|
||||||
|
to heapsort when the depth level reaches 2*log2(total elements). The
|
||||||
|
heapsort is a textbook implementation.
|
||||||
|
|
||||||
|
Checked on x86_64-linux-gnu and aarch64-linux-gnu.
|
||||||
|
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||||
|
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index 821a87420638c5a5..db299eb333cf0302 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -99,6 +99,7 @@ typedef struct
|
||||||
|
{
|
||||||
|
char *lo;
|
||||||
|
char *hi;
|
||||||
|
+ size_t depth;
|
||||||
|
} stack_node;
|
||||||
|
|
||||||
|
/* The stack needs log (total_elements) entries (we could even subtract
|
||||||
|
@@ -108,22 +109,85 @@ typedef struct
|
||||||
|
enum { STACK_SIZE = CHAR_BIT * sizeof (size_t) };
|
||||||
|
|
||||||
|
static inline stack_node *
|
||||||
|
-push (stack_node *top, char *lo, char *hi)
|
||||||
|
+push (stack_node *top, char *lo, char *hi, size_t depth)
|
||||||
|
{
|
||||||
|
top->lo = lo;
|
||||||
|
top->hi = hi;
|
||||||
|
+ top->depth = depth;
|
||||||
|
return ++top;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline stack_node *
|
||||||
|
-pop (stack_node *top, char **lo, char **hi)
|
||||||
|
+pop (stack_node *top, char **lo, char **hi, size_t *depth)
|
||||||
|
{
|
||||||
|
--top;
|
||||||
|
*lo = top->lo;
|
||||||
|
*hi = top->hi;
|
||||||
|
+ *depth = top->depth;
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* NB: N is inclusive bound for BASE. */
|
||||||
|
+static inline void
|
||||||
|
+siftdown (void *base, size_t size, size_t k, size_t n,
|
||||||
|
+ enum swap_type_t swap_type, __compar_d_fn_t cmp, void *arg)
|
||||||
|
+{
|
||||||
|
+ while (k <= n / 2)
|
||||||
|
+ {
|
||||||
|
+ size_t j = 2 * k;
|
||||||
|
+ if (j < n && cmp (base + (j * size), base + ((j + 1) * size), arg) < 0)
|
||||||
|
+ j++;
|
||||||
|
+
|
||||||
|
+ if (cmp (base + (k * size), base + (j * size), arg) >= 0)
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ do_swap (base + (size * j), base + (k * size), size, swap_type);
|
||||||
|
+ k = j;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void
|
||||||
|
+heapify (void *base, size_t size, size_t n, enum swap_type_t swap_type,
|
||||||
|
+ __compar_d_fn_t cmp, void *arg)
|
||||||
|
+{
|
||||||
|
+ size_t k = n / 2;
|
||||||
|
+ while (1)
|
||||||
|
+ {
|
||||||
|
+ siftdown (base, size, k, n, swap_type, cmp, arg);
|
||||||
|
+ if (k-- == 0)
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* A non-recursive heapsort, used on introsort implementation as a fallback
|
||||||
|
+ routine with worst-case performance of O(nlog n) and worst-case space
|
||||||
|
+ complexity of O(1). It sorts the array starting at BASE and ending at
|
||||||
|
+ END, with each element of SIZE bytes. The SWAP_TYPE is the callback
|
||||||
|
+ function used to swap elements, and CMP is the function used to compare
|
||||||
|
+ elements. */
|
||||||
|
+static void
|
||||||
|
+heapsort_r (void *base, void *end, size_t size, enum swap_type_t swap_type,
|
||||||
|
+ __compar_d_fn_t cmp, void *arg)
|
||||||
|
+{
|
||||||
|
+ const size_t count = ((uintptr_t) end - (uintptr_t) base) / size;
|
||||||
|
+
|
||||||
|
+ if (count < 2)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ size_t n = count - 1;
|
||||||
|
+
|
||||||
|
+ /* Build the binary heap, largest value at the base[0]. */
|
||||||
|
+ heapify (base, size, n, swap_type, cmp, arg);
|
||||||
|
+
|
||||||
|
+ /* On each iteration base[0:n] is the binary heap, while base[n:count]
|
||||||
|
+ is sorted. */
|
||||||
|
+ while (n > 0)
|
||||||
|
+ {
|
||||||
|
+ do_swap (base, base + (n * size), size, swap_type);
|
||||||
|
+ n--;
|
||||||
|
+ siftdown (base, size, 0, n, swap_type, cmp, arg);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
insertion_sort_qsort_partitions (void *const pbase, size_t total_elems,
|
||||||
|
@@ -209,7 +273,7 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
|
||||||
|
const size_t max_thresh = MAX_THRESH * size;
|
||||||
|
|
||||||
|
- if (total_elems == 0)
|
||||||
|
+ if (total_elems <= 1)
|
||||||
|
/* Avoid lossage with unsigned arithmetic below. */
|
||||||
|
return;
|
||||||
|
|
||||||
|
@@ -221,15 +285,26 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
else
|
||||||
|
swap_type = SWAP_BYTES;
|
||||||
|
|
||||||
|
+ /* Maximum depth before quicksort switches to heapsort. */
|
||||||
|
+ size_t depth = 2 * (sizeof (size_t) * CHAR_BIT - 1
|
||||||
|
+ - __builtin_clzl (total_elems));
|
||||||
|
+
|
||||||
|
if (total_elems > MAX_THRESH)
|
||||||
|
{
|
||||||
|
char *lo = base_ptr;
|
||||||
|
char *hi = &lo[size * (total_elems - 1)];
|
||||||
|
stack_node stack[STACK_SIZE];
|
||||||
|
- stack_node *top = stack + 1;
|
||||||
|
+ stack_node *top = push (stack, NULL, NULL, depth);
|
||||||
|
|
||||||
|
while (stack < top)
|
||||||
|
{
|
||||||
|
+ if (depth == 0)
|
||||||
|
+ {
|
||||||
|
+ heapsort_r (lo, hi, size, swap_type, cmp, arg);
|
||||||
|
+ top = pop (top, &lo, &hi, &depth);
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
char *left_ptr;
|
||||||
|
char *right_ptr;
|
||||||
|
|
||||||
|
@@ -293,7 +368,7 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
{
|
||||||
|
if ((size_t) (hi - left_ptr) <= max_thresh)
|
||||||
|
/* Ignore both small partitions. */
|
||||||
|
- top = pop (top, &lo, &hi);
|
||||||
|
+ top = pop (top, &lo, &hi, &depth);
|
||||||
|
else
|
||||||
|
/* Ignore small left partition. */
|
||||||
|
lo = left_ptr;
|
||||||
|
@@ -304,13 +379,13 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
else if ((right_ptr - lo) > (hi - left_ptr))
|
||||||
|
{
|
||||||
|
/* Push larger left partition indices. */
|
||||||
|
- top = push (top, lo, right_ptr);
|
||||||
|
+ top = push (top, lo, right_ptr, depth - 1);
|
||||||
|
lo = left_ptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Push larger right partition indices. */
|
||||||
|
- top = push (top, left_ptr, hi);
|
||||||
|
+ top = push (top, left_ptr, hi, depth - 1);
|
||||||
|
hi = right_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
491
SOURCES/glibc-RHEL-24168-8.patch
Normal file
491
SOURCES/glibc-RHEL-24168-8.patch
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
commit 03bf8357e8291857a435afcc3048e0b697b6cc04
|
||||||
|
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
Date: Tue Oct 3 09:22:50 2023 -0300
|
||||||
|
|
||||||
|
stdlib: Remove use of mergesort on qsort (BZ 21719)
|
||||||
|
|
||||||
|
This patch removes the mergesort optimization on qsort implementation
|
||||||
|
and uses the introsort instead. The mergesort implementation has some
|
||||||
|
issues:
|
||||||
|
|
||||||
|
- It is as-safe only for certain types sizes (if total size is less
|
||||||
|
than 1 KB with large element sizes also forcing memory allocation)
|
||||||
|
which contradicts the function documentation. Although not required
|
||||||
|
by the C standard, it is preferable and doable to have an O(1) space
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
- The malloc for certain element size and element number adds
|
||||||
|
arbitrary latency (might even be worse if malloc is interposed).
|
||||||
|
|
||||||
|
- To avoid trigger swap from memory allocation the implementation
|
||||||
|
relies on system information that might be virtualized (for instance
|
||||||
|
VMs with overcommit memory) which might lead to potentially use of
|
||||||
|
swap even if system advertise more memory than actually has. The
|
||||||
|
check also have the downside of issuing syscalls where none is
|
||||||
|
expected (although only once per execution).
|
||||||
|
|
||||||
|
- The mergesort is suboptimal on an already sorted array (BZ#21719).
|
||||||
|
|
||||||
|
The introsort implementation is already optimized to use constant extra
|
||||||
|
space (due to the limit of total number of elements from maximum VM
|
||||||
|
size) and thus can be used to avoid the malloc usage issues.
|
||||||
|
|
||||||
|
Resulting performance is slower due the usage of qsort, specially in the
|
||||||
|
worst-case scenario (partialy or sorted arrays) and due the fact
|
||||||
|
mergesort uses a slight improved swap operations.
|
||||||
|
|
||||||
|
This change also renders the BZ#21719 fix unrequired (since it is meant
|
||||||
|
to fix the sorted input performance degradation for mergesort). The
|
||||||
|
manual is also updated to indicate the function is now async-cancel
|
||||||
|
safe.
|
||||||
|
|
||||||
|
Checked on x86_64-linux-gnu.
|
||||||
|
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
stdlib/msort.c: Deletion had conflicts due to skipped backports.
|
||||||
|
|
||||||
|
diff --git a/include/stdlib.h b/include/stdlib.h
|
||||||
|
index 22c9fb65c3074765..fd108df58ddf8b89 100644
|
||||||
|
--- a/include/stdlib.h
|
||||||
|
+++ b/include/stdlib.h
|
||||||
|
@@ -107,8 +107,6 @@ extern int __posix_openpt (int __oflag) attribute_hidden;
|
||||||
|
extern int __add_to_environ (const char *name, const char *value,
|
||||||
|
const char *combines, int replace)
|
||||||
|
attribute_hidden;
|
||||||
|
-extern void _quicksort (void *const pbase, size_t total_elems,
|
||||||
|
- size_t size, __compar_d_fn_t cmp, void *arg);
|
||||||
|
|
||||||
|
extern int __on_exit (void (*__func) (int __status, void *__arg), void *__arg);
|
||||||
|
|
||||||
|
diff --git a/manual/argp.texi b/manual/argp.texi
|
||||||
|
index 0023441812d4e584..b77ad68285ecb732 100644
|
||||||
|
--- a/manual/argp.texi
|
||||||
|
+++ b/manual/argp.texi
|
||||||
|
@@ -735,7 +735,7 @@ for options, bad phase of the moon, etc.
|
||||||
|
@c hol_set_group ok
|
||||||
|
@c hol_find_entry ok
|
||||||
|
@c hol_sort @mtslocale @acucorrupt
|
||||||
|
-@c qsort dup @acucorrupt
|
||||||
|
+@c qsort dup
|
||||||
|
@c hol_entry_qcmp @mtslocale
|
||||||
|
@c hol_entry_cmp @mtslocale
|
||||||
|
@c group_cmp ok
|
||||||
|
diff --git a/manual/locale.texi b/manual/locale.texi
|
||||||
|
index 720e0ca952a665bd..f6afa5dc44a2a016 100644
|
||||||
|
--- a/manual/locale.texi
|
||||||
|
+++ b/manual/locale.texi
|
||||||
|
@@ -253,7 +253,7 @@ The symbols in this section are defined in the header file @file{locale.h}.
|
||||||
|
@c calculate_head_size ok
|
||||||
|
@c __munmap ok
|
||||||
|
@c compute_hashval ok
|
||||||
|
-@c qsort dup @acucorrupt
|
||||||
|
+@c qsort dup
|
||||||
|
@c rangecmp ok
|
||||||
|
@c malloc @ascuheap @acsmem
|
||||||
|
@c strdup @ascuheap @acsmem
|
||||||
|
@@ -275,7 +275,6 @@ The symbols in this section are defined in the header file @file{locale.h}.
|
||||||
|
@c realloc @ascuheap @acsmem
|
||||||
|
@c realloc @ascuheap @acsmem
|
||||||
|
@c fclose @ascuheap @asulock @acsmem @acsfd @aculock
|
||||||
|
-@c qsort @ascuheap @acsmem
|
||||||
|
@c alias_compare dup
|
||||||
|
@c libc_lock_unlock @aculock
|
||||||
|
@c _nl_explode_name @ascuheap @acsmem
|
||||||
|
diff --git a/manual/search.texi b/manual/search.texi
|
||||||
|
index 5691bf2f2b2bb861..a550858478f7fc83 100644
|
||||||
|
--- a/manual/search.texi
|
||||||
|
+++ b/manual/search.texi
|
||||||
|
@@ -159,7 +159,7 @@ To sort an array using an arbitrary comparison function, use the
|
||||||
|
|
||||||
|
@deftypefun void qsort (void *@var{array}, size_t @var{count}, size_t @var{size}, comparison_fn_t @var{compare})
|
||||||
|
@standards{ISO, stdlib.h}
|
||||||
|
-@safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}}
|
||||||
|
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
|
||||||
|
The @code{qsort} function sorts the array @var{array}. The array
|
||||||
|
contains @var{count} elements, each of which is of size @var{size}.
|
||||||
|
|
||||||
|
@@ -199,9 +199,8 @@ Functions}):
|
||||||
|
The @code{qsort} function derives its name from the fact that it was
|
||||||
|
originally implemented using the ``quick sort'' algorithm.
|
||||||
|
|
||||||
|
-The implementation of @code{qsort} in this library might not be an
|
||||||
|
-in-place sort and might thereby use an extra amount of memory to store
|
||||||
|
-the array.
|
||||||
|
+The implementation of @code{qsort} in this library is an in-place sort
|
||||||
|
+and uses a constant extra space (allocated on the stack).
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
@node Search/Sort Example
|
||||||
|
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||||||
|
index 03f8478c64408ed3..3b89bc2aa0307321 100644
|
||||||
|
--- a/stdlib/Makefile
|
||||||
|
+++ b/stdlib/Makefile
|
||||||
|
@@ -94,7 +94,6 @@ routines := \
|
||||||
|
mbtowc \
|
||||||
|
mrand48 \
|
||||||
|
mrand48_r \
|
||||||
|
- msort \
|
||||||
|
nrand48 \
|
||||||
|
nrand48_r \
|
||||||
|
old_atexit \
|
||||||
|
@@ -370,7 +369,6 @@ generated += \
|
||||||
|
# generated
|
||||||
|
|
||||||
|
CFLAGS-bsearch.c += $(uses-callbacks)
|
||||||
|
-CFLAGS-msort.c += $(uses-callbacks)
|
||||||
|
CFLAGS-qsort.c += $(uses-callbacks)
|
||||||
|
CFLAGS-system.c += -fexceptions
|
||||||
|
CFLAGS-system.os = -fomit-frame-pointer
|
||||||
|
diff --git a/stdlib/msort.c b/stdlib/msort.c
|
||||||
|
deleted file mode 100644
|
||||||
|
index 8750cc59db2337cf..0000000000000000
|
||||||
|
--- a/stdlib/msort.c
|
||||||
|
+++ /dev/null
|
||||||
|
@@ -1,310 +0,0 @@
|
||||||
|
-/* An alternative to qsort, with an identical interface.
|
||||||
|
- This file is part of the GNU C Library.
|
||||||
|
- Copyright (C) 1992-2021 Free Software Foundation, Inc.
|
||||||
|
- Written by Mike Haertel, September 1988.
|
||||||
|
-
|
||||||
|
- 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 <alloca.h>
|
||||||
|
-#include <stdint.h>
|
||||||
|
-#include <stdlib.h>
|
||||||
|
-#include <string.h>
|
||||||
|
-#include <unistd.h>
|
||||||
|
-#include <memcopy.h>
|
||||||
|
-#include <errno.h>
|
||||||
|
-#include <atomic.h>
|
||||||
|
-
|
||||||
|
-struct msort_param
|
||||||
|
-{
|
||||||
|
- size_t s;
|
||||||
|
- size_t var;
|
||||||
|
- __compar_d_fn_t cmp;
|
||||||
|
- void *arg;
|
||||||
|
- char *t;
|
||||||
|
-};
|
||||||
|
-static void msort_with_tmp (const struct msort_param *p, void *b, size_t n);
|
||||||
|
-
|
||||||
|
-static void
|
||||||
|
-msort_with_tmp (const struct msort_param *p, void *b, size_t n)
|
||||||
|
-{
|
||||||
|
- char *b1, *b2;
|
||||||
|
- size_t n1, n2;
|
||||||
|
-
|
||||||
|
- if (n <= 1)
|
||||||
|
- return;
|
||||||
|
-
|
||||||
|
- n1 = n / 2;
|
||||||
|
- n2 = n - n1;
|
||||||
|
- b1 = b;
|
||||||
|
- b2 = (char *) b + (n1 * p->s);
|
||||||
|
-
|
||||||
|
- msort_with_tmp (p, b1, n1);
|
||||||
|
- msort_with_tmp (p, b2, n2);
|
||||||
|
-
|
||||||
|
- char *tmp = p->t;
|
||||||
|
- const size_t s = p->s;
|
||||||
|
- __compar_d_fn_t cmp = p->cmp;
|
||||||
|
- void *arg = p->arg;
|
||||||
|
- switch (p->var)
|
||||||
|
- {
|
||||||
|
- case 0:
|
||||||
|
- while (n1 > 0 && n2 > 0)
|
||||||
|
- {
|
||||||
|
- if ((*cmp) (b1, b2, arg) <= 0)
|
||||||
|
- {
|
||||||
|
- *(uint32_t *) tmp = *(uint32_t *) b1;
|
||||||
|
- b1 += sizeof (uint32_t);
|
||||||
|
- --n1;
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- *(uint32_t *) tmp = *(uint32_t *) b2;
|
||||||
|
- b2 += sizeof (uint32_t);
|
||||||
|
- --n2;
|
||||||
|
- }
|
||||||
|
- tmp += sizeof (uint32_t);
|
||||||
|
- }
|
||||||
|
- break;
|
||||||
|
- case 1:
|
||||||
|
- while (n1 > 0 && n2 > 0)
|
||||||
|
- {
|
||||||
|
- if ((*cmp) (b1, b2, arg) <= 0)
|
||||||
|
- {
|
||||||
|
- *(uint64_t *) tmp = *(uint64_t *) b1;
|
||||||
|
- b1 += sizeof (uint64_t);
|
||||||
|
- --n1;
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- *(uint64_t *) tmp = *(uint64_t *) b2;
|
||||||
|
- b2 += sizeof (uint64_t);
|
||||||
|
- --n2;
|
||||||
|
- }
|
||||||
|
- tmp += sizeof (uint64_t);
|
||||||
|
- }
|
||||||
|
- break;
|
||||||
|
- case 2:
|
||||||
|
- while (n1 > 0 && n2 > 0)
|
||||||
|
- {
|
||||||
|
- unsigned long *tmpl = (unsigned long *) tmp;
|
||||||
|
- unsigned long *bl;
|
||||||
|
-
|
||||||
|
- tmp += s;
|
||||||
|
- if ((*cmp) (b1, b2, arg) <= 0)
|
||||||
|
- {
|
||||||
|
- bl = (unsigned long *) b1;
|
||||||
|
- b1 += s;
|
||||||
|
- --n1;
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- bl = (unsigned long *) b2;
|
||||||
|
- b2 += s;
|
||||||
|
- --n2;
|
||||||
|
- }
|
||||||
|
- while (tmpl < (unsigned long *) tmp)
|
||||||
|
- *tmpl++ = *bl++;
|
||||||
|
- }
|
||||||
|
- break;
|
||||||
|
- case 3:
|
||||||
|
- while (n1 > 0 && n2 > 0)
|
||||||
|
- {
|
||||||
|
- if ((*cmp) (*(const void **) b1, *(const void **) b2, arg) <= 0)
|
||||||
|
- {
|
||||||
|
- *(void **) tmp = *(void **) b1;
|
||||||
|
- b1 += sizeof (void *);
|
||||||
|
- --n1;
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- *(void **) tmp = *(void **) b2;
|
||||||
|
- b2 += sizeof (void *);
|
||||||
|
- --n2;
|
||||||
|
- }
|
||||||
|
- tmp += sizeof (void *);
|
||||||
|
- }
|
||||||
|
- break;
|
||||||
|
- default:
|
||||||
|
- while (n1 > 0 && n2 > 0)
|
||||||
|
- {
|
||||||
|
- if ((*cmp) (b1, b2, arg) <= 0)
|
||||||
|
- {
|
||||||
|
- tmp = (char *) __mempcpy (tmp, b1, s);
|
||||||
|
- b1 += s;
|
||||||
|
- --n1;
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- tmp = (char *) __mempcpy (tmp, b2, s);
|
||||||
|
- b2 += s;
|
||||||
|
- --n2;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if (n1 > 0)
|
||||||
|
- memcpy (tmp, b1, n1 * s);
|
||||||
|
- memcpy (b, p->t, (n - n2) * s);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-void
|
||||||
|
-__qsort_r (void *b, size_t n, size_t s, __compar_d_fn_t cmp, void *arg)
|
||||||
|
-{
|
||||||
|
- size_t size = n * s;
|
||||||
|
- char *tmp = NULL;
|
||||||
|
- struct msort_param p;
|
||||||
|
-
|
||||||
|
- /* For large object sizes use indirect sorting. */
|
||||||
|
- if (s > 32)
|
||||||
|
- size = 2 * n * sizeof (void *) + s;
|
||||||
|
-
|
||||||
|
- if (size < 1024)
|
||||||
|
- /* The temporary array is small, so put it on the stack. */
|
||||||
|
- p.t = __alloca (size);
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- /* We should avoid allocating too much memory since this might
|
||||||
|
- have to be backed up by swap space. */
|
||||||
|
- static long int phys_pages;
|
||||||
|
- static int pagesize;
|
||||||
|
-
|
||||||
|
- if (pagesize == 0)
|
||||||
|
- {
|
||||||
|
- phys_pages = __sysconf (_SC_PHYS_PAGES);
|
||||||
|
-
|
||||||
|
- if (phys_pages == -1)
|
||||||
|
- /* Error while determining the memory size. So let's
|
||||||
|
- assume there is enough memory. Otherwise the
|
||||||
|
- implementer should provide a complete implementation of
|
||||||
|
- the `sysconf' function. */
|
||||||
|
- phys_pages = (long int) (~0ul >> 1);
|
||||||
|
-
|
||||||
|
- /* The following determines that we will never use more than
|
||||||
|
- a quarter of the physical memory. */
|
||||||
|
- phys_pages /= 4;
|
||||||
|
-
|
||||||
|
- /* Make sure phys_pages is written to memory. */
|
||||||
|
- atomic_write_barrier ();
|
||||||
|
-
|
||||||
|
- pagesize = __sysconf (_SC_PAGESIZE);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* Just a comment here. We cannot compute
|
||||||
|
- phys_pages * pagesize
|
||||||
|
- and compare the needed amount of memory against this value.
|
||||||
|
- The problem is that some systems might have more physical
|
||||||
|
- memory then can be represented with a `size_t' value (when
|
||||||
|
- measured in bytes. */
|
||||||
|
-
|
||||||
|
- /* If the memory requirements are too high don't allocate memory. */
|
||||||
|
- if (size / pagesize > (size_t) phys_pages)
|
||||||
|
- {
|
||||||
|
- _quicksort (b, n, s, cmp, arg);
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* It's somewhat large, so malloc it. */
|
||||||
|
- int save = errno;
|
||||||
|
- tmp = malloc (size);
|
||||||
|
- __set_errno (save);
|
||||||
|
- if (tmp == NULL)
|
||||||
|
- {
|
||||||
|
- /* Couldn't get space, so use the slower algorithm
|
||||||
|
- that doesn't need a temporary array. */
|
||||||
|
- _quicksort (b, n, s, cmp, arg);
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
- p.t = tmp;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- p.s = s;
|
||||||
|
- p.var = 4;
|
||||||
|
- p.cmp = cmp;
|
||||||
|
- p.arg = arg;
|
||||||
|
-
|
||||||
|
- if (s > 32)
|
||||||
|
- {
|
||||||
|
- /* Indirect sorting. */
|
||||||
|
- char *ip = (char *) b;
|
||||||
|
- void **tp = (void **) (p.t + n * sizeof (void *));
|
||||||
|
- void **t = tp;
|
||||||
|
- void *tmp_storage = (void *) (tp + n);
|
||||||
|
-
|
||||||
|
- while ((void *) t < tmp_storage)
|
||||||
|
- {
|
||||||
|
- *t++ = ip;
|
||||||
|
- ip += s;
|
||||||
|
- }
|
||||||
|
- p.s = sizeof (void *);
|
||||||
|
- p.var = 3;
|
||||||
|
- msort_with_tmp (&p, p.t + n * sizeof (void *), n);
|
||||||
|
-
|
||||||
|
- /* tp[0] .. tp[n - 1] is now sorted, copy around entries of
|
||||||
|
- the original array. Knuth vol. 3 (2nd ed.) exercise 5.2-10. */
|
||||||
|
- char *kp;
|
||||||
|
- size_t i;
|
||||||
|
- for (i = 0, ip = (char *) b; i < n; i++, ip += s)
|
||||||
|
- if ((kp = tp[i]) != ip)
|
||||||
|
- {
|
||||||
|
- size_t j = i;
|
||||||
|
- char *jp = ip;
|
||||||
|
- memcpy (tmp_storage, ip, s);
|
||||||
|
-
|
||||||
|
- do
|
||||||
|
- {
|
||||||
|
- size_t k = (kp - (char *) b) / s;
|
||||||
|
- tp[j] = jp;
|
||||||
|
- memcpy (jp, kp, s);
|
||||||
|
- j = k;
|
||||||
|
- jp = kp;
|
||||||
|
- kp = tp[k];
|
||||||
|
- }
|
||||||
|
- while (kp != ip);
|
||||||
|
-
|
||||||
|
- tp[j] = jp;
|
||||||
|
- memcpy (jp, tmp_storage, s);
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- if ((s & (sizeof (uint32_t) - 1)) == 0
|
||||||
|
- && ((char *) b - (char *) 0) % __alignof__ (uint32_t) == 0)
|
||||||
|
- {
|
||||||
|
- if (s == sizeof (uint32_t))
|
||||||
|
- p.var = 0;
|
||||||
|
- else if (s == sizeof (uint64_t)
|
||||||
|
- && ((char *) b - (char *) 0) % __alignof__ (uint64_t) == 0)
|
||||||
|
- p.var = 1;
|
||||||
|
- else if ((s & (sizeof (unsigned long) - 1)) == 0
|
||||||
|
- && ((char *) b - (char *) 0)
|
||||||
|
- % __alignof__ (unsigned long) == 0)
|
||||||
|
- p.var = 2;
|
||||||
|
- }
|
||||||
|
- msort_with_tmp (&p, b, n);
|
||||||
|
- }
|
||||||
|
- free (tmp);
|
||||||
|
-}
|
||||||
|
-libc_hidden_def (__qsort_r)
|
||||||
|
-weak_alias (__qsort_r, qsort_r)
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-void
|
||||||
|
-qsort (void *b, size_t n, size_t s, __compar_fn_t cmp)
|
||||||
|
-{
|
||||||
|
- return __qsort_r (b, n, s, (__compar_d_fn_t) cmp, NULL);
|
||||||
|
-}
|
||||||
|
-libc_hidden_def (qsort)
|
||||||
|
diff --git a/stdlib/qsort.c b/stdlib/qsort.c
|
||||||
|
index db299eb333cf0302..cb1619aa0ae7de72 100644
|
||||||
|
--- a/stdlib/qsort.c
|
||||||
|
+++ b/stdlib/qsort.c
|
||||||
|
@@ -20,7 +20,6 @@
|
||||||
|
Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
|
||||||
|
Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */
|
||||||
|
|
||||||
|
-#include <alloca.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <memswap.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
@@ -266,8 +265,8 @@ insertion_sort_qsort_partitions (void *const pbase, size_t total_elems,
|
||||||
|
stack size is needed (actually O(1) in this case)! */
|
||||||
|
|
||||||
|
void
|
||||||
|
-_quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
- __compar_d_fn_t cmp, void *arg)
|
||||||
|
+__qsort_r (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
+ __compar_d_fn_t cmp, void *arg)
|
||||||
|
{
|
||||||
|
char *base_ptr = (char *) pbase;
|
||||||
|
|
||||||
|
@@ -399,3 +398,12 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
|
||||||
|
insertion_sort_qsort_partitions (pbase, total_elems, size, swap_type, cmp,
|
||||||
|
arg);
|
||||||
|
}
|
||||||
|
+libc_hidden_def (__qsort_r)
|
||||||
|
+weak_alias (__qsort_r, qsort_r)
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+qsort (void *b, size_t n, size_t s, __compar_fn_t cmp)
|
||||||
|
+{
|
||||||
|
+ return __qsort_r (b, n, s, (__compar_d_fn_t) cmp, NULL);
|
||||||
|
+}
|
||||||
|
+libc_hidden_def (qsort)
|
||||||
399
SOURCES/glibc-RHEL-24168-9.patch
Normal file
399
SOURCES/glibc-RHEL-24168-9.patch
Normal file
@ -0,0 +1,399 @@
|
|||||||
|
commit bc888a3976700a3607f6ec4a36dbf3030161cb3e
|
||||||
|
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
Date: Tue Oct 3 09:22:51 2023 -0300
|
||||||
|
|
||||||
|
stdlib: Add more qsort{_r} coverage
|
||||||
|
|
||||||
|
This patch adds a qsort and qsort_r to trigger the worst case
|
||||||
|
scenario for the quicksort (which glibc current lacks coverage).
|
||||||
|
The test is done with random input, dfferent internal types (uint8_t,
|
||||||
|
uint16_t, uint32_t, uint64_t, large size), and with
|
||||||
|
different set of element numbers.
|
||||||
|
|
||||||
|
Checked on x86_64-linux-gnu and i686-linux-gnu.
|
||||||
|
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
|
||||||
|
|
||||||
|
diff --git a/stdlib/Makefile b/stdlib/Makefile
|
||||||
|
index 3b89bc2aa0307321..4039e5395eeea2b0 100644
|
||||||
|
--- a/stdlib/Makefile
|
||||||
|
+++ b/stdlib/Makefile
|
||||||
|
@@ -211,6 +211,7 @@ tests := \
|
||||||
|
tst-on_exit \
|
||||||
|
tst-qsort \
|
||||||
|
tst-qsort2 \
|
||||||
|
+ tst-qsort3 \
|
||||||
|
tst-quick_exit \
|
||||||
|
tst-rand48 \
|
||||||
|
tst-rand48-2 \
|
||||||
|
diff --git a/stdlib/tst-qsort3.c b/stdlib/tst-qsort3.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..421560d74434a116
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdlib/tst-qsort3.c
|
||||||
|
@@ -0,0 +1,366 @@
|
||||||
|
+/* qsort(_r) tests to trigger worst case for quicksort.
|
||||||
|
+ Copyright (C) 2023 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
|
||||||
|
+ <http://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <array_length.h>
|
||||||
|
+#include <errno.h>
|
||||||
|
+#include <getopt.h>
|
||||||
|
+#include <stdbool.h>
|
||||||
|
+#include <stdint.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/support.h>
|
||||||
|
+#include <support/test-driver.h>
|
||||||
|
+
|
||||||
|
+typedef enum
|
||||||
|
+{
|
||||||
|
+ Sorted,
|
||||||
|
+ Random,
|
||||||
|
+ Repeated,
|
||||||
|
+ Bitonic,
|
||||||
|
+ Duplicated,
|
||||||
|
+} arraytype_t;
|
||||||
|
+
|
||||||
|
+/* Ratio of total of elements which will be repeated. */
|
||||||
|
+static const double RepeatedRatio = 0.2;
|
||||||
|
+
|
||||||
|
+/* Ratio of duplicated element . */
|
||||||
|
+static const double DuplicatedRatio = 0.4;
|
||||||
|
+
|
||||||
|
+struct array_t
|
||||||
|
+{
|
||||||
|
+ arraytype_t type;
|
||||||
|
+ const char *name;
|
||||||
|
+} static const arraytypes[] =
|
||||||
|
+{
|
||||||
|
+ { Sorted, "Sorted" },
|
||||||
|
+ { Random, "Random" },
|
||||||
|
+ { Repeated, "Repeated" },
|
||||||
|
+ { Bitonic, "Bitonic" },
|
||||||
|
+ { Duplicated, "Duplicated" },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/* Return the index of BASE as interpreted as an array of elements
|
||||||
|
+ of size SIZE. */
|
||||||
|
+static inline void *
|
||||||
|
+arr (void *base, size_t idx, size_t size)
|
||||||
|
+{
|
||||||
|
+ return (void*)((uintptr_t)base + (idx * size));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Functions used to check qsort. */
|
||||||
|
+static int
|
||||||
|
+uint8_t_cmp (const void *a, const void *b)
|
||||||
|
+{
|
||||||
|
+ uint8_t ia = *(uint8_t*)a;
|
||||||
|
+ uint8_t ib = *(uint8_t*)b;
|
||||||
|
+ return (ia > ib) - (ia < ib);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+uint16_t_cmp (const void *a, const void *b)
|
||||||
|
+{
|
||||||
|
+ uint16_t ia = *(uint16_t*)a;
|
||||||
|
+ uint16_t ib = *(uint16_t*)b;
|
||||||
|
+ return (ia > ib) - (ia < ib);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+uint32_t_cmp (const void *a, const void *b)
|
||||||
|
+{
|
||||||
|
+ uint32_t ia = *(uint32_t*)a;
|
||||||
|
+ uint32_t ib = *(uint32_t*)b;
|
||||||
|
+ return (ia > ib) - (ia < ib);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+uint64_t_cmp (const void *a, const void *b)
|
||||||
|
+{
|
||||||
|
+ uint64_t ia = *(uint64_t*)a;
|
||||||
|
+ uint64_t ib = *(uint64_t*)b;
|
||||||
|
+ return (ia > ib) - (ia < ib);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#define LARGE_SIZE 47
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+large_cmp (const void *a, const void *b)
|
||||||
|
+{
|
||||||
|
+ return memcmp (a, b, LARGE_SIZE);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Function used to check qsort_r. */
|
||||||
|
+typedef enum
|
||||||
|
+{
|
||||||
|
+ UINT8_CMP_T,
|
||||||
|
+ UINT16_CMP_T,
|
||||||
|
+ UINT32_CMP_T,
|
||||||
|
+ UINT64_CMP_T,
|
||||||
|
+ LARGE_CMP_T
|
||||||
|
+} type_cmp_t;
|
||||||
|
+
|
||||||
|
+static type_cmp_t
|
||||||
|
+uint_t_cmp_type (size_t sz)
|
||||||
|
+{
|
||||||
|
+ switch (sz)
|
||||||
|
+ {
|
||||||
|
+ case sizeof (uint8_t): return UINT8_CMP_T;
|
||||||
|
+ case sizeof (uint16_t): return UINT16_CMP_T;
|
||||||
|
+ case sizeof (uint64_t): return UINT64_CMP_T;
|
||||||
|
+ case sizeof (uint32_t): return UINT32_CMP_T;
|
||||||
|
+ default: return LARGE_CMP_T;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+uint_t_cmp (const void *a, const void *b, void *arg)
|
||||||
|
+{
|
||||||
|
+ type_cmp_t type = *(type_cmp_t*) arg;
|
||||||
|
+ switch (type)
|
||||||
|
+ {
|
||||||
|
+ case UINT8_CMP_T: return uint8_t_cmp (a, b);
|
||||||
|
+ case UINT32_CMP_T: return uint32_t_cmp (a, b);
|
||||||
|
+ case UINT16_CMP_T: return uint16_t_cmp (a, b);
|
||||||
|
+ case UINT64_CMP_T: return uint64_t_cmp (a, b);
|
||||||
|
+ default: return large_cmp (a, b);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+seq (void *elem, size_t type_size, int value)
|
||||||
|
+{
|
||||||
|
+ if (type_size == sizeof (uint8_t))
|
||||||
|
+ *(uint8_t*)elem = value;
|
||||||
|
+ else if (type_size == sizeof (uint16_t))
|
||||||
|
+ *(uint16_t*)elem = value;
|
||||||
|
+ else if (type_size == sizeof (uint32_t))
|
||||||
|
+ *(uint32_t*)elem = value;
|
||||||
|
+ else if (type_size == sizeof (uint64_t))
|
||||||
|
+ *(uint64_t*)elem = value;
|
||||||
|
+ else
|
||||||
|
+ memset (elem, value, type_size);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+fill_array (void *array, void *refarray, size_t nmemb, size_t type_size,
|
||||||
|
+ arraytype_t type)
|
||||||
|
+{
|
||||||
|
+ size_t size = nmemb * type_size;
|
||||||
|
+
|
||||||
|
+ switch (type)
|
||||||
|
+ {
|
||||||
|
+ case Sorted:
|
||||||
|
+ for (size_t i = 0; i < nmemb; i++)
|
||||||
|
+ seq (arr (array, i, type_size), type_size, i);
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case Random:
|
||||||
|
+ arc4random_buf (array, size);
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case Repeated:
|
||||||
|
+ {
|
||||||
|
+ arc4random_buf (array, size);
|
||||||
|
+
|
||||||
|
+ void *randelem = xmalloc (type_size);
|
||||||
|
+ arc4random_buf (randelem, type_size);
|
||||||
|
+
|
||||||
|
+ /* Repeat REPEATED elements (based on RepeatRatio ratio) in the random
|
||||||
|
+ array. */
|
||||||
|
+ size_t repeated = (size_t)(nmemb * RepeatedRatio);
|
||||||
|
+ for (size_t i = 0; i < repeated; i++)
|
||||||
|
+ {
|
||||||
|
+ size_t pos = arc4random_uniform (nmemb - 1);
|
||||||
|
+ memcpy (arr (array, pos, type_size), randelem, type_size);
|
||||||
|
+ }
|
||||||
|
+ free (randelem);
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case Bitonic:
|
||||||
|
+ {
|
||||||
|
+ size_t i;
|
||||||
|
+ for (i = 0; i < nmemb / 2; i++)
|
||||||
|
+ seq (arr (array, i, type_size), type_size, i);
|
||||||
|
+ for ( ; i < nmemb; i++)
|
||||||
|
+ seq (arr (array, i, type_size), type_size, (nmemb - 1) - i);
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case Duplicated:
|
||||||
|
+ {
|
||||||
|
+ int randelem1 = arc4random ();
|
||||||
|
+ for (size_t i = 0; i < nmemb; i++)
|
||||||
|
+ seq (arr (array, i, type_size), type_size, randelem1);
|
||||||
|
+
|
||||||
|
+ size_t duplicates = (size_t)(nmemb * DuplicatedRatio);
|
||||||
|
+ int randelem2 = arc4random ();
|
||||||
|
+ for (size_t i = 0; i < duplicates; i++)
|
||||||
|
+ {
|
||||||
|
+ size_t pos = arc4random_uniform (nmemb - 1);
|
||||||
|
+ seq (arr (array, pos, type_size), type_size, randelem2);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ memcpy (refarray, array, size);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+typedef int (*cmpfunc_t)(const void *, const void *);
|
||||||
|
+
|
||||||
|
+/* Simple insertion sort to use as reference sort. */
|
||||||
|
+static void
|
||||||
|
+qsort_r_ref (void *p, size_t n, size_t s, __compar_d_fn_t cmp, void *arg)
|
||||||
|
+{
|
||||||
|
+ if (n <= 1)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ int i = 1;
|
||||||
|
+ char tmp[s];
|
||||||
|
+ while (i < n)
|
||||||
|
+ {
|
||||||
|
+ memcpy (tmp, arr (p, i, s), s);
|
||||||
|
+ int j = i - 1;
|
||||||
|
+ while (j >= 0 && cmp (arr (p, j, s), tmp, arg) > 0)
|
||||||
|
+ {
|
||||||
|
+ memcpy (arr (p, j + 1, s), arr (p, j, s), s);
|
||||||
|
+ j = j - 1;
|
||||||
|
+ }
|
||||||
|
+ memcpy (arr (p, j + 1, s), tmp, s);
|
||||||
|
+ i = i + 1;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+qsort_ref (void *b, size_t n, size_t s, __compar_fn_t cmp)
|
||||||
|
+{
|
||||||
|
+ return qsort_r_ref (b, n, s, (__compar_d_fn_t) cmp, NULL);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Check if ARRAY of total NMEMB element of size SIZE is sorted
|
||||||
|
+ based on CMPFUNC. */
|
||||||
|
+static void
|
||||||
|
+check_array (void *array, void *refarray, size_t nmemb, size_t type_size,
|
||||||
|
+ cmpfunc_t cmpfunc)
|
||||||
|
+{
|
||||||
|
+ for (size_t i = 1; i < nmemb; i++)
|
||||||
|
+ {
|
||||||
|
+ int ret = cmpfunc (arr (array, i, type_size),
|
||||||
|
+ arr (array, i-1, type_size));
|
||||||
|
+ TEST_VERIFY_EXIT (ret >= 0);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ size_t size = nmemb * type_size;
|
||||||
|
+ TEST_COMPARE_BLOB (array, size, refarray, size);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+check_qsort (void *buf, void *refbuf, size_t nelem, size_t type_size,
|
||||||
|
+ arraytype_t type, cmpfunc_t cmpfunc)
|
||||||
|
+{
|
||||||
|
+ fill_array (buf, refbuf, nelem, type_size, type);
|
||||||
|
+
|
||||||
|
+ qsort (buf, nelem, type_size, cmpfunc);
|
||||||
|
+ qsort_ref (refbuf, nelem, type_size, cmpfunc);
|
||||||
|
+
|
||||||
|
+ check_array (buf, refbuf, nelem, type_size, cmpfunc);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+check_qsort_r (void *buf, void *refbuf, size_t nelem, size_t type_size,
|
||||||
|
+ arraytype_t type, cmpfunc_t cmpfunc)
|
||||||
|
+{
|
||||||
|
+ fill_array (buf, refbuf, nelem, type_size, type);
|
||||||
|
+
|
||||||
|
+ type_cmp_t typecmp = uint_t_cmp_type (type_size);
|
||||||
|
+
|
||||||
|
+ qsort_r (buf, nelem, type_size, uint_t_cmp, &typecmp);
|
||||||
|
+ qsort_r_ref (refbuf, nelem, type_size, uint_t_cmp, &typecmp);
|
||||||
|
+
|
||||||
|
+ check_array (buf, refbuf, nelem, type_size, cmpfunc);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ /* Some random sizes. */
|
||||||
|
+ static const size_t nelems[] = { 0, 1, 7, 20, 32, 100, 256, 1024, 4256 };
|
||||||
|
+ size_t max_nelems = 0;
|
||||||
|
+ for (int i = 0; i < array_length (nelems); i++)
|
||||||
|
+ if (nelems[i] > max_nelems)
|
||||||
|
+ max_nelems = nelems[i];
|
||||||
|
+
|
||||||
|
+ static const struct test_t
|
||||||
|
+ {
|
||||||
|
+ size_t type_size;
|
||||||
|
+ cmpfunc_t cmpfunc;
|
||||||
|
+ }
|
||||||
|
+ tests[] =
|
||||||
|
+ {
|
||||||
|
+ { sizeof (uint8_t), uint8_t_cmp },
|
||||||
|
+ { sizeof (uint16_t), uint16_t_cmp },
|
||||||
|
+ { sizeof (uint32_t), uint32_t_cmp },
|
||||||
|
+ { sizeof (uint64_t), uint64_t_cmp },
|
||||||
|
+ /* Test swap with large elements. */
|
||||||
|
+ { LARGE_SIZE, large_cmp },
|
||||||
|
+ };
|
||||||
|
+ size_t max_type_size = 0;
|
||||||
|
+ for (int i = 0; i < array_length (tests); i++)
|
||||||
|
+ if (tests[i].type_size > max_type_size)
|
||||||
|
+ max_type_size = tests[i].type_size;
|
||||||
|
+
|
||||||
|
+ void *buf = reallocarray (NULL, max_nelems, max_type_size);
|
||||||
|
+ TEST_VERIFY_EXIT (buf != NULL);
|
||||||
|
+ void *refbuf = reallocarray (NULL, max_nelems, max_type_size);
|
||||||
|
+ TEST_VERIFY_EXIT (refbuf != NULL);
|
||||||
|
+
|
||||||
|
+ for (const struct test_t *test = tests; test < array_end (tests); ++test)
|
||||||
|
+ {
|
||||||
|
+ if (test_verbose > 0)
|
||||||
|
+ printf ("info: testing qsort with type_size=%zu\n", test->type_size);
|
||||||
|
+ for (const struct array_t *arraytype = arraytypes;
|
||||||
|
+ arraytype < array_end (arraytypes);
|
||||||
|
+ ++arraytype)
|
||||||
|
+ {
|
||||||
|
+ if (test_verbose > 0)
|
||||||
|
+ printf (" distribution=%s\n", arraytype->name);
|
||||||
|
+ for (const size_t *nelem = nelems;
|
||||||
|
+ nelem < array_end (nelems);
|
||||||
|
+ ++nelem)
|
||||||
|
+ {
|
||||||
|
+ if (test_verbose > 0)
|
||||||
|
+ printf (" nelem=%zu, total size=%zu\n", *nelem,
|
||||||
|
+ *nelem * test->type_size);
|
||||||
|
+
|
||||||
|
+ check_qsort (buf, refbuf, *nelem, test->type_size,
|
||||||
|
+ arraytype->type, test->cmpfunc);
|
||||||
|
+ check_qsort_r (buf, refbuf, *nelem, test->type_size,
|
||||||
|
+ arraytype->type, test->cmpfunc);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ free (buf);
|
||||||
|
+ free (refbuf);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
45
SOURCES/glibc-RHEL-28119.patch
Normal file
45
SOURCES/glibc-RHEL-28119.patch
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
commit 7a76f218677d149d8b7875b336722108239f7ee9
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Mar 15 19:08:24 2024 +0100
|
||||||
|
|
||||||
|
linux: Use rseq area unconditionally in sched_getcpu (bug 31479)
|
||||||
|
|
||||||
|
Originally, nptl/descr.h included <sys/rseq.h>, but we removed that
|
||||||
|
in commit 2c6b4b272e6b4d07303af25709051c3e96288f2d ("nptl:
|
||||||
|
Unconditionally use a 32-byte rseq area"). After that, it was
|
||||||
|
not ensured that the RSEQ_SIG macro was defined during sched_getcpu.c
|
||||||
|
compilation that provided a definition. This commit always checks
|
||||||
|
the rseq area for CPU number information before using the other
|
||||||
|
approaches.
|
||||||
|
|
||||||
|
This adds an unnecessary (but well-predictable) branch on
|
||||||
|
architectures which do not define RSEQ_SIG, but its cost is small
|
||||||
|
compared to the system call. Most architectures that have vDSO
|
||||||
|
acceleration for getcpu also have rseq support.
|
||||||
|
|
||||||
|
Fixes: 2c6b4b272e6b4d07303af25709051c3e96288f2d
|
||||||
|
Fixes: 1d350aa06091211863e41169729cee1bca39f72f
|
||||||
|
Reviewed-by: Arjun Shankar <arjun@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/sysdeps/unix/sysv/linux/sched_getcpu.c b/sysdeps/unix/sysv/linux/sched_getcpu.c
|
||||||
|
index 6f78edaea1495342..a33e30a1cb8e161b 100644
|
||||||
|
--- a/sysdeps/unix/sysv/linux/sched_getcpu.c
|
||||||
|
+++ b/sysdeps/unix/sysv/linux/sched_getcpu.c
|
||||||
|
@@ -33,17 +33,9 @@ vsyscall_sched_getcpu (void)
|
||||||
|
return r == -1 ? r : cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
-#ifdef RSEQ_SIG
|
||||||
|
int
|
||||||
|
sched_getcpu (void)
|
||||||
|
{
|
||||||
|
int cpu_id = THREAD_GETMEM_VOLATILE (THREAD_SELF, rseq_area.cpu_id);
|
||||||
|
return __glibc_likely (cpu_id >= 0) ? cpu_id : vsyscall_sched_getcpu ();
|
||||||
|
}
|
||||||
|
-#else /* RSEQ_SIG */
|
||||||
|
-int
|
||||||
|
-sched_getcpu (void)
|
||||||
|
-{
|
||||||
|
- return vsyscall_sched_getcpu ();
|
||||||
|
-}
|
||||||
|
-#endif /* RSEQ_SIG */
|
||||||
135
SOURCES/glibc-RHEL-44920-1.patch
Normal file
135
SOURCES/glibc-RHEL-44920-1.patch
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
commit 4e4641164d2722d622a1bf3b5e4583538d9c7227
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Mon Apr 17 15:41:08 2023 +0200
|
||||||
|
|
||||||
|
debug: Re-flow and sort routines variable in Makefile
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
debug/Makefile (fixed context)
|
||||||
|
|
||||||
|
diff --git a/debug/Makefile b/debug/Makefile
|
||||||
|
index 63395fc626610a53..c19c76e2b8564bd2 100644
|
||||||
|
--- a/debug/Makefile
|
||||||
|
+++ b/debug/Makefile
|
||||||
|
@@ -28,31 +28,94 @@ headers := execinfo.h
|
||||||
|
# Note that ptsname_r_chk and getlogin_r are not here, but in
|
||||||
|
# login/Makefile instead. If that subdir is omitted from the
|
||||||
|
# build, its _FORTIFY_SOURCE support will be too.
|
||||||
|
-routines = backtrace backtracesyms backtracesymsfd noophooks \
|
||||||
|
- memcpy_chk memmove_chk mempcpy_chk memset_chk stpcpy_chk \
|
||||||
|
- strcat_chk strcpy_chk strncat_chk strncpy_chk stpncpy_chk \
|
||||||
|
- sprintf_chk vsprintf_chk snprintf_chk vsnprintf_chk \
|
||||||
|
- printf_chk fprintf_chk vprintf_chk vfprintf_chk \
|
||||||
|
- gets_chk chk_fail readonly-area fgets_chk fgets_u_chk \
|
||||||
|
- read_chk pread_chk pread64_chk recv_chk recvfrom_chk \
|
||||||
|
- readlink_chk readlinkat_chk getwd_chk getcwd_chk \
|
||||||
|
- realpath_chk fread_chk fread_u_chk \
|
||||||
|
- wctomb_chk wcscpy_chk wmemcpy_chk wmemmove_chk wmempcpy_chk \
|
||||||
|
- wcpcpy_chk wcsncpy_chk wcscat_chk wcsncat_chk wmemset_chk \
|
||||||
|
- wcpncpy_chk \
|
||||||
|
- swprintf_chk vswprintf_chk wprintf_chk fwprintf_chk \
|
||||||
|
- vwprintf_chk vfwprintf_chk fgetws_chk fgetws_u_chk \
|
||||||
|
- confstr_chk getgroups_chk ttyname_r_chk \
|
||||||
|
- gethostname_chk getdomainname_chk wcrtomb_chk mbsnrtowcs_chk \
|
||||||
|
- wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \
|
||||||
|
- wcstombs_chk asprintf_chk vasprintf_chk dprintf_chk \
|
||||||
|
- vdprintf_chk obprintf_chk vobprintf_chk \
|
||||||
|
- longjmp_chk ____longjmp_chk \
|
||||||
|
- fdelt_chk poll_chk ppoll_chk \
|
||||||
|
- explicit_bzero_chk \
|
||||||
|
- stack_chk_fail fortify_fail \
|
||||||
|
- readonly-area-fallback \
|
||||||
|
- $(static-only-routines)
|
||||||
|
+routines = \
|
||||||
|
+ ____longjmp_chk \
|
||||||
|
+ asprintf_chk \
|
||||||
|
+ backtrace \
|
||||||
|
+ backtracesyms \
|
||||||
|
+ backtracesymsfd \
|
||||||
|
+ chk_fail \
|
||||||
|
+ confstr_chk \
|
||||||
|
+ dprintf_chk \
|
||||||
|
+ explicit_bzero_chk \
|
||||||
|
+ fdelt_chk \
|
||||||
|
+ fgets_chk \
|
||||||
|
+ fgets_u_chk \
|
||||||
|
+ fgetws_chk \
|
||||||
|
+ fgetws_u_chk \
|
||||||
|
+ fortify_fail \
|
||||||
|
+ fprintf_chk \
|
||||||
|
+ fread_chk \
|
||||||
|
+ fread_u_chk \
|
||||||
|
+ fwprintf_chk \
|
||||||
|
+ getcwd_chk \
|
||||||
|
+ getdomainname_chk \
|
||||||
|
+ getgroups_chk \
|
||||||
|
+ gethostname_chk \
|
||||||
|
+ gets_chk \
|
||||||
|
+ getwd_chk \
|
||||||
|
+ longjmp_chk \
|
||||||
|
+ mbsnrtowcs_chk \
|
||||||
|
+ mbsrtowcs_chk \
|
||||||
|
+ mbstowcs_chk \
|
||||||
|
+ memcpy_chk \
|
||||||
|
+ memmove_chk \
|
||||||
|
+ mempcpy_chk \
|
||||||
|
+ memset_chk \
|
||||||
|
+ noophooks \
|
||||||
|
+ obprintf_chk \
|
||||||
|
+ poll_chk \
|
||||||
|
+ ppoll_chk \
|
||||||
|
+ pread64_chk \
|
||||||
|
+ pread_chk \
|
||||||
|
+ printf_chk \
|
||||||
|
+ read_chk \
|
||||||
|
+ readlink_chk \
|
||||||
|
+ readlinkat_chk \
|
||||||
|
+ readonly-area \
|
||||||
|
+ readonly-area-fallback \
|
||||||
|
+ realpath_chk \
|
||||||
|
+ recv_chk \
|
||||||
|
+ recvfrom_chk \
|
||||||
|
+ snprintf_chk \
|
||||||
|
+ sprintf_chk \
|
||||||
|
+ stack_chk_fail \
|
||||||
|
+ stpcpy_chk \
|
||||||
|
+ stpncpy_chk \
|
||||||
|
+ strcat_chk \
|
||||||
|
+ strcpy_chk \
|
||||||
|
+ strncat_chk \
|
||||||
|
+ strncpy_chk \
|
||||||
|
+ swprintf_chk \
|
||||||
|
+ ttyname_r_chk \
|
||||||
|
+ vasprintf_chk \
|
||||||
|
+ vdprintf_chk \
|
||||||
|
+ vfprintf_chk \
|
||||||
|
+ vfwprintf_chk \
|
||||||
|
+ vobprintf_chk \
|
||||||
|
+ vprintf_chk \
|
||||||
|
+ vsnprintf_chk \
|
||||||
|
+ vsprintf_chk \
|
||||||
|
+ vswprintf_chk \
|
||||||
|
+ vwprintf_chk \
|
||||||
|
+ wcpcpy_chk \
|
||||||
|
+ wcpncpy_chk \
|
||||||
|
+ wcrtomb_chk \
|
||||||
|
+ wcscat_chk \
|
||||||
|
+ wcscpy_chk \
|
||||||
|
+ wcsncat_chk \
|
||||||
|
+ wcsncpy_chk \
|
||||||
|
+ wcsnrtombs_chk \
|
||||||
|
+ wcsrtombs_chk \
|
||||||
|
+ wcstombs_chk \
|
||||||
|
+ wctomb_chk \
|
||||||
|
+ wmemcpy_chk \
|
||||||
|
+ wmemmove_chk \
|
||||||
|
+ wmempcpy_chk \
|
||||||
|
+ wmemset_chk \
|
||||||
|
+ wprintf_chk \
|
||||||
|
+ $(static-only-routines)
|
||||||
|
+ # routines
|
||||||
|
static-only-routines := stack_chk_fail_local
|
||||||
|
|
||||||
|
# Don't add stack_chk_fail_local.o to libc.a since __stack_chk_fail_local
|
||||||
168
SOURCES/glibc-RHEL-44920-2.patch
Normal file
168
SOURCES/glibc-RHEL-44920-2.patch
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
commit b6b8a88cf59a00d7716e9dd2e5ba92eedfec69ce
|
||||||
|
Author: Arjun Shankar <arjun@redhat.com>
|
||||||
|
Date: Mon Oct 2 14:55:13 2023 +0200
|
||||||
|
|
||||||
|
inet: Rearrange and sort Makefile variables
|
||||||
|
|
||||||
|
Rearrange lists of routines, tests, etc. into one-per-line in
|
||||||
|
inet/Makefile and sort them using scripts/sort-makefile-lines.py.
|
||||||
|
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||||
|
|
||||||
|
diff --git a/inet/Makefile b/inet/Makefile
|
||||||
|
index cf4cf5cf8ae6732f..b7d6e40fb319f52d 100644
|
||||||
|
--- a/inet/Makefile
|
||||||
|
+++ b/inet/Makefile
|
||||||
|
@@ -22,41 +22,123 @@ subdir := inet
|
||||||
|
|
||||||
|
include ../Makeconfig
|
||||||
|
|
||||||
|
-headers := netinet/ether.h netinet/in.h netinet/in_systm.h \
|
||||||
|
- netinet/if_ether.h netinet/igmp.h \
|
||||||
|
- netinet/tcp.h netinet/ip.h $(wildcard arpa/*.h protocols/*.h) \
|
||||||
|
- aliases.h ifaddrs.h netinet/ip6.h netinet/icmp6.h bits/in.h \
|
||||||
|
- rpc/netdb.h
|
||||||
|
-
|
||||||
|
-routines := htonl htons \
|
||||||
|
- inet_lnaof inet_mkadr \
|
||||||
|
- inet_netof inet_ntoa inet_net herrno herrno-loc \
|
||||||
|
- gethstbyad gethstbyad_r gethstbynm gethstbynm2 gethstbynm2_r \
|
||||||
|
- gethstbynm_r gethstent gethstent_r \
|
||||||
|
- getnetbyad getnetbyad_r getnetbynm getnetent getnetent_r \
|
||||||
|
- getnetbynm_r \
|
||||||
|
- getproto getproto_r getprtent getprtent_r getprtname getprtname_r \
|
||||||
|
- getsrvbynm getsrvbynm_r getsrvbypt getsrvbypt_r getservent \
|
||||||
|
- getservent_r getrpcent getrpcbyname getrpcbynumber \
|
||||||
|
- getrpcent_r getrpcbyname_r getrpcbynumber_r \
|
||||||
|
- ether_aton ether_aton_r ether_hton ether_line \
|
||||||
|
- ether_ntoa ether_ntoa_r ether_ntoh \
|
||||||
|
- rcmd rexec ruserpass bindresvport \
|
||||||
|
- getnetgrent_r getnetgrent \
|
||||||
|
- getaliasent_r getaliasent getaliasname getaliasname_r \
|
||||||
|
- in6_addr getnameinfo if_index ifaddrs inet6_option \
|
||||||
|
- getipv4sourcefilter setipv4sourcefilter \
|
||||||
|
- getsourcefilter setsourcefilter inet6_opt inet6_rth \
|
||||||
|
- inet6_scopeid_pton deadline idna idna_name_classify
|
||||||
|
+headers := \
|
||||||
|
+ $(wildcard arpa/*.h protocols/*.h) \
|
||||||
|
+ aliases.h \
|
||||||
|
+ bits/in.h \
|
||||||
|
+ ifaddrs.h \
|
||||||
|
+ netinet/ether.h \
|
||||||
|
+ netinet/icmp6.h \
|
||||||
|
+ netinet/if_ether.h \
|
||||||
|
+ netinet/igmp.h \
|
||||||
|
+ netinet/in.h \
|
||||||
|
+ netinet/in_systm.h \
|
||||||
|
+ netinet/ip.h \
|
||||||
|
+ netinet/ip6.h \
|
||||||
|
+ netinet/tcp.h \
|
||||||
|
+ rpc/netdb.h \
|
||||||
|
+ # headers
|
||||||
|
+
|
||||||
|
+routines := \
|
||||||
|
+ bindresvport \
|
||||||
|
+ deadline \
|
||||||
|
+ ether_aton \
|
||||||
|
+ ether_aton_r \
|
||||||
|
+ ether_hton \
|
||||||
|
+ ether_line \
|
||||||
|
+ ether_ntoa \
|
||||||
|
+ ether_ntoa_r \
|
||||||
|
+ ether_ntoh \
|
||||||
|
+ getaliasent \
|
||||||
|
+ getaliasent_r \
|
||||||
|
+ getaliasname \
|
||||||
|
+ getaliasname_r \
|
||||||
|
+ gethstbyad \
|
||||||
|
+ gethstbyad_r \
|
||||||
|
+ gethstbynm \
|
||||||
|
+ gethstbynm2 \
|
||||||
|
+ gethstbynm2_r \
|
||||||
|
+ gethstbynm_r \
|
||||||
|
+ gethstent \
|
||||||
|
+ gethstent_r \
|
||||||
|
+ getipv4sourcefilter \
|
||||||
|
+ getnameinfo \
|
||||||
|
+ getnetbyad \
|
||||||
|
+ getnetbyad_r \
|
||||||
|
+ getnetbynm \
|
||||||
|
+ getnetbynm_r \
|
||||||
|
+ getnetent \
|
||||||
|
+ getnetent_r \
|
||||||
|
+ getnetgrent \
|
||||||
|
+ getnetgrent_r \
|
||||||
|
+ getproto \
|
||||||
|
+ getproto_r \
|
||||||
|
+ getprtent \
|
||||||
|
+ getprtent_r \
|
||||||
|
+ getprtname \
|
||||||
|
+ getprtname_r \
|
||||||
|
+ getrpcbyname \
|
||||||
|
+ getrpcbyname_r \
|
||||||
|
+ getrpcbynumber \
|
||||||
|
+ getrpcbynumber_r \
|
||||||
|
+ getrpcent \
|
||||||
|
+ getrpcent_r \
|
||||||
|
+ getservent \
|
||||||
|
+ getservent_r \
|
||||||
|
+ getsourcefilter \
|
||||||
|
+ getsrvbynm \
|
||||||
|
+ getsrvbynm_r \
|
||||||
|
+ getsrvbypt \
|
||||||
|
+ getsrvbypt_r \
|
||||||
|
+ herrno \
|
||||||
|
+ herrno-loc \
|
||||||
|
+ htonl \
|
||||||
|
+ htons \
|
||||||
|
+ idna \
|
||||||
|
+ idna_name_classify \
|
||||||
|
+ if_index \
|
||||||
|
+ ifaddrs \
|
||||||
|
+ in6_addr \
|
||||||
|
+ inet6_opt \
|
||||||
|
+ inet6_option \
|
||||||
|
+ inet6_rth \
|
||||||
|
+ inet6_scopeid_pton \
|
||||||
|
+ inet_lnaof \
|
||||||
|
+ inet_mkadr \
|
||||||
|
+ inet_net \
|
||||||
|
+ inet_netof \
|
||||||
|
+ inet_ntoa \
|
||||||
|
+ rcmd \
|
||||||
|
+ rexec \
|
||||||
|
+ ruserpass \
|
||||||
|
+ setipv4sourcefilter \
|
||||||
|
+ setsourcefilter \
|
||||||
|
+ # routines
|
||||||
|
|
||||||
|
install-others = $(inst_sysconfdir)/rpc
|
||||||
|
|
||||||
|
aux := check_pf check_native ifreq
|
||||||
|
|
||||||
|
-tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \
|
||||||
|
- tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \
|
||||||
|
- tst-getni1 tst-getni2 tst-inet6_rth tst-checks tst-checks-posix \
|
||||||
|
- tst-sockaddr test-hnto-types tst-if_index-long
|
||||||
|
+tests := \
|
||||||
|
+ bug-if1 \
|
||||||
|
+ htontest \
|
||||||
|
+ test-hnto-types \
|
||||||
|
+ test-ifaddrs \
|
||||||
|
+ test-inet6_opt \
|
||||||
|
+ test_ifindex \
|
||||||
|
+ tst-checks \
|
||||||
|
+ tst-checks-posix \
|
||||||
|
+ tst-ether_aton \
|
||||||
|
+ tst-ether_line \
|
||||||
|
+ tst-gethnm \
|
||||||
|
+ tst-getni1 \
|
||||||
|
+ tst-getni2 \
|
||||||
|
+ tst-if_index-long \
|
||||||
|
+ tst-inet6_rth \
|
||||||
|
+ tst-network \
|
||||||
|
+ tst-ntoa \
|
||||||
|
+ tst-sockaddr \
|
||||||
|
+ # tests
|
||||||
|
|
||||||
|
# tst-deadline must be linked statically so that we can access
|
||||||
|
# internal functions.
|
||||||
81
SOURCES/glibc-RHEL-44920-3.patch
Normal file
81
SOURCES/glibc-RHEL-44920-3.patch
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
commit 84373ef7b72c9c8ab61ce1fdfd798777715a1a52
|
||||||
|
Author: Frédéric Bérat <fberat@redhat.com>
|
||||||
|
Date: Fri Mar 7 14:42:26 2025 +0100
|
||||||
|
|
||||||
|
Prepare inet_ntop to be fortified
|
||||||
|
|
||||||
|
Rename inet_ntop to __inet_ntop and create the inet_ntop weak alias
|
||||||
|
based on it in order to prepare for disabling fortification when
|
||||||
|
available.
|
||||||
|
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/include/arpa/inet.h b/include/arpa/inet.h
|
||||||
|
index df9472ba3bc52689..d1ea13bb19d4a497 100644
|
||||||
|
--- a/include/arpa/inet.h
|
||||||
|
+++ b/include/arpa/inet.h
|
||||||
|
@@ -5,7 +5,9 @@
|
||||||
|
extern int __inet_aton_exact (const char *__cp, struct in_addr *__inp);
|
||||||
|
libc_hidden_proto (__inet_aton_exact)
|
||||||
|
|
||||||
|
-libc_hidden_proto (inet_ntop)
|
||||||
|
+extern __typeof (inet_ntop) __inet_ntop;
|
||||||
|
+libc_hidden_proto (__inet_ntop)
|
||||||
|
+
|
||||||
|
libc_hidden_proto (inet_pton)
|
||||||
|
extern __typeof (inet_pton) __inet_pton;
|
||||||
|
libc_hidden_proto (__inet_pton)
|
||||||
|
diff --git a/inet/getnameinfo.c b/inet/getnameinfo.c
|
||||||
|
index 8380d8578361b289..d0c6de6ba12b6298 100644
|
||||||
|
--- a/inet/getnameinfo.c
|
||||||
|
+++ b/inet/getnameinfo.c
|
||||||
|
@@ -323,7 +323,7 @@ gni_host_inet_numeric (struct scratch_buffer *tmpbuf,
|
||||||
|
if (sa->sa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
const struct sockaddr_in6 *sin6p = (const struct sockaddr_in6 *) sa;
|
||||||
|
- if (inet_ntop (AF_INET6, &sin6p->sin6_addr, host, hostlen) == NULL)
|
||||||
|
+ if (__inet_ntop (AF_INET6, &sin6p->sin6_addr, host, hostlen) == NULL)
|
||||||
|
return EAI_OVERFLOW;
|
||||||
|
|
||||||
|
uint32_t scopeid = sin6p->sin6_scope_id;
|
||||||
|
@@ -350,7 +350,7 @@ gni_host_inet_numeric (struct scratch_buffer *tmpbuf,
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa;
|
||||||
|
- if (inet_ntop (AF_INET, &sinp->sin_addr, host, hostlen) == NULL)
|
||||||
|
+ if (__inet_ntop (AF_INET, &sinp->sin_addr, host, hostlen) == NULL)
|
||||||
|
return EAI_OVERFLOW;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
diff --git a/resolv/inet_ntop.c b/resolv/inet_ntop.c
|
||||||
|
index c4d38c0f951013e5..acf5f3cb885e2e47 100644
|
||||||
|
--- a/resolv/inet_ntop.c
|
||||||
|
+++ b/resolv/inet_ntop.c
|
||||||
|
@@ -42,7 +42,7 @@ static const char *inet_ntop4 (const u_char *src, char *dst, socklen_t size);
|
||||||
|
static const char *inet_ntop6 (const u_char *src, char *dst, socklen_t size);
|
||||||
|
|
||||||
|
/* char *
|
||||||
|
- * inet_ntop(af, src, dst, size)
|
||||||
|
+ * __inet_ntop(af, src, dst, size)
|
||||||
|
* convert a network format address to presentation format.
|
||||||
|
* return:
|
||||||
|
* pointer to presentation format address (`dst'), or NULL (see errno).
|
||||||
|
@@ -50,7 +50,7 @@ static const char *inet_ntop6 (const u_char *src, char *dst, socklen_t size);
|
||||||
|
* Paul Vixie, 1996.
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
-inet_ntop (int af, const void *src, char *dst, socklen_t size)
|
||||||
|
+__inet_ntop (int af, const void *src, char *dst, socklen_t size)
|
||||||
|
{
|
||||||
|
switch (af) {
|
||||||
|
case AF_INET:
|
||||||
|
@@ -63,7 +63,8 @@ inet_ntop (int af, const void *src, char *dst, socklen_t size)
|
||||||
|
}
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
-libc_hidden_def (inet_ntop)
|
||||||
|
+libc_hidden_def (__inet_ntop)
|
||||||
|
+weak_alias (__inet_ntop, inet_ntop)
|
||||||
|
|
||||||
|
/* const char *
|
||||||
|
* inet_ntop4(src, dst, size)
|
||||||
26
SOURCES/glibc-RHEL-44920-4.patch
Normal file
26
SOURCES/glibc-RHEL-44920-4.patch
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
commit 3cdb99d8bb9d0008b2b297080e61d6c10dd66cc8
|
||||||
|
Author: Frédéric Bérat <fberat@redhat.com>
|
||||||
|
Date: Tue Mar 11 10:40:11 2025 +0100
|
||||||
|
|
||||||
|
Add missing guards in include/arpa/inet.h
|
||||||
|
|
||||||
|
Add the missing guards in the header, similarly to other headers at the
|
||||||
|
same level
|
||||||
|
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/include/arpa/inet.h b/include/arpa/inet.h
|
||||||
|
index d1ea13bb19d4a497..d9e55a3c7f2db9f2 100644
|
||||||
|
--- a/include/arpa/inet.h
|
||||||
|
+++ b/include/arpa/inet.h
|
||||||
|
@@ -1,3 +1,5 @@
|
||||||
|
+#ifndef _ARPA_INET_H
|
||||||
|
+/* Note: _ARPA_INET_H is defined by inet/arpa/inet.h below. */
|
||||||
|
#include <inet/arpa/inet.h>
|
||||||
|
|
||||||
|
#ifndef _ISOMAC
|
||||||
|
@@ -17,3 +19,4 @@ libc_hidden_proto (inet_netof)
|
||||||
|
extern __typeof (inet_network) __inet_network;
|
||||||
|
libc_hidden_proto (__inet_network)
|
||||||
|
#endif
|
||||||
|
+#endif
|
||||||
277
SOURCES/glibc-RHEL-44920-5.patch
Normal file
277
SOURCES/glibc-RHEL-44920-5.patch
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
commit 090dfa40a5e46f7c0e4d6e8369bcbbd51267625f
|
||||||
|
Author: Frédéric Bérat <fberat@redhat.com>
|
||||||
|
Date: Fri Mar 7 18:16:30 2025 +0100
|
||||||
|
|
||||||
|
Add _FORTIFY_SOURCE support for inet_ntop
|
||||||
|
|
||||||
|
- Create the __inet_ntop_chk routine that verifies that the builtin size
|
||||||
|
of the destination buffer is at least as big as the size given by the
|
||||||
|
user.
|
||||||
|
- Redirect calls from inet_ntop to __inet_ntop_chk or __inet_ntop_warn
|
||||||
|
- Update the abilist for this new routine
|
||||||
|
- Update the manual to mention the new fortification
|
||||||
|
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
debug/Makefile (New routine added to static-only-routines
|
||||||
|
instead of routines)
|
||||||
|
debug/Versions (Version not updated in the backport)
|
||||||
|
inet/Makefile (New headers)
|
||||||
|
manual/maint.texi (Not relevant in current Glibc Version)
|
||||||
|
*/libc.abilist (Not added in the backport)
|
||||||
|
inet/bits/inet-fortified-decl.h (Replace __REDIRECT_FORTIFY_NTH
|
||||||
|
with __REDIRECT_NTH)
|
||||||
|
inet/bits/inet-fortified.h (removed attribute_overloadable and
|
||||||
|
clang specific handling)
|
||||||
|
|
||||||
|
Note on the changes:
|
||||||
|
- Since we can't modify the ABI, __inet_ntop_chk has been added to
|
||||||
|
static-only-routines and `attribute_hidden` has been added to its definition.
|
||||||
|
- __REDIRECT_FORTIFY* macros aren't available in the current version, since
|
||||||
|
the patch to enable foritfication on glibc itself hasn't be ported.
|
||||||
|
- clang specific handling of foritifcation has not been ported, which means the
|
||||||
|
following had to be removed from the patch:
|
||||||
|
- use of __attribute_overloadable__
|
||||||
|
- use of __fortify_clang_* macros
|
||||||
|
|
||||||
|
diff --git a/debug/Makefile b/debug/Makefile
|
||||||
|
index c19c76e2b8564bd2..18be784e86bbaaab 100644
|
||||||
|
--- a/debug/Makefile
|
||||||
|
+++ b/debug/Makefile
|
||||||
|
@@ -116,7 +116,8 @@ routines = \
|
||||||
|
wprintf_chk \
|
||||||
|
$(static-only-routines)
|
||||||
|
# routines
|
||||||
|
-static-only-routines := stack_chk_fail_local
|
||||||
|
+static-only-routines := stack_chk_fail_local \
|
||||||
|
+ inet_ntop_chk \
|
||||||
|
|
||||||
|
# Don't add stack_chk_fail_local.o to libc.a since __stack_chk_fail_local
|
||||||
|
# is an alias of __stack_chk_fail in stack_chk_fail.o.
|
||||||
|
diff --git a/debug/inet_ntop_chk.c b/debug/inet_ntop_chk.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..8a3994dd3fc9bfe4
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/debug/inet_ntop_chk.c
|
||||||
|
@@ -0,0 +1,31 @@
|
||||||
|
+/* 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 <arpa/inet.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+
|
||||||
|
+attribute_hidden
|
||||||
|
+const char *
|
||||||
|
+__inet_ntop_chk (int af, const void *src, char *dst,
|
||||||
|
+ socklen_t size, size_t dst_size)
|
||||||
|
+{
|
||||||
|
+ if (size > dst_size)
|
||||||
|
+ __chk_fail ();
|
||||||
|
+
|
||||||
|
+ return inet_ntop (af, src, dst, size);
|
||||||
|
+}
|
||||||
|
+libc_hidden_def (__inet_ntop_chk)
|
||||||
|
diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
|
||||||
|
index 01a8703de1e6e09a..50909d0af53da10e 100644
|
||||||
|
--- a/debug/tst-fortify.c
|
||||||
|
+++ b/debug/tst-fortify.c
|
||||||
|
@@ -24,6 +24,7 @@
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
+#include <arpa/inet.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <obstack.h>
|
||||||
|
@@ -1762,6 +1763,26 @@ do_test (void)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+ struct in6_addr addr6 = {};
|
||||||
|
+ struct in_addr addr = {};
|
||||||
|
+ char addrstr6[INET6_ADDRSTRLEN];
|
||||||
|
+ char addrstr[INET_ADDRSTRLEN];
|
||||||
|
+
|
||||||
|
+ if (inet_ntop (AF_INET6, &addr6, addrstr6, sizeof (addrstr6)) == NULL)
|
||||||
|
+ FAIL ();
|
||||||
|
+ if (inet_ntop (AF_INET, &addr, addrstr, sizeof (addrstr)) == NULL)
|
||||||
|
+ FAIL ();
|
||||||
|
+
|
||||||
|
+#if __USE_FORTIFY_LEVEL >= 1
|
||||||
|
+ CHK_FAIL_START
|
||||||
|
+ inet_ntop (AF_INET6, &addr6, buf, INET6_ADDRSTRLEN);
|
||||||
|
+ CHK_FAIL_END
|
||||||
|
+
|
||||||
|
+ CHK_FAIL_START
|
||||||
|
+ inet_ntop (AF_INET, &addr, buf, INET_ADDRSTRLEN);
|
||||||
|
+ CHK_FAIL_END
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/include/arpa/inet.h b/include/arpa/inet.h
|
||||||
|
index d9e55a3c7f2db9f2..a02892f48a27454e 100644
|
||||||
|
--- a/include/arpa/inet.h
|
||||||
|
+++ b/include/arpa/inet.h
|
||||||
|
@@ -3,12 +3,18 @@
|
||||||
|
#include <inet/arpa/inet.h>
|
||||||
|
|
||||||
|
#ifndef _ISOMAC
|
||||||
|
+/* Declare functions with security checks.
|
||||||
|
+ This needs to be included unconditionally as these definition are needed even
|
||||||
|
+ when fortification is disabled in inet/arpa/inet.h. */
|
||||||
|
+#include <bits/inet-fortified-decl.h>
|
||||||
|
+
|
||||||
|
/* Variant of inet_aton which rejects trailing garbage. */
|
||||||
|
extern int __inet_aton_exact (const char *__cp, struct in_addr *__inp);
|
||||||
|
libc_hidden_proto (__inet_aton_exact)
|
||||||
|
|
||||||
|
extern __typeof (inet_ntop) __inet_ntop;
|
||||||
|
libc_hidden_proto (__inet_ntop)
|
||||||
|
+libc_hidden_proto (__inet_ntop_chk)
|
||||||
|
|
||||||
|
libc_hidden_proto (inet_pton)
|
||||||
|
extern __typeof (inet_pton) __inet_pton;
|
||||||
|
diff --git a/include/bits/inet-fortified-decl.h b/include/bits/inet-fortified-decl.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..e6ad4d4663c61a0d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/include/bits/inet-fortified-decl.h
|
||||||
|
@@ -0,0 +1 @@
|
||||||
|
+#include <inet/bits/inet-fortified-decl.h>
|
||||||
|
diff --git a/include/bits/inet-fortified.h b/include/bits/inet-fortified.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..abba7c57014c2a23
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/include/bits/inet-fortified.h
|
||||||
|
@@ -0,0 +1 @@
|
||||||
|
+#include <inet/bits/inet-fortified.h>
|
||||||
|
diff --git a/inet/Makefile b/inet/Makefile
|
||||||
|
index b7d6e40fb319f52d..ef6b94ed0b519d6d 100644
|
||||||
|
--- a/inet/Makefile
|
||||||
|
+++ b/inet/Makefile
|
||||||
|
@@ -26,6 +26,8 @@ headers := \
|
||||||
|
$(wildcard arpa/*.h protocols/*.h) \
|
||||||
|
aliases.h \
|
||||||
|
bits/in.h \
|
||||||
|
+ bits/inet-fortified-decl.h \
|
||||||
|
+ bits/inet-fortified.h \
|
||||||
|
ifaddrs.h \
|
||||||
|
netinet/ether.h \
|
||||||
|
netinet/icmp6.h \
|
||||||
|
diff --git a/inet/arpa/inet.h b/inet/arpa/inet.h
|
||||||
|
index 54c9c6d468b66a2f..2ac498061a533a7b 100644
|
||||||
|
--- a/inet/arpa/inet.h
|
||||||
|
+++ b/inet/arpa/inet.h
|
||||||
|
@@ -101,6 +101,11 @@ extern char *inet_nsap_ntoa (int __len, const unsigned char *__cp,
|
||||||
|
char *__buf) __THROW;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
|
||||||
|
+/* Include functions with security checks. */
|
||||||
|
+# include <bits/inet-fortified.h>
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif /* arpa/inet.h */
|
||||||
|
diff --git a/inet/bits/inet-fortified-decl.h b/inet/bits/inet-fortified-decl.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..229063ae7898ba2d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/inet/bits/inet-fortified-decl.h
|
||||||
|
@@ -0,0 +1,35 @@
|
||||||
|
+/* Declarations of checking macros for inet functions.
|
||||||
|
+ 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/>. */
|
||||||
|
+
|
||||||
|
+#ifndef _BITS_INET_FORTIFIED_DEC_H
|
||||||
|
+#define _BITS_INET_FORTIFIED_DEC_H 1
|
||||||
|
+
|
||||||
|
+#ifndef _ARPA_INET_H
|
||||||
|
+# error "Never include <bits/inet-fortified-decl.h> directly; use <arpa/inet.h> instead."
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+extern const char *__inet_ntop_chk (int, const void *, char *, socklen_t, size_t);
|
||||||
|
+
|
||||||
|
+extern const char *__REDIRECT_NTH (__inet_ntop_alias,
|
||||||
|
+ (int, const void *, char *, socklen_t), inet_ntop);
|
||||||
|
+extern const char *__REDIRECT_NTH (__inet_ntop_chk_warn,
|
||||||
|
+ (int, const void *, char *, socklen_t, size_t), __inet_ntop_chk)
|
||||||
|
+ __warnattr ("inet_ntop called with bigger length than "
|
||||||
|
+ "size of destination buffer");
|
||||||
|
+
|
||||||
|
+#endif /* bits/inet-fortified-decl.h. */
|
||||||
|
diff --git a/inet/bits/inet-fortified.h b/inet/bits/inet-fortified.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..af26f36ef6ae0533
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/inet/bits/inet-fortified.h
|
||||||
|
@@ -0,0 +1,37 @@
|
||||||
|
+/* Checking macros for inet functions.
|
||||||
|
+ 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/>. */
|
||||||
|
+
|
||||||
|
+#ifndef _BITS_INET_FORTIFIED_H
|
||||||
|
+#define _BITS_INET_FORTIFIED_H 1
|
||||||
|
+
|
||||||
|
+#ifndef _ARPA_INET_H
|
||||||
|
+# error "Never include <bits/inet-fortified.h> directly; use <arpa/inet.h> instead."
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#include <bits/inet-fortified-decl.h>
|
||||||
|
+
|
||||||
|
+__fortify_function const char *
|
||||||
|
+__NTH (inet_ntop (int __af, const void * __restrict __src,
|
||||||
|
+ char *__restrict __dst, socklen_t __dst_size))
|
||||||
|
+{
|
||||||
|
+ return __glibc_fortify (inet_ntop, __dst_size, sizeof (char),
|
||||||
|
+ __glibc_objsize (__dst),
|
||||||
|
+ __af, __src, __dst, __dst_size);
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+#endif /* bits/inet-fortified.h. */
|
||||||
23
SOURCES/glibc-RHEL-44920-6.patch
Normal file
23
SOURCES/glibc-RHEL-44920-6.patch
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
commit 7f0d9e61f40c669fca3cfd1e342fa8236c7220b7
|
||||||
|
Author: Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||||
|
Date: Sat May 20 13:37:47 2023 +0000
|
||||||
|
|
||||||
|
Fix all the remaining misspellings -- BZ 25337
|
||||||
|
|
||||||
|
Note on the changes:
|
||||||
|
- Partial backport, the only file modified is `resolv/inet_pton.c` to
|
||||||
|
ease further backport for RHEL-44920.
|
||||||
|
|
||||||
|
diff --git a/resolv/inet_pton.c b/resolv/inet_pton.c
|
||||||
|
index f1d5db75d0d47501..835f364794c1be96 100644
|
||||||
|
--- a/resolv/inet_pton.c
|
||||||
|
+++ b/resolv/inet_pton.c
|
||||||
|
@@ -121,7 +121,7 @@ inet_pton4 (const char *src, const char *end, unsigned char *dst)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* Return the value of CH as a hexademical digit, or -1 if it is a
|
||||||
|
+/* Return the value of CH as a hexadecimal digit, or -1 if it is a
|
||||||
|
different type of character. */
|
||||||
|
static int
|
||||||
|
hex_digit_value (char ch)
|
||||||
471
SOURCES/glibc-RHEL-44920-7.patch
Normal file
471
SOURCES/glibc-RHEL-44920-7.patch
Normal file
@ -0,0 +1,471 @@
|
|||||||
|
commit a71db81ed1353edd00ca2901d2fefd98c53209d3
|
||||||
|
Author: Aaron Merey <amerey@redhat.com>
|
||||||
|
Date: Thu Mar 20 11:07:05 2025 -0400
|
||||||
|
|
||||||
|
Prepare inet_pton to be fortified
|
||||||
|
|
||||||
|
Split inet_pton internals such as __inet_pton_length from the
|
||||||
|
inet_pton entry point.
|
||||||
|
|
||||||
|
This allows the internals to be built with fortification while
|
||||||
|
leaving the inet_pton entry point unchanged.
|
||||||
|
|
||||||
|
Co-authored-by: Frédéric Bérat <fberat@redhat.com>
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/resolv/Makefile b/resolv/Makefile
|
||||||
|
index e168a81d9e086df4..f3f5c260d0b7471f 100644
|
||||||
|
--- a/resolv/Makefile
|
||||||
|
+++ b/resolv/Makefile
|
||||||
|
@@ -38,6 +38,7 @@ routines := \
|
||||||
|
inet_addr \
|
||||||
|
inet_ntop \
|
||||||
|
inet_pton \
|
||||||
|
+ inet_pton_length \
|
||||||
|
ns_makecanon \
|
||||||
|
ns_name_compress \
|
||||||
|
ns_name_length_uncompressed \
|
||||||
|
@@ -73,6 +74,11 @@ routines := \
|
||||||
|
resolv_context \
|
||||||
|
# routines
|
||||||
|
|
||||||
|
+# Exclude fortified routines from being built with _FORTIFY_SOURCE
|
||||||
|
+routines_no_fortify += \
|
||||||
|
+ inet_pton \
|
||||||
|
+ # routines_no_fortify
|
||||||
|
+
|
||||||
|
tests = tst-aton tst-leaks tst-inet_ntop
|
||||||
|
tests-container = tst-leaks2
|
||||||
|
|
||||||
|
diff --git a/resolv/inet_pton.c b/resolv/inet_pton.c
|
||||||
|
index 835f364794c1be96..cebccb2e1ee7bfd1 100644
|
||||||
|
--- a/resolv/inet_pton.c
|
||||||
|
+++ b/resolv/inet_pton.c
|
||||||
|
@@ -33,33 +33,7 @@
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
-#include <arpa/nameser.h>
|
||||||
|
-#include <ctype.h>
|
||||||
|
-#include <errno.h>
|
||||||
|
-#include <netinet/in.h>
|
||||||
|
#include <resolv/resolv-internal.h>
|
||||||
|
-#include <string.h>
|
||||||
|
-#include <sys/socket.h>
|
||||||
|
-#include <sys/types.h>
|
||||||
|
-
|
||||||
|
-static int inet_pton4 (const char *src, const char *src_end, u_char *dst);
|
||||||
|
-static int inet_pton6 (const char *src, const char *src_end, u_char *dst);
|
||||||
|
-
|
||||||
|
-int
|
||||||
|
-__inet_pton_length (int af, const char *src, size_t srclen, void *dst)
|
||||||
|
-{
|
||||||
|
- switch (af)
|
||||||
|
- {
|
||||||
|
- case AF_INET:
|
||||||
|
- return inet_pton4 (src, src + srclen, dst);
|
||||||
|
- case AF_INET6:
|
||||||
|
- return inet_pton6 (src, src + srclen, dst);
|
||||||
|
- default:
|
||||||
|
- __set_errno (EAFNOSUPPORT);
|
||||||
|
- return -1;
|
||||||
|
- }
|
||||||
|
-}
|
||||||
|
-libc_hidden_def (__inet_pton_length)
|
||||||
|
|
||||||
|
/* Like __inet_pton_length, but use strlen (SRC) as the length of
|
||||||
|
SRC. */
|
||||||
|
@@ -71,164 +45,3 @@ __inet_pton (int af, const char *src, void *dst)
|
||||||
|
libc_hidden_def (__inet_pton)
|
||||||
|
weak_alias (__inet_pton, inet_pton)
|
||||||
|
libc_hidden_weak (inet_pton)
|
||||||
|
-
|
||||||
|
-/* Like inet_aton but without all the hexadecimal, octal and shorthand
|
||||||
|
- (and trailing garbage is not ignored). Return 1 if SRC is a valid
|
||||||
|
- dotted quad, else 0. This function does not touch DST unless it's
|
||||||
|
- returning 1.
|
||||||
|
- Author: Paul Vixie, 1996. */
|
||||||
|
-static int
|
||||||
|
-inet_pton4 (const char *src, const char *end, unsigned char *dst)
|
||||||
|
-{
|
||||||
|
- int saw_digit, octets, ch;
|
||||||
|
- unsigned char tmp[NS_INADDRSZ], *tp;
|
||||||
|
-
|
||||||
|
- saw_digit = 0;
|
||||||
|
- octets = 0;
|
||||||
|
- *(tp = tmp) = 0;
|
||||||
|
- while (src < end)
|
||||||
|
- {
|
||||||
|
- ch = *src++;
|
||||||
|
- if (ch >= '0' && ch <= '9')
|
||||||
|
- {
|
||||||
|
- unsigned int new = *tp * 10 + (ch - '0');
|
||||||
|
-
|
||||||
|
- if (saw_digit && *tp == 0)
|
||||||
|
- return 0;
|
||||||
|
- if (new > 255)
|
||||||
|
- return 0;
|
||||||
|
- *tp = new;
|
||||||
|
- if (! saw_digit)
|
||||||
|
- {
|
||||||
|
- if (++octets > 4)
|
||||||
|
- return 0;
|
||||||
|
- saw_digit = 1;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- else if (ch == '.' && saw_digit)
|
||||||
|
- {
|
||||||
|
- if (octets == 4)
|
||||||
|
- return 0;
|
||||||
|
- *++tp = 0;
|
||||||
|
- saw_digit = 0;
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- return 0;
|
||||||
|
- }
|
||||||
|
- if (octets < 4)
|
||||||
|
- return 0;
|
||||||
|
- memcpy (dst, tmp, NS_INADDRSZ);
|
||||||
|
- return 1;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/* Return the value of CH as a hexadecimal digit, or -1 if it is a
|
||||||
|
- different type of character. */
|
||||||
|
-static int
|
||||||
|
-hex_digit_value (char ch)
|
||||||
|
-{
|
||||||
|
- if ('0' <= ch && ch <= '9')
|
||||||
|
- return ch - '0';
|
||||||
|
- if ('a' <= ch && ch <= 'f')
|
||||||
|
- return ch - 'a' + 10;
|
||||||
|
- if ('A' <= ch && ch <= 'F')
|
||||||
|
- return ch - 'A' + 10;
|
||||||
|
- return -1;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/* Convert presentation-level IPv6 address to network order binary
|
||||||
|
- form. Return 1 if SRC is a valid [RFC1884 2.2] address, else 0.
|
||||||
|
- This function does not touch DST unless it's returning 1.
|
||||||
|
- Author: Paul Vixie, 1996. Inspired by Mark Andrews. */
|
||||||
|
-static int
|
||||||
|
-inet_pton6 (const char *src, const char *src_endp, unsigned char *dst)
|
||||||
|
-{
|
||||||
|
- unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
|
||||||
|
- const char *curtok;
|
||||||
|
- int ch;
|
||||||
|
- size_t xdigits_seen; /* Number of hex digits since colon. */
|
||||||
|
- unsigned int val;
|
||||||
|
-
|
||||||
|
- tp = memset (tmp, '\0', NS_IN6ADDRSZ);
|
||||||
|
- endp = tp + NS_IN6ADDRSZ;
|
||||||
|
- colonp = NULL;
|
||||||
|
-
|
||||||
|
- /* Leading :: requires some special handling. */
|
||||||
|
- if (src == src_endp)
|
||||||
|
- return 0;
|
||||||
|
- if (*src == ':')
|
||||||
|
- {
|
||||||
|
- ++src;
|
||||||
|
- if (src == src_endp || *src != ':')
|
||||||
|
- return 0;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- curtok = src;
|
||||||
|
- xdigits_seen = 0;
|
||||||
|
- val = 0;
|
||||||
|
- while (src < src_endp)
|
||||||
|
- {
|
||||||
|
- ch = *src++;
|
||||||
|
- int digit = hex_digit_value (ch);
|
||||||
|
- if (digit >= 0)
|
||||||
|
- {
|
||||||
|
- if (xdigits_seen == 4)
|
||||||
|
- return 0;
|
||||||
|
- val <<= 4;
|
||||||
|
- val |= digit;
|
||||||
|
- if (val > 0xffff)
|
||||||
|
- return 0;
|
||||||
|
- ++xdigits_seen;
|
||||||
|
- continue;
|
||||||
|
- }
|
||||||
|
- if (ch == ':')
|
||||||
|
- {
|
||||||
|
- curtok = src;
|
||||||
|
- if (xdigits_seen == 0)
|
||||||
|
- {
|
||||||
|
- if (colonp)
|
||||||
|
- return 0;
|
||||||
|
- colonp = tp;
|
||||||
|
- continue;
|
||||||
|
- }
|
||||||
|
- else if (src == src_endp)
|
||||||
|
- return 0;
|
||||||
|
- if (tp + NS_INT16SZ > endp)
|
||||||
|
- return 0;
|
||||||
|
- *tp++ = (unsigned char) (val >> 8) & 0xff;
|
||||||
|
- *tp++ = (unsigned char) val & 0xff;
|
||||||
|
- xdigits_seen = 0;
|
||||||
|
- val = 0;
|
||||||
|
- continue;
|
||||||
|
- }
|
||||||
|
- if (ch == '.' && ((tp + NS_INADDRSZ) <= endp)
|
||||||
|
- && inet_pton4 (curtok, src_endp, tp) > 0)
|
||||||
|
- {
|
||||||
|
- tp += NS_INADDRSZ;
|
||||||
|
- xdigits_seen = 0;
|
||||||
|
- break; /* '\0' was seen by inet_pton4. */
|
||||||
|
- }
|
||||||
|
- return 0;
|
||||||
|
- }
|
||||||
|
- if (xdigits_seen > 0)
|
||||||
|
- {
|
||||||
|
- if (tp + NS_INT16SZ > endp)
|
||||||
|
- return 0;
|
||||||
|
- *tp++ = (unsigned char) (val >> 8) & 0xff;
|
||||||
|
- *tp++ = (unsigned char) val & 0xff;
|
||||||
|
- }
|
||||||
|
- if (colonp != NULL)
|
||||||
|
- {
|
||||||
|
- /* Replace :: with zeros. */
|
||||||
|
- if (tp == endp)
|
||||||
|
- /* :: would expand to a zero-width field. */
|
||||||
|
- return 0;
|
||||||
|
- size_t n = tp - colonp;
|
||||||
|
- memmove (endp - n, colonp, n);
|
||||||
|
- memset (colonp, 0, endp - n - colonp);
|
||||||
|
- tp = endp;
|
||||||
|
- }
|
||||||
|
- if (tp != endp)
|
||||||
|
- return 0;
|
||||||
|
- memcpy (dst, tmp, NS_IN6ADDRSZ);
|
||||||
|
- return 1;
|
||||||
|
-}
|
||||||
|
diff --git a/resolv/inet_pton_length.c b/resolv/inet_pton_length.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..c3614074a47140c1
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/resolv/inet_pton_length.c
|
||||||
|
@@ -0,0 +1,223 @@
|
||||||
|
+/* Copyright (C) 1996-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/>. */
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
|
||||||
|
+ *
|
||||||
|
+ * Permission to use, copy, modify, and distribute this software for any
|
||||||
|
+ * purpose with or without fee is hereby granted, provided that the above
|
||||||
|
+ * copyright notice and this permission notice appear in all copies.
|
||||||
|
+ *
|
||||||
|
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||||
|
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||||
|
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||||
|
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||||
|
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||||
|
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||||
|
+ * SOFTWARE.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <arpa/inet.h>
|
||||||
|
+#include <arpa/nameser.h>
|
||||||
|
+#include <ctype.h>
|
||||||
|
+#include <errno.h>
|
||||||
|
+#include <netinet/in.h>
|
||||||
|
+#include <resolv/resolv-internal.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <sys/socket.h>
|
||||||
|
+#include <sys/types.h>
|
||||||
|
+
|
||||||
|
+static int inet_pton4 (const char *src, const char *src_end, u_char *dst);
|
||||||
|
+static int inet_pton6 (const char *src, const char *src_end, u_char *dst);
|
||||||
|
+
|
||||||
|
+int
|
||||||
|
+__inet_pton_length (int af, const char *src, size_t srclen, void *dst)
|
||||||
|
+{
|
||||||
|
+ switch (af)
|
||||||
|
+ {
|
||||||
|
+ case AF_INET:
|
||||||
|
+ return inet_pton4 (src, src + srclen, dst);
|
||||||
|
+ case AF_INET6:
|
||||||
|
+ return inet_pton6 (src, src + srclen, dst);
|
||||||
|
+ default:
|
||||||
|
+ __set_errno (EAFNOSUPPORT);
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+libc_hidden_def (__inet_pton_length)
|
||||||
|
+
|
||||||
|
+/* Like inet_aton but without all the hexadecimal, octal and shorthand
|
||||||
|
+ (and trailing garbage is not ignored). Return 1 if SRC is a valid
|
||||||
|
+ dotted quad, else 0. This function does not touch DST unless it's
|
||||||
|
+ returning 1.
|
||||||
|
+ Author: Paul Vixie, 1996. */
|
||||||
|
+static int
|
||||||
|
+inet_pton4 (const char *src, const char *end, unsigned char *dst)
|
||||||
|
+{
|
||||||
|
+ int saw_digit, octets, ch;
|
||||||
|
+ unsigned char tmp[NS_INADDRSZ], *tp;
|
||||||
|
+
|
||||||
|
+ saw_digit = 0;
|
||||||
|
+ octets = 0;
|
||||||
|
+ *(tp = tmp) = 0;
|
||||||
|
+ while (src < end)
|
||||||
|
+ {
|
||||||
|
+ ch = *src++;
|
||||||
|
+ if (ch >= '0' && ch <= '9')
|
||||||
|
+ {
|
||||||
|
+ unsigned int new = *tp * 10 + (ch - '0');
|
||||||
|
+
|
||||||
|
+ if (saw_digit && *tp == 0)
|
||||||
|
+ return 0;
|
||||||
|
+ if (new > 255)
|
||||||
|
+ return 0;
|
||||||
|
+ *tp = new;
|
||||||
|
+ if (! saw_digit)
|
||||||
|
+ {
|
||||||
|
+ if (++octets > 4)
|
||||||
|
+ return 0;
|
||||||
|
+ saw_digit = 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ else if (ch == '.' && saw_digit)
|
||||||
|
+ {
|
||||||
|
+ if (octets == 4)
|
||||||
|
+ return 0;
|
||||||
|
+ *++tp = 0;
|
||||||
|
+ saw_digit = 0;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ if (octets < 4)
|
||||||
|
+ return 0;
|
||||||
|
+ memcpy (dst, tmp, NS_INADDRSZ);
|
||||||
|
+ return 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Return the value of CH as a hexadecimal digit, or -1 if it is a
|
||||||
|
+ different type of character. */
|
||||||
|
+static int
|
||||||
|
+hex_digit_value (char ch)
|
||||||
|
+{
|
||||||
|
+ if ('0' <= ch && ch <= '9')
|
||||||
|
+ return ch - '0';
|
||||||
|
+ if ('a' <= ch && ch <= 'f')
|
||||||
|
+ return ch - 'a' + 10;
|
||||||
|
+ if ('A' <= ch && ch <= 'F')
|
||||||
|
+ return ch - 'A' + 10;
|
||||||
|
+ return -1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Convert presentation-level IPv6 address to network order binary
|
||||||
|
+ form. Return 1 if SRC is a valid [RFC1884 2.2] address, else 0.
|
||||||
|
+ This function does not touch DST unless it's returning 1.
|
||||||
|
+ Author: Paul Vixie, 1996. Inspired by Mark Andrews. */
|
||||||
|
+static int
|
||||||
|
+inet_pton6 (const char *src, const char *src_endp, unsigned char *dst)
|
||||||
|
+{
|
||||||
|
+ unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
|
||||||
|
+ const char *curtok;
|
||||||
|
+ int ch;
|
||||||
|
+ size_t xdigits_seen; /* Number of hex digits since colon. */
|
||||||
|
+ unsigned int val;
|
||||||
|
+
|
||||||
|
+ tp = memset (tmp, '\0', NS_IN6ADDRSZ);
|
||||||
|
+ endp = tp + NS_IN6ADDRSZ;
|
||||||
|
+ colonp = NULL;
|
||||||
|
+
|
||||||
|
+ /* Leading :: requires some special handling. */
|
||||||
|
+ if (src == src_endp)
|
||||||
|
+ return 0;
|
||||||
|
+ if (*src == ':')
|
||||||
|
+ {
|
||||||
|
+ ++src;
|
||||||
|
+ if (src == src_endp || *src != ':')
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ curtok = src;
|
||||||
|
+ xdigits_seen = 0;
|
||||||
|
+ val = 0;
|
||||||
|
+ while (src < src_endp)
|
||||||
|
+ {
|
||||||
|
+ ch = *src++;
|
||||||
|
+ int digit = hex_digit_value (ch);
|
||||||
|
+ if (digit >= 0)
|
||||||
|
+ {
|
||||||
|
+ if (xdigits_seen == 4)
|
||||||
|
+ return 0;
|
||||||
|
+ val <<= 4;
|
||||||
|
+ val |= digit;
|
||||||
|
+ if (val > 0xffff)
|
||||||
|
+ return 0;
|
||||||
|
+ ++xdigits_seen;
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ if (ch == ':')
|
||||||
|
+ {
|
||||||
|
+ curtok = src;
|
||||||
|
+ if (xdigits_seen == 0)
|
||||||
|
+ {
|
||||||
|
+ if (colonp)
|
||||||
|
+ return 0;
|
||||||
|
+ colonp = tp;
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ else if (src == src_endp)
|
||||||
|
+ return 0;
|
||||||
|
+ if (tp + NS_INT16SZ > endp)
|
||||||
|
+ return 0;
|
||||||
|
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
|
||||||
|
+ *tp++ = (unsigned char) val & 0xff;
|
||||||
|
+ xdigits_seen = 0;
|
||||||
|
+ val = 0;
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp)
|
||||||
|
+ && inet_pton4 (curtok, src_endp, tp) > 0)
|
||||||
|
+ {
|
||||||
|
+ tp += NS_INADDRSZ;
|
||||||
|
+ xdigits_seen = 0;
|
||||||
|
+ break; /* '\0' was seen by inet_pton4. */
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ if (xdigits_seen > 0)
|
||||||
|
+ {
|
||||||
|
+ if (tp + NS_INT16SZ > endp)
|
||||||
|
+ return 0;
|
||||||
|
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
|
||||||
|
+ *tp++ = (unsigned char) val & 0xff;
|
||||||
|
+ }
|
||||||
|
+ if (colonp != NULL)
|
||||||
|
+ {
|
||||||
|
+ /* Replace :: with zeros. */
|
||||||
|
+ if (tp == endp)
|
||||||
|
+ /* :: would expand to a zero-width field. */
|
||||||
|
+ return 0;
|
||||||
|
+ size_t n = tp - colonp;
|
||||||
|
+ memmove (endp - n, colonp, n);
|
||||||
|
+ memset (colonp, 0, endp - n - colonp);
|
||||||
|
+ tp = endp;
|
||||||
|
+ }
|
||||||
|
+ if (tp != endp)
|
||||||
|
+ return 0;
|
||||||
|
+ memcpy (dst, tmp, NS_IN6ADDRSZ);
|
||||||
|
+ return 1;
|
||||||
|
+}
|
||||||
176
SOURCES/glibc-RHEL-44920-8.patch
Normal file
176
SOURCES/glibc-RHEL-44920-8.patch
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
commit e3a6e85d67f1a48dec3e2557a83d6ce1544a58cb
|
||||||
|
Author: Aaron Merey <amerey@redhat.com>
|
||||||
|
Date: Thu Mar 20 13:13:33 2025 -0400
|
||||||
|
|
||||||
|
Add _FORTIFY_SOURCE support for inet_pton
|
||||||
|
|
||||||
|
Add function __inet_pton_chk which calls __chk_fail when the size of
|
||||||
|
argument dst is too small. inet_pton is redirected to __inet_pton_chk
|
||||||
|
or __inet_pton_warn when _FORTIFY_SOURCE is > 0.
|
||||||
|
|
||||||
|
Also add tests to debug/tst-fortify.c, update the abilist with
|
||||||
|
__inet_pton_chk and mention inet_pton fortification in maint.texi.
|
||||||
|
|
||||||
|
Co-authored-by: Frédéric Bérat <fberat@redhat.com>
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
debug/Makefile (New routine added to static-only-routines
|
||||||
|
instead of routines)
|
||||||
|
debug/Versions (Not added in the backport)
|
||||||
|
manual/maint.texi (Not relevant for this version)
|
||||||
|
*/libc.abilist (Not added in the backport)
|
||||||
|
inet/bits/inet-fortified-decl.h (Replace __REDIRECT_FORTIFY_NTH
|
||||||
|
with __REDIRECT_NTH)
|
||||||
|
inet/bits/inet-fortified.h (removed attribute_overloadable and
|
||||||
|
clang specific handling)
|
||||||
|
|
||||||
|
Note on the changes:
|
||||||
|
- Since we can't modify the ABI, __inet_pton_chk has been added to
|
||||||
|
static-only-routines and `attribute_hidden` has been added to its definition.
|
||||||
|
- __REDIRECT_FORTIFY* macros aren't available in the current version, since
|
||||||
|
the patch to enable foritfication on glibc itself hasn't be ported.
|
||||||
|
- clang specific handling of foritifcation has not been ported, which means the
|
||||||
|
following had to be removed from the patch:
|
||||||
|
- use of __attribute_overloadable__
|
||||||
|
- use of __fortify_clang_* macros
|
||||||
|
|
||||||
|
diff --git a/debug/Makefile b/debug/Makefile
|
||||||
|
index 18be784e86bbaaab..c6ca9946d5fb5d19 100644
|
||||||
|
--- a/debug/Makefile
|
||||||
|
+++ b/debug/Makefile
|
||||||
|
@@ -118,6 +118,7 @@ routines = \
|
||||||
|
# routines
|
||||||
|
static-only-routines := stack_chk_fail_local \
|
||||||
|
inet_ntop_chk \
|
||||||
|
+ inet_pton_chk \
|
||||||
|
|
||||||
|
# Don't add stack_chk_fail_local.o to libc.a since __stack_chk_fail_local
|
||||||
|
# is an alias of __stack_chk_fail in stack_chk_fail.o.
|
||||||
|
diff --git a/debug/inet_pton_chk.c b/debug/inet_pton_chk.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..c9e4fd4683900141
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/debug/inet_pton_chk.c
|
||||||
|
@@ -0,0 +1,31 @@
|
||||||
|
+/* 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 <arpa/inet.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+
|
||||||
|
+attribute_hidden
|
||||||
|
+int
|
||||||
|
+__inet_pton_chk (int af, const char *src, void *dst, size_t dst_size)
|
||||||
|
+{
|
||||||
|
+ if ((af == AF_INET && dst_size < 4)
|
||||||
|
+ || (af == AF_INET6 && dst_size < 16))
|
||||||
|
+ __chk_fail ();
|
||||||
|
+
|
||||||
|
+ return inet_pton (af, src, dst);
|
||||||
|
+}
|
||||||
|
+libc_hidden_def (__inet_pton_chk)
|
||||||
|
diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
|
||||||
|
index 50909d0af53da10e..a87793e44ee36363 100644
|
||||||
|
--- a/debug/tst-fortify.c
|
||||||
|
+++ b/debug/tst-fortify.c
|
||||||
|
@@ -1783,6 +1783,30 @@ do_test (void)
|
||||||
|
CHK_FAIL_END
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+ const char *ipv4str = "127.0.0.1";
|
||||||
|
+ const char *ipv6str = "::1";
|
||||||
|
+
|
||||||
|
+ if (inet_pton (AF_INET, ipv4str, (void *) &addr) != 1)
|
||||||
|
+ FAIL ();
|
||||||
|
+ if (inet_pton (AF_INET6, ipv6str, (void *) &addr6) != 1)
|
||||||
|
+ FAIL ();
|
||||||
|
+
|
||||||
|
+#if __USE_FORTIFY_LEVEL >= 1
|
||||||
|
+ char smallbuf[2];
|
||||||
|
+
|
||||||
|
+ CHK_FAIL_START
|
||||||
|
+ inet_pton (AF_INET, ipv4str, (void *) smallbuf);
|
||||||
|
+ CHK_FAIL_END
|
||||||
|
+
|
||||||
|
+ CHK_FAIL_START
|
||||||
|
+ inet_pton (AF_INET6, ipv6str, (void *) smallbuf);
|
||||||
|
+ CHK_FAIL_END
|
||||||
|
+
|
||||||
|
+ CHK_FAIL_START
|
||||||
|
+ inet_pton (AF_INET6, ipv6str, (void *) &addr);
|
||||||
|
+ CHK_FAIL_END
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/include/arpa/inet.h b/include/arpa/inet.h
|
||||||
|
index a02892f48a27454e..3db8f1a96fdbd6fd 100644
|
||||||
|
--- a/include/arpa/inet.h
|
||||||
|
+++ b/include/arpa/inet.h
|
||||||
|
@@ -19,6 +19,8 @@ libc_hidden_proto (__inet_ntop_chk)
|
||||||
|
libc_hidden_proto (inet_pton)
|
||||||
|
extern __typeof (inet_pton) __inet_pton;
|
||||||
|
libc_hidden_proto (__inet_pton)
|
||||||
|
+libc_hidden_proto (__inet_pton_chk)
|
||||||
|
+
|
||||||
|
extern __typeof (inet_makeaddr) __inet_makeaddr;
|
||||||
|
libc_hidden_proto (__inet_makeaddr)
|
||||||
|
libc_hidden_proto (inet_netof)
|
||||||
|
diff --git a/inet/bits/inet-fortified-decl.h b/inet/bits/inet-fortified-decl.h
|
||||||
|
index 229063ae7898ba2d..189d35aee8bacab1 100644
|
||||||
|
--- a/inet/bits/inet-fortified-decl.h
|
||||||
|
+++ b/inet/bits/inet-fortified-decl.h
|
||||||
|
@@ -32,4 +32,11 @@ extern const char *__REDIRECT_NTH (__inet_ntop_chk_warn,
|
||||||
|
__warnattr ("inet_ntop called with bigger length than "
|
||||||
|
"size of destination buffer");
|
||||||
|
|
||||||
|
+extern int __inet_pton_chk (int, const char *, void *, size_t);
|
||||||
|
+
|
||||||
|
+extern int __REDIRECT_NTH (__inet_pton_alias,
|
||||||
|
+ (int, const char *, void *), inet_pton);
|
||||||
|
+extern int __REDIRECT_NTH (__inet_pton_chk_warn,
|
||||||
|
+ (int, const char *, void *, size_t), __inet_pton_chk)
|
||||||
|
+ __warnattr ("inet_pton called with a destination buffer size too small");
|
||||||
|
#endif /* bits/inet-fortified-decl.h. */
|
||||||
|
diff --git a/inet/bits/inet-fortified.h b/inet/bits/inet-fortified.h
|
||||||
|
index af26f36ef6ae0533..8420a4b7fb41086f 100644
|
||||||
|
--- a/inet/bits/inet-fortified.h
|
||||||
|
+++ b/inet/bits/inet-fortified.h
|
||||||
|
@@ -34,4 +34,21 @@ __NTH (inet_ntop (int __af, const void * __restrict __src,
|
||||||
|
__af, __src, __dst, __dst_size);
|
||||||
|
};
|
||||||
|
|
||||||
|
+__fortify_function int
|
||||||
|
+__NTH (inet_pton (int __af, const char *__restrict __src,
|
||||||
|
+ void * __restrict __dst))
|
||||||
|
+{
|
||||||
|
+ size_t sz = 0;
|
||||||
|
+ if (__af == AF_INET)
|
||||||
|
+ sz = sizeof (struct in_addr);
|
||||||
|
+ else if (__af == AF_INET6)
|
||||||
|
+ sz = sizeof (struct in6_addr);
|
||||||
|
+ else
|
||||||
|
+ return __inet_pton_alias (__af, __src, __dst);
|
||||||
|
+
|
||||||
|
+ return __glibc_fortify (inet_pton, sz, sizeof (char),
|
||||||
|
+ __glibc_objsize (__dst),
|
||||||
|
+ __af, __src, __dst);
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
#endif /* bits/inet-fortified.h. */
|
||||||
15927
SOURCES/glibc-RHEL-46726-1.patch
Normal file
15927
SOURCES/glibc-RHEL-46726-1.patch
Normal file
File diff suppressed because it is too large
Load Diff
451
SOURCES/glibc-RHEL-46726-10.patch
Normal file
451
SOURCES/glibc-RHEL-46726-10.patch
Normal file
@ -0,0 +1,451 @@
|
|||||||
|
commit 50576060c8bf88a3c64c9ab1cdd516974ffb2690
|
||||||
|
Author: Maciej W. Rozycki <macro@redhat.com>
|
||||||
|
Date: Fri Mar 28 12:35:52 2025 +0000
|
||||||
|
|
||||||
|
stdio-common: Add tests for formatted fscanf input specifiers
|
||||||
|
|
||||||
|
Wire fscanf into test infrastructure for formatted scanf input
|
||||||
|
specifiers.
|
||||||
|
|
||||||
|
Reviewed-by: Joseph Myers <josmyers@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||||
|
index 15525a0f768244c6..74d5e02c7206cabc 100644
|
||||||
|
--- a/stdio-common/Makefile
|
||||||
|
+++ b/stdio-common/Makefile
|
||||||
|
@@ -52,7 +52,7 @@ nonfmt-xprintf-stems := \
|
||||||
|
xprintf-stems := $(sort $(fmt-xprintf-stems) $(nonfmt-xprintf-stems))
|
||||||
|
|
||||||
|
# List of markers for scanf family function tests.
|
||||||
|
-xscanf-funcs := s
|
||||||
|
+xscanf-funcs := s f
|
||||||
|
|
||||||
|
# List of data types and formats for individual per-conversion scanf tests.
|
||||||
|
# Further conversions are provided by sysdeps.
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-c.c b/stdio-common/tst-scanf-format-f-c.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..75ce3cd7c314faee
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-c.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for the character conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-character.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-c.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-char.c b/stdio-common/tst-scanf-format-f-char.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..ee5fbe9e1fc9c0aa
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-char.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for signed char conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-char.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-double.c b/stdio-common/tst-scanf-format-f-double.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..1fb25b56b2d27ce5
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-double.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for double conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-double.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-float.c b/stdio-common/tst-scanf-format-f-float.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..b5a6ae4b1e957bd3
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-float.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for float conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-float.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-int.c b/stdio-common/tst-scanf-format-f-int.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..961d66bfa0a842b8
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-int.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-int.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-ldouble.c b/stdio-common/tst-scanf-format-f-ldouble.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..6198d35041584402
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-ldouble.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for long double conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ldouble.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-llong.c b/stdio-common/tst-scanf-format-f-llong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..1af672f9c2e1484c
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-llong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for long long conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-llong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-long.c b/stdio-common/tst-scanf-format-f-long.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..fc908111d973ddfa
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-long.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for long conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-long.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-short.c b/stdio-common/tst-scanf-format-f-short.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..61697e25987f6281
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-short.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for short int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-short.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-uchar.c b/stdio-common/tst-scanf-format-f-uchar.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..b4b8af38e6124c77
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-uchar.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for unsigned char conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-uchar.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-uint.c b/stdio-common/tst-scanf-format-f-uint.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..af226b0d1044cc8b
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-uint.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for unsigned int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-uint.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-ullong.c b/stdio-common/tst-scanf-format-f-ullong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..50ea8123bbe52c60
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-ullong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for unsigned long long int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ullong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-ulong.c b/stdio-common/tst-scanf-format-f-ulong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..673e7703264756dd
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-ulong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for unsigned long int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ulong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f-ushort.c b/stdio-common/tst-scanf-format-f-ushort.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..413ba670e9782984
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f-ushort.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'fscanf' input for unsigned short int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-f.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ushort.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-f.h b/stdio-common/tst-scanf-format-f.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..9a4caeeb16f87801
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-f.h
|
||||||
|
@@ -0,0 +1,29 @@
|
||||||
|
+/* Test feature wrapper for formatted 'fscanf' input.
|
||||||
|
+ 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 <stdio.h>
|
||||||
|
+
|
||||||
|
+#define scanf_under_test(...) \
|
||||||
|
+({ \
|
||||||
|
+ int result = fscanf (stdin, __VA_ARGS__); \
|
||||||
|
+ if (ferror (stdin)) \
|
||||||
|
+ result = INPUT_ERROR; \
|
||||||
|
+ else if (result == EOF) \
|
||||||
|
+ result = INPUT_EOF; \
|
||||||
|
+ result; \
|
||||||
|
+})
|
||||||
495
SOURCES/glibc-RHEL-46726-11.patch
Normal file
495
SOURCES/glibc-RHEL-46726-11.patch
Normal file
@ -0,0 +1,495 @@
|
|||||||
|
commit bf6ac302cde4aef55ded7e5340f16e6cd8b8e874
|
||||||
|
Author: Maciej W. Rozycki <macro@redhat.com>
|
||||||
|
Date: Fri Mar 28 12:35:52 2025 +0000
|
||||||
|
|
||||||
|
stdio-common: Add tests for formatted sscanf input specifiers
|
||||||
|
|
||||||
|
Wire sscanf into test infrastructure for formatted scanf input
|
||||||
|
specifiers.
|
||||||
|
|
||||||
|
Reviewed-by: Joseph Myers <josmyers@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||||
|
index 74d5e02c7206cabc..3e165685af09a1c3 100644
|
||||||
|
--- a/stdio-common/Makefile
|
||||||
|
+++ b/stdio-common/Makefile
|
||||||
|
@@ -52,7 +52,7 @@ nonfmt-xprintf-stems := \
|
||||||
|
xprintf-stems := $(sort $(fmt-xprintf-stems) $(nonfmt-xprintf-stems))
|
||||||
|
|
||||||
|
# List of markers for scanf family function tests.
|
||||||
|
-xscanf-funcs := s f
|
||||||
|
+xscanf-funcs := s f ss
|
||||||
|
|
||||||
|
# List of data types and formats for individual per-conversion scanf tests.
|
||||||
|
# Further conversions are provided by sysdeps.
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-c.c b/stdio-common/tst-scanf-format-ss-c.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..58a7ce8f63398f22
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-c.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for the character conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-character.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-c.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-char.c b/stdio-common/tst-scanf-format-ss-char.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..66eb04c0d620126d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-char.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for signed char conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-char.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-double.c b/stdio-common/tst-scanf-format-ss-double.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..2a9fd8afb552fa96
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-double.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for double conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-double.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-float.c b/stdio-common/tst-scanf-format-ss-float.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..640e35dbebd2e459
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-float.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for float conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-float.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-int.c b/stdio-common/tst-scanf-format-ss-int.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..c01a0a3f1f1a530d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-int.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-int.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-ldouble.c b/stdio-common/tst-scanf-format-ss-ldouble.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..3e57ab568f45a741
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-ldouble.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for long double conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ldouble.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-llong.c b/stdio-common/tst-scanf-format-ss-llong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..9c1603c869b7f5dc
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-llong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for long long conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-llong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-long.c b/stdio-common/tst-scanf-format-ss-long.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..003cfac55282b3cc
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-long.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for long conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-long.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-short.c b/stdio-common/tst-scanf-format-ss-short.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..ba1a58289cd7bd1d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-short.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for short int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-short.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-uchar.c b/stdio-common/tst-scanf-format-ss-uchar.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..1db14241dcab6d89
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-uchar.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for unsigned char conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-uchar.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-uint.c b/stdio-common/tst-scanf-format-ss-uint.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..a296fb48c9c9500a
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-uint.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for unsigned int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-uint.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-ullong.c b/stdio-common/tst-scanf-format-ss-ullong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..885d5709be386471
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-ullong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for unsigned long long int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ullong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-ulong.c b/stdio-common/tst-scanf-format-ss-ulong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..8a2f24dc5ce7d8d8
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-ulong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for unsigned long int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ulong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss-ushort.c b/stdio-common/tst-scanf-format-ss-ushort.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..40618889ac34e910
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss-ushort.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'sscanf' input for unsigned short int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-ss.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ushort.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-ss.h b/stdio-common/tst-scanf-format-ss.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..2fb1ca20deb845df
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-ss.h
|
||||||
|
@@ -0,0 +1,73 @@
|
||||||
|
+/* Test feature wrapper for formatted 'scanf' input.
|
||||||
|
+ 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 <stddef.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+
|
||||||
|
+#include <support/support.h>
|
||||||
|
+
|
||||||
|
+static char *sscanf_buf;
|
||||||
|
+static size_t sscanf_buf_size;
|
||||||
|
+
|
||||||
|
+static void __attribute__ ((destructor))
|
||||||
|
+scanf_under_test_fini (void)
|
||||||
|
+{
|
||||||
|
+ free (sscanf_buf);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#define scanf_under_test(...) \
|
||||||
|
+({ \
|
||||||
|
+ __label__ out; \
|
||||||
|
+ size_t i = 0; \
|
||||||
|
+ int result; \
|
||||||
|
+ int ch; \
|
||||||
|
+ \
|
||||||
|
+ do \
|
||||||
|
+ { \
|
||||||
|
+ ch = read_input (); \
|
||||||
|
+ if (ch < 0) \
|
||||||
|
+ { \
|
||||||
|
+ result = ch; \
|
||||||
|
+ goto out; \
|
||||||
|
+ } \
|
||||||
|
+ if (i == sscanf_buf_size) \
|
||||||
|
+ { \
|
||||||
|
+ sscanf_buf_size += SIZE_CHUNK; \
|
||||||
|
+ /* Add an extra byte for the terminating null character. */ \
|
||||||
|
+ sscanf_buf = xrealloc (sscanf_buf, sscanf_buf_size + 1); \
|
||||||
|
+ } \
|
||||||
|
+ sscanf_buf[i++] = ch; \
|
||||||
|
+ } \
|
||||||
|
+ while (ch != ':'); \
|
||||||
|
+ sscanf_buf[i++] = '\0'; \
|
||||||
|
+ \
|
||||||
|
+ ch = ungetc (ch, stdin); \
|
||||||
|
+ if (ch == EOF) \
|
||||||
|
+ { \
|
||||||
|
+ result = INPUT_ERROR; \
|
||||||
|
+ goto out; \
|
||||||
|
+ } \
|
||||||
|
+ \
|
||||||
|
+ result = sscanf (sscanf_buf, __VA_ARGS__); \
|
||||||
|
+ if (result == EOF) \
|
||||||
|
+ result = INPUT_EOF; \
|
||||||
|
+ \
|
||||||
|
+out: \
|
||||||
|
+ result; \
|
||||||
|
+})
|
||||||
458
SOURCES/glibc-RHEL-46726-12.patch
Normal file
458
SOURCES/glibc-RHEL-46726-12.patch
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
commit 63c81fa0dbf741b33bbac03bf204d896ee8e4694
|
||||||
|
Author: Maciej W. Rozycki <macro@redhat.com>
|
||||||
|
Date: Fri Mar 28 12:35:52 2025 +0000
|
||||||
|
|
||||||
|
stdio-common: Add tests for formatted vscanf input specifiers
|
||||||
|
|
||||||
|
Wire vscanf into test infrastructure for formatted scanf input
|
||||||
|
specifiers.
|
||||||
|
|
||||||
|
Reviewed-by: Joseph Myers <josmyers@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||||
|
index 3e165685af09a1c3..3a09b5bfbc930b45 100644
|
||||||
|
--- a/stdio-common/Makefile
|
||||||
|
+++ b/stdio-common/Makefile
|
||||||
|
@@ -52,7 +52,7 @@ nonfmt-xprintf-stems := \
|
||||||
|
xprintf-stems := $(sort $(fmt-xprintf-stems) $(nonfmt-xprintf-stems))
|
||||||
|
|
||||||
|
# List of markers for scanf family function tests.
|
||||||
|
-xscanf-funcs := s f ss
|
||||||
|
+xscanf-funcs := s f ss v
|
||||||
|
|
||||||
|
# List of data types and formats for individual per-conversion scanf tests.
|
||||||
|
# Further conversions are provided by sysdeps.
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-c.c b/stdio-common/tst-scanf-format-v-c.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..0e2c000ce0218e92
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-c.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for the character conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-character.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-c.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-char.c b/stdio-common/tst-scanf-format-v-char.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..be3a56c663b457ee
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-char.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for signed char conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-char.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-double.c b/stdio-common/tst-scanf-format-v-double.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..91886318e800f274
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-double.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for double conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-double.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-float.c b/stdio-common/tst-scanf-format-v-float.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..5d289d3e8be7a640
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-float.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for float conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-float.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-int.c b/stdio-common/tst-scanf-format-v-int.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..770a686bb1a355fa
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-int.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-int.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-ldouble.c b/stdio-common/tst-scanf-format-v-ldouble.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..8215ea7ecb4f785a
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-ldouble.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for long double conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ldouble.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-llong.c b/stdio-common/tst-scanf-format-v-llong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..2a1ef02844fc7c27
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-llong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for long long conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-llong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-long.c b/stdio-common/tst-scanf-format-v-long.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..8376032bd459d253
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-long.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for long conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-long.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-short.c b/stdio-common/tst-scanf-format-v-short.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..23b9c568874d89bb
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-short.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for short int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-short.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-uchar.c b/stdio-common/tst-scanf-format-v-uchar.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..861db22fbafe508e
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-uchar.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for unsigned char conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-uchar.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-uint.c b/stdio-common/tst-scanf-format-v-uint.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..30e58c591723d719
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-uint.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for unsigned int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-uint.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-ullong.c b/stdio-common/tst-scanf-format-v-ullong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..ee2914d3e932e5cf
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-ullong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for unsigned long long int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ullong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-ulong.c b/stdio-common/tst-scanf-format-v-ulong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..f7864dd57636c6b2
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-ulong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for unsigned long int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ulong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v-ushort.c b/stdio-common/tst-scanf-format-v-ushort.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..79ca16b4e8f953d0
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v-ushort.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vscanf' input for unsigned short int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-v.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ushort.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-v.h b/stdio-common/tst-scanf-format-v.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..bf19877670d7aea3
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-v.h
|
||||||
|
@@ -0,0 +1,36 @@
|
||||||
|
+/* Test feature wrapper for formatted 'vscanf' input.
|
||||||
|
+ 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 <stdarg.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+scanf_under_test (const char *restrict fmt, ...)
|
||||||
|
+{
|
||||||
|
+ va_list ap;
|
||||||
|
+ int result;
|
||||||
|
+
|
||||||
|
+ va_start (ap, fmt);
|
||||||
|
+ result = vscanf (fmt, ap);
|
||||||
|
+ va_end (ap);
|
||||||
|
+ if (ferror (stdin))
|
||||||
|
+ result = INPUT_ERROR;
|
||||||
|
+ else if (result == EOF)
|
||||||
|
+ result = INPUT_EOF;
|
||||||
|
+ return result;
|
||||||
|
+}
|
||||||
458
SOURCES/glibc-RHEL-46726-13.patch
Normal file
458
SOURCES/glibc-RHEL-46726-13.patch
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
commit 53ee7ede430b92fcefd31fc00bfd3fa9acec5846
|
||||||
|
Author: Maciej W. Rozycki <macro@redhat.com>
|
||||||
|
Date: Fri Mar 28 12:35:53 2025 +0000
|
||||||
|
|
||||||
|
stdio-common: Add tests for formatted vfscanf input specifiers
|
||||||
|
|
||||||
|
Wire vfscanf into test infrastructure for formatted scanf input
|
||||||
|
specifiers.
|
||||||
|
|
||||||
|
Reviewed-by: Joseph Myers <josmyers@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||||
|
index 3a09b5bfbc930b45..13c50f07ccfc86c3 100644
|
||||||
|
--- a/stdio-common/Makefile
|
||||||
|
+++ b/stdio-common/Makefile
|
||||||
|
@@ -52,7 +52,7 @@ nonfmt-xprintf-stems := \
|
||||||
|
xprintf-stems := $(sort $(fmt-xprintf-stems) $(nonfmt-xprintf-stems))
|
||||||
|
|
||||||
|
# List of markers for scanf family function tests.
|
||||||
|
-xscanf-funcs := s f ss v
|
||||||
|
+xscanf-funcs := s f ss v vf
|
||||||
|
|
||||||
|
# List of data types and formats for individual per-conversion scanf tests.
|
||||||
|
# Further conversions are provided by sysdeps.
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-c.c b/stdio-common/tst-scanf-format-vf-c.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..307bfe82c3875245
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-c.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for the character conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-character.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-c.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-char.c b/stdio-common/tst-scanf-format-vf-char.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..602899b2bcd5b7eb
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-char.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for signed char conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-char.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-double.c b/stdio-common/tst-scanf-format-vf-double.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..8b58bbe10b3e8622
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-double.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for double conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-double.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-float.c b/stdio-common/tst-scanf-format-vf-float.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..81dad06ebe389438
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-float.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for float conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-float.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-int.c b/stdio-common/tst-scanf-format-vf-int.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..8038791f1411d579
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-int.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-int.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-ldouble.c b/stdio-common/tst-scanf-format-vf-ldouble.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..ec9a7c4632968966
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-ldouble.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for long double conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ldouble.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-llong.c b/stdio-common/tst-scanf-format-vf-llong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..adc4b125de23cd3c
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-llong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for long long conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-llong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-long.c b/stdio-common/tst-scanf-format-vf-long.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..5f26d6c9ce69e08f
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-long.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for long conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-long.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-short.c b/stdio-common/tst-scanf-format-vf-short.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..0e081ead780b6882
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-short.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for short int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-short.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-uchar.c b/stdio-common/tst-scanf-format-vf-uchar.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..2e879f52ce705646
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-uchar.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for unsigned char conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-uchar.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-uint.c b/stdio-common/tst-scanf-format-vf-uint.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..4874f86ef21cf5fe
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-uint.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for unsigned int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-uint.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-ullong.c b/stdio-common/tst-scanf-format-vf-ullong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..dde09018c46128a5
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-ullong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for unsigned long long int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ullong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-ulong.c b/stdio-common/tst-scanf-format-vf-ulong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..81023061ef66f824
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-ulong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for unsigned long int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ulong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf-ushort.c b/stdio-common/tst-scanf-format-vf-ushort.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..cb8eb4bdcf5e3abc
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf-ushort.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vfscanf' input for unsigned short int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vf.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ushort.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vf.h b/stdio-common/tst-scanf-format-vf.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..6037e63921aa4ba3
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vf.h
|
||||||
|
@@ -0,0 +1,36 @@
|
||||||
|
+/* Test feature wrapper for formatted 'vfscanf' input.
|
||||||
|
+ 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 <stdarg.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+scanf_under_test (const char *restrict fmt, ...)
|
||||||
|
+{
|
||||||
|
+ va_list ap;
|
||||||
|
+ int result;
|
||||||
|
+
|
||||||
|
+ va_start (ap, fmt);
|
||||||
|
+ result = vfscanf (stdin, fmt, ap);
|
||||||
|
+ va_end (ap);
|
||||||
|
+ if (ferror (stdin))
|
||||||
|
+ result = INPUT_ERROR;
|
||||||
|
+ else if (result == EOF)
|
||||||
|
+ result = INPUT_EOF;
|
||||||
|
+ return result;
|
||||||
|
+}
|
||||||
499
SOURCES/glibc-RHEL-46726-14.patch
Normal file
499
SOURCES/glibc-RHEL-46726-14.patch
Normal file
@ -0,0 +1,499 @@
|
|||||||
|
commit 47076b3163ce645f791d5c8f80080e9811733347
|
||||||
|
Author: Maciej W. Rozycki <macro@redhat.com>
|
||||||
|
Date: Fri Mar 28 12:35:53 2025 +0000
|
||||||
|
|
||||||
|
stdio-common: Add tests for formatted vsscanf input specifiers
|
||||||
|
|
||||||
|
Wire vsscanf into test infrastructure for formatted scanf input
|
||||||
|
specifiers.
|
||||||
|
|
||||||
|
Reviewed-by: Joseph Myers <josmyers@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||||
|
index 13c50f07ccfc86c3..1aefe3702800bd73 100644
|
||||||
|
--- a/stdio-common/Makefile
|
||||||
|
+++ b/stdio-common/Makefile
|
||||||
|
@@ -52,7 +52,7 @@ nonfmt-xprintf-stems := \
|
||||||
|
xprintf-stems := $(sort $(fmt-xprintf-stems) $(nonfmt-xprintf-stems))
|
||||||
|
|
||||||
|
# List of markers for scanf family function tests.
|
||||||
|
-xscanf-funcs := s f ss v vf
|
||||||
|
+xscanf-funcs := s f ss v vf vs
|
||||||
|
|
||||||
|
# List of data types and formats for individual per-conversion scanf tests.
|
||||||
|
# Further conversions are provided by sysdeps.
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-c.c b/stdio-common/tst-scanf-format-vs-c.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..2df5aa7acbecf851
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-c.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for the character conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-character.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-c.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-char.c b/stdio-common/tst-scanf-format-vs-char.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..ae4d8e0d0a06b549
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-char.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for signed char conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-char.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-double.c b/stdio-common/tst-scanf-format-vs-double.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..cd459a8506d4a1e1
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-double.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for double conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-double.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-float.c b/stdio-common/tst-scanf-format-vs-float.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..7872afef5a49c515
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-float.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for float conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-float.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-int.c b/stdio-common/tst-scanf-format-vs-int.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..e67b4be6c1ffffb4
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-int.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-int.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-ldouble.c b/stdio-common/tst-scanf-format-vs-ldouble.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..4d299c29eeee5202
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-ldouble.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for long double conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-real.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ldouble.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-llong.c b/stdio-common/tst-scanf-format-vs-llong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..06c8cc921f40bcab
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-llong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for long long conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-llong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-long.c b/stdio-common/tst-scanf-format-vs-long.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..575a6cb36a20385d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-long.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for long conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-long.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-short.c b/stdio-common/tst-scanf-format-vs-short.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..5473471996bfad9b
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-short.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for short int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-short.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-uchar.c b/stdio-common/tst-scanf-format-vs-uchar.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..5a29b9b944f7df31
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-uchar.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for unsigned char conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-uchar.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-uint.c b/stdio-common/tst-scanf-format-vs-uint.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..b9486b1488270d7a
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-uint.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for unsigned int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-uint.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-ullong.c b/stdio-common/tst-scanf-format-vs-ullong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..5396a7812fc13c39
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-ullong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for unsigned long long int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ullong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-ulong.c b/stdio-common/tst-scanf-format-vs-ulong.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..3dbc14206dea3176
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-ulong.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for unsigned long int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ulong.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs-ushort.c b/stdio-common/tst-scanf-format-vs-ushort.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..0f28b36dee83ddbe
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs-ushort.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/* Test for formatted 'vsscanf' input for unsigned short int conversions.
|
||||||
|
+ 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 "tst-scanf-format-skeleton.h"
|
||||||
|
+#include "tst-scanf-format-vs.h"
|
||||||
|
+#include "tst-scanf-format-integer.h"
|
||||||
|
+#include "tst-scanf-format-skeleton-ushort.c"
|
||||||
|
diff --git a/stdio-common/tst-scanf-format-vs.h b/stdio-common/tst-scanf-format-vs.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..d49690daa00bb954
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-scanf-format-vs.h
|
||||||
|
@@ -0,0 +1,77 @@
|
||||||
|
+/* Test feature wrapper for formatted 'vsscanf' input.
|
||||||
|
+ 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 <stdarg.h>
|
||||||
|
+#include <stddef.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+
|
||||||
|
+#include <support/support.h>
|
||||||
|
+
|
||||||
|
+static char *sscanf_buf;
|
||||||
|
+static size_t sscanf_buf_size;
|
||||||
|
+
|
||||||
|
+static void __attribute__ ((destructor))
|
||||||
|
+scanf_under_test_fini (void)
|
||||||
|
+{
|
||||||
|
+ free (sscanf_buf);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+scanf_under_test (const char *restrict fmt, ...)
|
||||||
|
+{
|
||||||
|
+ size_t i = 0;
|
||||||
|
+ va_list ap;
|
||||||
|
+ int result;
|
||||||
|
+ int ch;
|
||||||
|
+
|
||||||
|
+ do
|
||||||
|
+ {
|
||||||
|
+ ch = read_input ();
|
||||||
|
+ if (ch < 0)
|
||||||
|
+ {
|
||||||
|
+ result = ch;
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+ if (i == sscanf_buf_size)
|
||||||
|
+ {
|
||||||
|
+ sscanf_buf_size += SIZE_CHUNK;
|
||||||
|
+ /* Add an extra byte for the terminating null character. */
|
||||||
|
+ sscanf_buf = xrealloc (sscanf_buf, sscanf_buf_size + 1);
|
||||||
|
+ }
|
||||||
|
+ sscanf_buf[i++] = ch;
|
||||||
|
+ }
|
||||||
|
+ while (ch != ':');
|
||||||
|
+ sscanf_buf[i++] = '\0';
|
||||||
|
+
|
||||||
|
+ ch = ungetc (ch, stdin);
|
||||||
|
+ if (ch == EOF)
|
||||||
|
+ {
|
||||||
|
+ result = INPUT_ERROR;
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ va_start (ap, fmt);
|
||||||
|
+ result = vsscanf (sscanf_buf, fmt, ap);
|
||||||
|
+ va_end (ap);
|
||||||
|
+ if (result == EOF)
|
||||||
|
+ result = INPUT_EOF;
|
||||||
|
+
|
||||||
|
+out:
|
||||||
|
+ return result;
|
||||||
|
+}
|
||||||
32483
SOURCES/glibc-RHEL-46726-15.patch
Normal file
32483
SOURCES/glibc-RHEL-46726-15.patch
Normal file
File diff suppressed because it is too large
Load Diff
9159
SOURCES/glibc-RHEL-46726-2.patch
Normal file
9159
SOURCES/glibc-RHEL-46726-2.patch
Normal file
File diff suppressed because it is too large
Load Diff
9223
SOURCES/glibc-RHEL-46726-3.patch
Normal file
9223
SOURCES/glibc-RHEL-46726-3.patch
Normal file
File diff suppressed because it is too large
Load Diff
5032
SOURCES/glibc-RHEL-46726-4.patch
Normal file
5032
SOURCES/glibc-RHEL-46726-4.patch
Normal file
File diff suppressed because it is too large
Load Diff
5035
SOURCES/glibc-RHEL-46726-5.patch
Normal file
5035
SOURCES/glibc-RHEL-46726-5.patch
Normal file
File diff suppressed because it is too large
Load Diff
4911
SOURCES/glibc-RHEL-46726-6.patch
Normal file
4911
SOURCES/glibc-RHEL-46726-6.patch
Normal file
File diff suppressed because one or more lines are too long
5116
SOURCES/glibc-RHEL-46726-7.patch
Normal file
5116
SOURCES/glibc-RHEL-46726-7.patch
Normal file
File diff suppressed because it is too large
Load Diff
4984
SOURCES/glibc-RHEL-46726-8.patch
Normal file
4984
SOURCES/glibc-RHEL-46726-8.patch
Normal file
File diff suppressed because it is too large
Load Diff
4953
SOURCES/glibc-RHEL-46726-9.patch
Normal file
4953
SOURCES/glibc-RHEL-46726-9.patch
Normal file
File diff suppressed because one or more lines are too long
578
SOURCES/glibc-RHEL-46729.patch
Normal file
578
SOURCES/glibc-RHEL-46729.patch
Normal file
@ -0,0 +1,578 @@
|
|||||||
|
commit 45c42b65c29422b773ac94771aa71165e245f8f8
|
||||||
|
Author: Martin Coufal <mcoufal@redhat.com>
|
||||||
|
Date: Thu Jan 23 13:04:06 2025 +0100
|
||||||
|
|
||||||
|
Add new tests for fopen
|
||||||
|
|
||||||
|
Adding some basic tests for fopen, testing different modes, stream
|
||||||
|
positioning and concurrent read/write operation on files.
|
||||||
|
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||||
|
|
||||||
|
# Conflicts:
|
||||||
|
# sysdeps/pthread/Makefile (new test added)
|
||||||
|
|
||||||
|
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||||
|
index 74e0edff73a9e468..fe69e48849cb9819 100644
|
||||||
|
--- a/stdio-common/Makefile
|
||||||
|
+++ b/stdio-common/Makefile
|
||||||
|
@@ -201,6 +201,7 @@ tests := \
|
||||||
|
tst-fmemopen2 \
|
||||||
|
tst-fmemopen3 \
|
||||||
|
tst-fmemopen4 \
|
||||||
|
+ tst-fopen \
|
||||||
|
tst-fphex \
|
||||||
|
tst-fphex-wide \
|
||||||
|
tst-fread \
|
||||||
|
diff --git a/stdio-common/tst-fopen.c b/stdio-common/tst-fopen.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..8c1fefd116f9f581
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/stdio-common/tst-fopen.c
|
||||||
|
@@ -0,0 +1,279 @@
|
||||||
|
+/* Basic test for fopen.
|
||||||
|
+ 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 <errno.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/temp_file.h>
|
||||||
|
+#include <support/xstdio.h>
|
||||||
|
+
|
||||||
|
+#define APPENDED_TEXT "This is appended text. "
|
||||||
|
+#define DEFAULT_TEXT "Lorem ipsum dolor sit amet, consectetur " \
|
||||||
|
+ "adipiscing elit, sed do eiusmod tempor incididunt ut labore et " \
|
||||||
|
+ "dolore magna aliqua."
|
||||||
|
+#define MAX_BUFFER_SIZE 300
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ char *temp_file;
|
||||||
|
+ FILE *fd_file = NULL;
|
||||||
|
+ char read_buffer[MAX_BUFFER_SIZE] = "";
|
||||||
|
+ size_t ret;
|
||||||
|
+
|
||||||
|
+ /* Prepare files. */
|
||||||
|
+ int fd = create_temp_file ("tst-fopen.", &temp_file);
|
||||||
|
+ TEST_VERIFY_EXIT (fd != -1);
|
||||||
|
+ fd_file = fdopen (fd, "w");
|
||||||
|
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
|
||||||
|
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+
|
||||||
|
+ /* Test 1: This checks for fopen with mode "r". Open text file for
|
||||||
|
+ reading. The stream is positioned at the beginning of the file. */
|
||||||
|
+ printf ("Test 1: This checks for fopen with mode \"r\".\n");
|
||||||
|
+ fd_file = fopen (temp_file, "r");
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_VERIFY (fd_file != NULL);
|
||||||
|
+ TEST_COMPARE (ftell (fd_file), 0);
|
||||||
|
+ /* Read should succeed. */
|
||||||
|
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
|
||||||
|
+ TEST_VERIFY (strcmp (read_buffer, DEFAULT_TEXT) == 0);
|
||||||
|
+ /* Write should fail. */
|
||||||
|
+ errno = 0;
|
||||||
|
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
|
||||||
|
+ TEST_VERIFY (ferror (fd_file) != 0);
|
||||||
|
+ TEST_COMPARE (errno, EBADF);
|
||||||
|
+ TEST_COMPARE (ret, 0);
|
||||||
|
+ clearerr (fd_file);
|
||||||
|
+ /* Opening non-existent file should fail. */
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+ errno = 0;
|
||||||
|
+ fd_file = fopen ("file-that-does-not-exist", "r");
|
||||||
|
+ TEST_VERIFY (fd_file == NULL);
|
||||||
|
+ TEST_COMPARE (errno, ENOENT);
|
||||||
|
+ TEST_VERIFY (fd_file == NULL);
|
||||||
|
+
|
||||||
|
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
|
||||||
|
+
|
||||||
|
+ /* Test 2: This checks for fopen with mode "r+". Open for reading and
|
||||||
|
+ writing. The stream is positioned at the beginning of the file. */
|
||||||
|
+ printf ("Test 2: This checks for fopen with mode \"r+\".\n");
|
||||||
|
+ fd_file = fopen (temp_file, "r+");
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_VERIFY (fd_file != NULL);
|
||||||
|
+ TEST_COMPARE (ftell (fd_file), 0);
|
||||||
|
+ /* Read should succeed. */
|
||||||
|
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
|
||||||
|
+ TEST_VERIFY (strcmp (read_buffer, DEFAULT_TEXT) == 0);
|
||||||
|
+ fflush (fd_file);
|
||||||
|
+ /* File position indicator expected at 0 + read bytes. */
|
||||||
|
+ TEST_COMPARE (ftell (fd_file), ret);
|
||||||
|
+ /* Write should succeed. */
|
||||||
|
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
|
||||||
|
+ /* Opening non-existent file should fail. */
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+ errno = 0;
|
||||||
|
+ fd_file = fopen ("file-that-does-not-exist", "r+");
|
||||||
|
+ TEST_VERIFY (fd_file == NULL);
|
||||||
|
+ TEST_COMPARE (errno, ENOENT);
|
||||||
|
+ TEST_VERIFY (fd_file == NULL);
|
||||||
|
+
|
||||||
|
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
|
||||||
|
+
|
||||||
|
+ /* Test 3: This checks for fopen with mode "w". Truncate file to zero
|
||||||
|
+ length or create text file for writing. The stream is positioned
|
||||||
|
+ at the beginning of the file. */
|
||||||
|
+ printf ("Test 3: This checks for fopen with mode \"w\".\n");
|
||||||
|
+ fd_file = fopen (temp_file, "w");
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_VERIFY (fd_file != NULL);
|
||||||
|
+ TEST_COMPARE (ftell (fd_file), 0);
|
||||||
|
+ /* Read should fail. */
|
||||||
|
+ errno = 0;
|
||||||
|
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
|
||||||
|
+ TEST_VERIFY (ferror (fd_file) != 0);
|
||||||
|
+ TEST_COMPARE (errno, EBADF);
|
||||||
|
+ TEST_COMPARE (ret, 0);
|
||||||
|
+ clearerr (fd_file);
|
||||||
|
+ /* Write should succeed. */
|
||||||
|
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
|
||||||
|
+ /* Opening non-existent file should succeed. */
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+ fd_file = fopen ("/tmp/file-that-does-not-exist", "w");
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_VERIFY (fd_file != NULL);
|
||||||
|
+ TEST_COMPARE (ftell (fd_file), 0);
|
||||||
|
+
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+ remove ("/tmp/file-that-does-not-exist");
|
||||||
|
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
|
||||||
|
+
|
||||||
|
+ /* Test 4: This checks for fopen with mode "w+". Open for reading and
|
||||||
|
+ writing. The file is created if it does not exist, otherwise it is
|
||||||
|
+ truncated. The stream is positioned at the beginning of the file.
|
||||||
|
+ */
|
||||||
|
+ printf ("Test 4: This checks for fopen with mode \"w+\".\n");
|
||||||
|
+ fd_file = fopen (temp_file, "w+");
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_VERIFY (fd_file != NULL);
|
||||||
|
+ TEST_COMPARE (ftell (fd_file), 0);
|
||||||
|
+ /* Read should succeed. */
|
||||||
|
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_COMPARE (ret, 0);
|
||||||
|
+ TEST_VERIFY (read_buffer[0] == '\0');
|
||||||
|
+ /* Write should succeed. */
|
||||||
|
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
|
||||||
|
+ /* Opening non-existent file should succeed. */
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+ fd_file = fopen ("/tmp/file-that-does-not-exist", "w+");
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_VERIFY (fd_file != NULL);
|
||||||
|
+ TEST_COMPARE (ftell (fd_file), 0);
|
||||||
|
+
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+ remove ("/tmp/file-that-does-not-exist");
|
||||||
|
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
|
||||||
|
+
|
||||||
|
+ /* Test 5: This checks for fopen with mode "a". Open for appending
|
||||||
|
+ (writing at end of file). The file is created if it does not
|
||||||
|
+ exist. The stream is positioned at the end of the file. */
|
||||||
|
+ printf ("Test 5: This checks for fopen with mode \"a\".\n");
|
||||||
|
+ fd_file = fopen (temp_file, "a");
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_VERIFY (fd_file != NULL);
|
||||||
|
+ TEST_COMPARE (ftell (fd_file), strlen (DEFAULT_TEXT));
|
||||||
|
+ /* Read should fail. */
|
||||||
|
+ errno = 0;
|
||||||
|
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
|
||||||
|
+ TEST_VERIFY (ferror (fd_file) != 0);
|
||||||
|
+ TEST_COMPARE (errno, EBADF);
|
||||||
|
+ TEST_COMPARE (ret, 0);
|
||||||
|
+ clearerr (fd_file);
|
||||||
|
+ /* Write should succeed. */
|
||||||
|
+ ret = fwrite (APPENDED_TEXT, sizeof (char), strlen (APPENDED_TEXT), fd_file);
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_COMPARE (ret, strlen (APPENDED_TEXT));
|
||||||
|
+ /* The file position indicator for the stream is advanced by the
|
||||||
|
+ * number of bytes successfully read or written. */
|
||||||
|
+ TEST_COMPARE (ftell (fd_file), strlen (DEFAULT_TEXT) + ret);
|
||||||
|
+ /* Opening non-existent file should succeed. */
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+ fd_file = fopen ("/tmp/file-that-does-not-exist", "a");
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_VERIFY (fd_file != NULL);
|
||||||
|
+ TEST_COMPARE (ftell (fd_file), 0);
|
||||||
|
+
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+ remove ("/tmp/file-that-does-not-exist");
|
||||||
|
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
|
||||||
|
+
|
||||||
|
+ /* Test 6: This checks for fopen with mode "a+". Open for reading and
|
||||||
|
+ appending (writing at end of file). The file is created if it does
|
||||||
|
+ not exist. Output is always appended to the end of the file. The
|
||||||
|
+ initial file position for reading is at the beginning of the file,
|
||||||
|
+ but it is advanced to the end prior to each write. */
|
||||||
|
+ printf ("Test 6: This checks for fopen with mode \"a+\".\n");
|
||||||
|
+ errno = 0;
|
||||||
|
+ fd_file = fopen (temp_file, "a+");
|
||||||
|
+ TEST_COMPARE (errno, 0);
|
||||||
|
+ TEST_VERIFY (fd_file != NULL);
|
||||||
|
+ TEST_COMPARE (ftell (fd_file), 0);
|
||||||
|
+ /* Read should succeed. */
|
||||||
|
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT) + strlen (APPENDED_TEXT));
|
||||||
|
+ TEST_VERIFY (strcmp (read_buffer, DEFAULT_TEXT APPENDED_TEXT) == 0);
|
||||||
|
+ /* Write should succeed. */
|
||||||
|
+ const char* SECOND_APPEND = "This is second append.";
|
||||||
|
+ ret = fwrite (SECOND_APPEND, sizeof (char), strlen (SECOND_APPEND), fd_file);
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_COMPARE (ret, strlen (SECOND_APPEND));
|
||||||
|
+ /* The file position indicator for the stream is advanced by the
|
||||||
|
+ number of bytes successfully read or written. */
|
||||||
|
+ TEST_COMPARE (ftell (fd_file),
|
||||||
|
+ strlen (DEFAULT_TEXT) + strlen (APPENDED_TEXT) + ret);
|
||||||
|
+ /* Opening non-existent file should succeed. */
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+ fd_file = fopen ("/tmp/file-that-does-not-exist", "a+");
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_VERIFY (fd_file != NULL);
|
||||||
|
+ TEST_COMPARE (ftell (fd_file), 0);
|
||||||
|
+
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+ remove ("/tmp/file-that-does-not-exist");
|
||||||
|
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
|
||||||
|
+
|
||||||
|
+ /* Test 7: This checks for fopen with other valid modes set, such as
|
||||||
|
+ "rc", "we" or "am". The test calls fopen with these modes and
|
||||||
|
+ checks that no errors appear. */
|
||||||
|
+ printf ("Test 7: This checks for fopen with other valid modes set, "
|
||||||
|
+ "such as \"rc\", \"we\" or \"am\".\n");
|
||||||
|
+ /* These modes all operate correctly with the file already present. */
|
||||||
|
+ static const char *valid_modes[] =
|
||||||
|
+ { "rc", "we", "am", "r+x", "wb+", "ab", 0 };
|
||||||
|
+ const char **p = valid_modes;
|
||||||
|
+ while (*p != 0)
|
||||||
|
+ {
|
||||||
|
+ fd_file = fopen (temp_file, *p);
|
||||||
|
+ TEST_COMPARE (ferror (fd_file), 0);
|
||||||
|
+ TEST_VERIFY (fd_file != NULL);
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+ ++p;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Test 8: This checks for fopen with invalid modes. The test calls
|
||||||
|
+ fopen with these modes and checks that opening existing files with
|
||||||
|
+ invalid mode fails and that opening non-existing files with invalid
|
||||||
|
+ mode doesn't create a new file. */
|
||||||
|
+ printf ("Test 8: This checks for fopen with invalid modes.\n");
|
||||||
|
+ static const char *invalid_modes[] = { "0", "tr", "z", "x", " ", 0 };
|
||||||
|
+ p = invalid_modes;
|
||||||
|
+ while (*p != 0)
|
||||||
|
+ {
|
||||||
|
+ errno = 0;
|
||||||
|
+ fd_file = fopen (temp_file, *p);
|
||||||
|
+ TEST_VERIFY (fd_file == NULL);
|
||||||
|
+ TEST_COMPARE (errno, EINVAL);
|
||||||
|
+ errno = 0;
|
||||||
|
+ fd_file = fopen ("/tmp/file-that-does-not-exist", *p);
|
||||||
|
+ TEST_VERIFY (fd_file == NULL);
|
||||||
|
+ TEST_COMPARE (errno, EINVAL);
|
||||||
|
+ ++p;
|
||||||
|
+ TEST_VERIFY (access ("/tmp/file-that-does-not-exist", F_OK) == -1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
|
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
|
||||||
|
index 43fcdf1182e735e1..58c33a8e49d517ad 100644
|
||||||
|
--- a/sysdeps/pthread/Makefile
|
||||||
|
+++ b/sysdeps/pthread/Makefile
|
||||||
|
@@ -131,6 +131,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
|
||||||
|
tst-sem18 \
|
||||||
|
tst-sem19 \
|
||||||
|
tst-join16 \
|
||||||
|
+ tst-fopen-threaded \
|
||||||
|
# tests
|
||||||
|
|
||||||
|
tests-time64 := \
|
||||||
|
diff --git a/sysdeps/pthread/tst-fopen-threaded.c b/sysdeps/pthread/tst-fopen-threaded.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..5c792c93e3711621
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/sysdeps/pthread/tst-fopen-threaded.c
|
||||||
|
@@ -0,0 +1,250 @@
|
||||||
|
+/* Test for fread and fwrite with multiple threads.
|
||||||
|
+ 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/>. */
|
||||||
|
+
|
||||||
|
+/* Description of test intent.
|
||||||
|
+ The test creates NUM_THREADS threads for reading and writing to the
|
||||||
|
+ prepared file. The prepared file contains 'NUM_THREADS - 1' bytes
|
||||||
|
+ where each byte is unique number from 0 to 'NUM_THREADS - 2'. If all
|
||||||
|
+ operations are correctly multi-threaded safe then all concurent read
|
||||||
|
+ operations should succeed and read a unique 1 byte value. The last
|
||||||
|
+ thread to read should get an EOF. In concurrent write, all write
|
||||||
|
+ operations should succeed and the file should contain all unique 1
|
||||||
|
+ byte values from 0 to 'NUM_THREADS - 1'. Both concurrent read and
|
||||||
|
+ concurrent write tests are repeated ITERS times to increase
|
||||||
|
+ the probability of detecting concurrency issues. */
|
||||||
|
+
|
||||||
|
+#include <errno.h>
|
||||||
|
+#include <pthread.h>
|
||||||
|
+#include <stdbool.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/temp_file.h>
|
||||||
|
+#include <support/xstdio.h>
|
||||||
|
+#include <support/xthread.h>
|
||||||
|
+
|
||||||
|
+#define NUM_THREADS 100
|
||||||
|
+#define ITERS 10
|
||||||
|
+
|
||||||
|
+char *temp_file;
|
||||||
|
+pthread_barrier_t barrier;
|
||||||
|
+
|
||||||
|
+struct thread_data
|
||||||
|
+{
|
||||||
|
+ FILE *fd;
|
||||||
|
+ /* Read value or value to be written. */
|
||||||
|
+ unsigned char value;
|
||||||
|
+ bool eof;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void *
|
||||||
|
+threadReadRoutine (void *argv)
|
||||||
|
+{
|
||||||
|
+ struct thread_data *my_data;
|
||||||
|
+ unsigned char read_buffer;
|
||||||
|
+ int ret = 0;
|
||||||
|
+ my_data = (struct thread_data *) argv;
|
||||||
|
+ /* Wait for all threads to be ready to read. */
|
||||||
|
+ xpthread_barrier_wait (&barrier);
|
||||||
|
+
|
||||||
|
+ ret =
|
||||||
|
+ fread (&read_buffer, sizeof (char), sizeof (read_buffer), my_data->fd);
|
||||||
|
+ if (feof (my_data->fd) != 0)
|
||||||
|
+ {
|
||||||
|
+ clearerr (my_data->fd);
|
||||||
|
+ my_data->eof = true;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ TEST_COMPARE (ret, 1);
|
||||||
|
+ /* Save the read value. */
|
||||||
|
+ my_data->value = read_buffer;
|
||||||
|
+ }
|
||||||
|
+ TEST_COMPARE (ferror (my_data->fd), 0);
|
||||||
|
+ return NULL;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void *
|
||||||
|
+threadWriteRoutine (void *argv)
|
||||||
|
+{
|
||||||
|
+ struct thread_data *my_data;
|
||||||
|
+ int ret = 0;
|
||||||
|
+ my_data = (struct thread_data *) argv;
|
||||||
|
+ /* Wait for all threads to be ready to write. */
|
||||||
|
+ xpthread_barrier_wait (&barrier);
|
||||||
|
+
|
||||||
|
+ ret = fwrite (&my_data->value, sizeof (unsigned char), 1, my_data->fd);
|
||||||
|
+ TEST_COMPARE (ferror (my_data->fd), 0);
|
||||||
|
+ TEST_COMPARE (feof (my_data->fd), 0);
|
||||||
|
+ TEST_COMPARE (ret, 1);
|
||||||
|
+ return NULL;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void *
|
||||||
|
+threadOpenCloseRoutine (void *argv)
|
||||||
|
+{
|
||||||
|
+ /* Wait for all threads to be ready to call fopen and fclose. */
|
||||||
|
+ xpthread_barrier_wait (&barrier);
|
||||||
|
+
|
||||||
|
+ FILE *fd = xfopen ("/tmp/openclosetest", "w+");
|
||||||
|
+ xfclose (fd);
|
||||||
|
+ return NULL;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ FILE *fd_file = NULL;
|
||||||
|
+ unsigned char buffer[NUM_THREADS] = "0";
|
||||||
|
+ size_t ret = 0;
|
||||||
|
+ pthread_t threads[NUM_THREADS];
|
||||||
|
+ struct thread_data thread_data_array[NUM_THREADS];
|
||||||
|
+ bool present_values[NUM_THREADS] = { false };
|
||||||
|
+
|
||||||
|
+ /* Prepare files. */
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ buffer[i] = i;
|
||||||
|
+ int fd = create_temp_file ("tst-fopen.", &temp_file);
|
||||||
|
+ TEST_VERIFY_EXIT (fd != -1);
|
||||||
|
+ fd_file = fdopen (fd, "w");
|
||||||
|
+ /* NUM_THREADS - 1: last thread will read EOF */
|
||||||
|
+ ret = fwrite (buffer, sizeof (unsigned char), NUM_THREADS - 1, fd_file);
|
||||||
|
+ TEST_COMPARE (ret, NUM_THREADS - 1);
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+
|
||||||
|
+ /* Test 1: Concurrent read. */
|
||||||
|
+ for (int reps = 1; reps <= ITERS; reps++)
|
||||||
|
+ {
|
||||||
|
+ fd_file = xfopen (temp_file, "r");
|
||||||
|
+ xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ {
|
||||||
|
+ thread_data_array[i].fd = fd_file;
|
||||||
|
+ /* Initialize with highest possible value so it's easier to debug if
|
||||||
|
+ anything goes wrong. */
|
||||||
|
+ thread_data_array[i].value = 255;
|
||||||
|
+ thread_data_array[i].eof = false;
|
||||||
|
+
|
||||||
|
+ threads[i] =
|
||||||
|
+ xpthread_create (support_small_stack_thread_attribute (),
|
||||||
|
+ threadReadRoutine,
|
||||||
|
+ (void *) &thread_data_array[i]);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ {
|
||||||
|
+ xpthread_join (threads[i]);
|
||||||
|
+ }
|
||||||
|
+ xpthread_barrier_destroy (&barrier);
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+
|
||||||
|
+ /* Verify read values. */
|
||||||
|
+ int eof_cnt = 0;
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ present_values[i] = false;
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ {
|
||||||
|
+ if (thread_data_array[i].eof)
|
||||||
|
+ {
|
||||||
|
+ /* EOF was read. */
|
||||||
|
+ present_values[NUM_THREADS - 1] = true;
|
||||||
|
+ eof_cnt++;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ /* The same value shouldn't be read twice. */
|
||||||
|
+ TEST_VERIFY (!present_values[thread_data_array[i].value]);
|
||||||
|
+ present_values[thread_data_array[i].value] = true;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ /* EOF is read exactly once. */
|
||||||
|
+ TEST_COMPARE (eof_cnt, 1);
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ {
|
||||||
|
+ /* All values should be read. */
|
||||||
|
+ TEST_VERIFY (present_values[i]);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Test 2: Concurrent write. */
|
||||||
|
+ for (int reps = 1; reps <= ITERS; reps++)
|
||||||
|
+ {
|
||||||
|
+ fd_file = xfopen (temp_file, "w");
|
||||||
|
+ xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ {
|
||||||
|
+ thread_data_array[i].fd = fd_file;
|
||||||
|
+ thread_data_array[i].value = i;
|
||||||
|
+
|
||||||
|
+ threads[i] =
|
||||||
|
+ xpthread_create (support_small_stack_thread_attribute (),
|
||||||
|
+ threadWriteRoutine,
|
||||||
|
+ (void *) &thread_data_array[i]);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ {
|
||||||
|
+ xpthread_join (threads[i]);
|
||||||
|
+ }
|
||||||
|
+ xpthread_barrier_destroy (&barrier);
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+
|
||||||
|
+ /* Verify written values. */
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ present_values[i] = false;
|
||||||
|
+ memset (buffer, 0, NUM_THREADS);
|
||||||
|
+ fd_file = xfopen (temp_file, "r");
|
||||||
|
+ ret = fread (buffer, sizeof (unsigned char), NUM_THREADS, fd_file);
|
||||||
|
+ TEST_COMPARE (ret, NUM_THREADS);
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ {
|
||||||
|
+ /* The same value shouldn't be written twice. */
|
||||||
|
+ TEST_VERIFY (!present_values[buffer[i]]);
|
||||||
|
+ present_values[buffer[i]] = true;
|
||||||
|
+ }
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ {
|
||||||
|
+ /* All values should be written. */
|
||||||
|
+ TEST_VERIFY (present_values[i]);
|
||||||
|
+ }
|
||||||
|
+ xfclose (fd_file);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Test 3: Concurrent open/close. */
|
||||||
|
+ for (int reps = 1; reps <= ITERS; reps++)
|
||||||
|
+ {
|
||||||
|
+ xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ {
|
||||||
|
+ threads[i] =
|
||||||
|
+ xpthread_create (support_small_stack_thread_attribute (),
|
||||||
|
+ threadOpenCloseRoutine, NULL);
|
||||||
|
+ }
|
||||||
|
+ for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
+ {
|
||||||
|
+ xpthread_join (threads[i]);
|
||||||
|
+ }
|
||||||
|
+ xpthread_barrier_destroy (&barrier);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
124
SOURCES/glibc-RHEL-46737-1.patch
Normal file
124
SOURCES/glibc-RHEL-46737-1.patch
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
From 81e74c8676479811601b5894d72bb3d7e05f68dd Mon Sep 17 00:00:00 2001
|
||||||
|
From: DJ Delorie <dj@redhat.com>
|
||||||
|
Date: Fri, 14 Mar 2025 16:08:12 -0400
|
||||||
|
Subject: add ptmx support to test-container
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
support/Makefile (context, line numbers)
|
||||||
|
support/test-container.c (line numbers)
|
||||||
|
|
||||||
|
diff --git a/support/Makefile b/support/Makefile
|
||||||
|
index dfe8e547f6..d41278eeab 100644
|
||||||
|
--- a/support/Makefile
|
||||||
|
+++ b/support/Makefile
|
||||||
|
@@ -324,6 +324,7 @@ tests = \
|
||||||
|
tst-support_format_dns_packet \
|
||||||
|
tst-support_fuse \
|
||||||
|
tst-support-open-dev-null-range \
|
||||||
|
+ tst-support-openpty \
|
||||||
|
tst-support-process_state \
|
||||||
|
tst-support_quote_blob \
|
||||||
|
tst-support_quote_blob_wide \
|
||||||
|
@@ -340,6 +341,10 @@ tests = \
|
||||||
|
tst-xsigstack \
|
||||||
|
# tests
|
||||||
|
|
||||||
|
+tests-container = \
|
||||||
|
+ tst-support-openpty-c \
|
||||||
|
+ # tests-container
|
||||||
|
+
|
||||||
|
ifeq ($(run-built-tests),yes)
|
||||||
|
tests-special = \
|
||||||
|
$(objpfx)tst-support_record_failure-2.out
|
||||||
|
diff --git a/support/test-container.c b/support/test-container.c
|
||||||
|
index 79d3189e2f..a641250079 100644
|
||||||
|
--- a/support/test-container.c
|
||||||
|
+++ b/support/test-container.c
|
||||||
|
@@ -1149,6 +1149,9 @@ main (int argc, char **argv)
|
||||||
|
devmount (new_root_path, "null");
|
||||||
|
devmount (new_root_path, "zero");
|
||||||
|
devmount (new_root_path, "urandom");
|
||||||
|
+#ifdef __linux__
|
||||||
|
+ devmount (new_root_path, "ptmx");
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
/* We're done with the "old" root, switch to the new one. */
|
||||||
|
if (chroot (new_root_path) < 0)
|
||||||
|
@@ -1214,6 +1217,14 @@ main (int argc, char **argv)
|
||||||
|
|
||||||
|
maybe_xmkdir ("/tmp", 0755);
|
||||||
|
|
||||||
|
+#ifdef __linux__
|
||||||
|
+ maybe_xmkdir ("/dev/pts", 0777);
|
||||||
|
+ if (mount ("/dev/pts", "/dev/pts", "devpts", 0, "newinstance,ptmxmode=0666,mode=0666") < 0)
|
||||||
|
+ FAIL_EXIT1 ("can't mount /dev/pts: %m\n");
|
||||||
|
+ if (mount ("/dev/pts/ptmx", "/dev/ptmx", "", MS_BIND | MS_REC, NULL) < 0)
|
||||||
|
+ FAIL_EXIT1 ("can't mount /dev/ptmx\n");
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
if (require_pidns)
|
||||||
|
{
|
||||||
|
/* Now that we're pid 1 (effectively "root") we can mount /proc */
|
||||||
|
diff --git a/support/tst-support-openpty-c.c b/support/tst-support-openpty-c.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000..0a6a428fc3
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/support/tst-support-openpty-c.c
|
||||||
|
@@ -0,0 +1,2 @@
|
||||||
|
+/* Same test, but in a test-container. */
|
||||||
|
+#include "tst-support-openpty.c"
|
||||||
|
diff --git a/support/tst-support-openpty.c b/support/tst-support-openpty.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000..1222d7018f
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/support/tst-support-openpty.c
|
||||||
|
@@ -0,0 +1,49 @@
|
||||||
|
+/* Basic test for support_openpty support in test-container.
|
||||||
|
+ 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 <termios.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+#include <sys/ioctl.h>
|
||||||
|
+
|
||||||
|
+#include <support/tty.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/support.h>
|
||||||
|
+
|
||||||
|
+/* Note: the purpose of this test isn't to test if ptys function
|
||||||
|
+ correctly, but only to verify that test-container's support for
|
||||||
|
+ them is correct. The many checks in support_openpty.c are
|
||||||
|
+ sufficient for this. */
|
||||||
|
+
|
||||||
|
+int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ int outer, inner;
|
||||||
|
+ char *name;
|
||||||
|
+ struct termios term;
|
||||||
|
+ struct winsize win;
|
||||||
|
+
|
||||||
|
+ cfmakeraw (&term);
|
||||||
|
+ win.ws_row = 24;
|
||||||
|
+ win.ws_col = 80;
|
||||||
|
+
|
||||||
|
+ support_openpty (&outer, &inner, &name, &term, &win);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
1092
SOURCES/glibc-RHEL-46737-2.patch
Normal file
1092
SOURCES/glibc-RHEL-46737-2.patch
Normal file
File diff suppressed because it is too large
Load Diff
112
SOURCES/glibc-RHEL-46737-3.patch
Normal file
112
SOURCES/glibc-RHEL-46737-3.patch
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
commit 4fa959d13d21b8f56a43aa0a416100303736c55c
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Tue Apr 8 10:39:44 2025 +0200
|
||||||
|
|
||||||
|
stdio-common: In tst-setvbuf2, close helper thread descriptor only if opened
|
||||||
|
|
||||||
|
The helper thread may get canceled before the open system
|
||||||
|
call succeds. Then ThreadData.fd remains zero, and eventually
|
||||||
|
the xclose call in end_reader_thread fails because descriptor 0
|
||||||
|
is not open.
|
||||||
|
|
||||||
|
Instead, initialize the fd member to -1 (not a valid descriptor)
|
||||||
|
and close the descriptor only if valid. Do this in a new end_thread
|
||||||
|
helper routine.
|
||||||
|
|
||||||
|
Also add more error checking to close operations.
|
||||||
|
|
||||||
|
Fixes commit 95b780c1d0549678c0a244c6e2112ec97edf0839 ("stdio: Add
|
||||||
|
more setvbuf tests").
|
||||||
|
|
||||||
|
diff --git a/stdio-common/tst-setvbuf2.c b/stdio-common/tst-setvbuf2.c
|
||||||
|
index 6cc83355f391afab..84d8b43a5811b4be 100644
|
||||||
|
--- a/stdio-common/tst-setvbuf2.c
|
||||||
|
+++ b/stdio-common/tst-setvbuf2.c
|
||||||
|
@@ -240,6 +240,21 @@ typedef struct {
|
||||||
|
/* It's OK if this is static, we only run one at a time. */
|
||||||
|
ThreadData thread_data;
|
||||||
|
|
||||||
|
+static void
|
||||||
|
+end_thread (pthread_t *ptid)
|
||||||
|
+{
|
||||||
|
+ if (*ptid)
|
||||||
|
+ {
|
||||||
|
+ pthread_cancel (*ptid);
|
||||||
|
+ xpthread_join (*ptid);
|
||||||
|
+ /* The descriptor was passed in, or the helper thread made
|
||||||
|
+ sufficient progress and opened the file. */
|
||||||
|
+ if (thread_data.fd >= 0)
|
||||||
|
+ xclose (thread_data.fd);
|
||||||
|
+ *ptid = 0;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void *
|
||||||
|
writer_thread_proc (void *closure)
|
||||||
|
{
|
||||||
|
@@ -306,7 +321,7 @@ static void
|
||||||
|
start_writer_thread_n (const char *fname)
|
||||||
|
{
|
||||||
|
debug;
|
||||||
|
- thread_data.fd = 0;
|
||||||
|
+ thread_data.fd = -1;
|
||||||
|
thread_data.fname = fname;
|
||||||
|
writer_thread_tid = xpthread_create (NULL, writer_thread_proc,
|
||||||
|
(void *)&thread_data);
|
||||||
|
@@ -316,13 +331,7 @@ static void
|
||||||
|
end_writer_thread (void)
|
||||||
|
{
|
||||||
|
debug;
|
||||||
|
- if (writer_thread_tid)
|
||||||
|
- {
|
||||||
|
- pthread_cancel (writer_thread_tid);
|
||||||
|
- xpthread_join (writer_thread_tid);
|
||||||
|
- xclose (thread_data.fd);
|
||||||
|
- writer_thread_tid = 0;
|
||||||
|
- }
|
||||||
|
+ end_thread (&writer_thread_tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
@@ -339,7 +348,7 @@ static void
|
||||||
|
start_reader_thread_n (const char *fname)
|
||||||
|
{
|
||||||
|
debug;
|
||||||
|
- thread_data.fd = 0;
|
||||||
|
+ thread_data.fd = -1;
|
||||||
|
thread_data.fname = fname;
|
||||||
|
reader_thread_tid = xpthread_create (NULL, reader_thread_proc,
|
||||||
|
(void *)&thread_data);
|
||||||
|
@@ -349,13 +358,7 @@ static void
|
||||||
|
end_reader_thread (void)
|
||||||
|
{
|
||||||
|
debug;
|
||||||
|
- if (reader_thread_tid)
|
||||||
|
- {
|
||||||
|
- pthread_cancel (reader_thread_tid);
|
||||||
|
- xpthread_join (reader_thread_tid);
|
||||||
|
- xclose (thread_data.fd);
|
||||||
|
- reader_thread_tid = 0;
|
||||||
|
- }
|
||||||
|
+ end_thread (&reader_thread_tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------*/
|
||||||
|
@@ -852,7 +855,7 @@ do_second_part (FILE *fp,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- fclose (fp);
|
||||||
|
+ xfclose (fp);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -939,7 +942,7 @@ recurse (FILE *fp,
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: /* parent */
|
||||||
|
- fclose (fp);
|
||||||
|
+ xfclose (fp);
|
||||||
|
xwaitpid (pid, &status, 0);
|
||||||
|
if (WIFEXITED (status)
|
||||||
|
&& WEXITSTATUS (status) == 0)
|
||||||
562
SOURCES/glibc-RHEL-47403-1.patch
Normal file
562
SOURCES/glibc-RHEL-47403-1.patch
Normal file
@ -0,0 +1,562 @@
|
|||||||
|
commit a93d9e03a31ec14405cb3a09aa95413b67067380
|
||||||
|
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||||
|
Date: Tue Aug 17 19:35:48 2021 -0700
|
||||||
|
|
||||||
|
Extend struct r_debug to support multiple namespaces [BZ #15971]
|
||||||
|
|
||||||
|
Glibc does not provide an interface for debugger to access libraries
|
||||||
|
loaded in multiple namespaces via dlmopen.
|
||||||
|
|
||||||
|
The current rtld-debugger interface is described in the file:
|
||||||
|
|
||||||
|
elf/rtld-debugger-interface.txt
|
||||||
|
|
||||||
|
under the "Standard debugger interface" heading. This interface only
|
||||||
|
provides access to the first link-map (LM_ID_BASE).
|
||||||
|
|
||||||
|
1. Bump r_version to 2 when multiple namespaces are used. This triggers
|
||||||
|
the GDB bug:
|
||||||
|
|
||||||
|
https://sourceware.org/bugzilla/show_bug.cgi?id=28236
|
||||||
|
|
||||||
|
2. Add struct r_debug_extended to extend struct r_debug into a linked-list,
|
||||||
|
where each element correlates to an unique namespace.
|
||||||
|
3. Initialize the r_debug_extended structure. Bump r_version to 2 for
|
||||||
|
the new namespace and add the new namespace to the namespace linked list.
|
||||||
|
4. Add _dl_debug_update to return the address of struct r_debug' of a
|
||||||
|
namespace.
|
||||||
|
5. Add a hidden symbol, _r_debug_extended, for struct r_debug_extended.
|
||||||
|
6. Provide the symbol, _r_debug, with size of struct r_debug, as an alias
|
||||||
|
of _r_debug_extended, for programs which reference _r_debug.
|
||||||
|
|
||||||
|
This fixes BZ #15971.
|
||||||
|
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/Makefile (fixup context due to reordering)
|
||||||
|
elf/dl-open.c (modified line didn't exist downstream)
|
||||||
|
|
||||||
|
diff --git a/csu/Makefile b/csu/Makefile
|
||||||
|
index 3054329cea4a276d..e2390e4a7deb6941 100644
|
||||||
|
--- a/csu/Makefile
|
||||||
|
+++ b/csu/Makefile
|
||||||
|
@@ -88,6 +88,9 @@ endif
|
||||||
|
before-compile += $(objpfx)abi-tag.h
|
||||||
|
generated += abi-tag.h
|
||||||
|
|
||||||
|
+# Put it here to generate it earlier.
|
||||||
|
+gen-as-const-headers += rtld-sizes.sym
|
||||||
|
+
|
||||||
|
# These are the special initializer/finalizer files. They are always the
|
||||||
|
# first and last file in the link. crti.o ... crtn.o define the global
|
||||||
|
# "functions" _init and _fini to run the .init and .fini sections.
|
||||||
|
diff --git a/csu/rtld-sizes.sym b/csu/rtld-sizes.sym
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..13924d5efdbaa248
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/csu/rtld-sizes.sym
|
||||||
|
@@ -0,0 +1,6 @@
|
||||||
|
+#include <link.h>
|
||||||
|
+
|
||||||
|
+--
|
||||||
|
+R_DEBUG_SIZE sizeof (struct r_debug)
|
||||||
|
+R_DEBUG_EXTENDED_SIZE sizeof (struct r_debug_extended)
|
||||||
|
+R_DEBUG_EXTENDED_ALIGN __alignof (struct r_debug_extended)
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index 15bec14364266c77..b074cc29664b3e20 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -54,6 +54,7 @@ dl-routines = \
|
||||||
|
dl-catch \
|
||||||
|
dl-close \
|
||||||
|
dl-debug \
|
||||||
|
+ dl-debug-symbols \
|
||||||
|
dl-deps \
|
||||||
|
dl-exception \
|
||||||
|
dl-execstack \
|
||||||
|
@@ -399,6 +400,7 @@ tests += \
|
||||||
|
tst-dlmodcount \
|
||||||
|
tst-dlmopen1 \
|
||||||
|
tst-dlmopen3 \
|
||||||
|
+ tst-dlmopen4 \
|
||||||
|
tst-dlmopen-dlerror \
|
||||||
|
tst-dlmopen-gethostbyname \
|
||||||
|
tst-dlmopen-twice \
|
||||||
|
@@ -1973,6 +1975,8 @@ $(objpfx)tst-dlmopen2.out: $(objpfx)tst-dlmopen1mod.so
|
||||||
|
|
||||||
|
$(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
|
||||||
|
|
||||||
|
+$(objpfx)tst-dlmopen4.out: $(objpfx)tst-dlmopen1mod.so
|
||||||
|
+
|
||||||
|
$(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
|
||||||
|
tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||||
|
|
||||||
|
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||||
|
index 9d158c25498fd8ae..bf699e58d753a1e2 100644
|
||||||
|
--- a/elf/dl-close.c
|
||||||
|
+++ b/elf/dl-close.c
|
||||||
|
@@ -469,7 +469,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Notify the debugger we are about to remove some loaded objects. */
|
||||||
|
- struct r_debug *r = _dl_debug_initialize (0, nsid);
|
||||||
|
+ struct r_debug *r = _dl_debug_update (nsid);
|
||||||
|
r->r_state = RT_DELETE;
|
||||||
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (unmap_start, 2, nsid, r);
|
||||||
|
diff --git a/elf/dl-debug-symbols.S b/elf/dl-debug-symbols.S
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..b7e9f5d9470c4da2
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/dl-debug-symbols.S
|
||||||
|
@@ -0,0 +1,36 @@
|
||||||
|
+/* Define symbols used to communicate dynamic linker state to the
|
||||||
|
+ debugger at runtime.
|
||||||
|
+ Copyright (C) 2021 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 <rtld-sizes.h>
|
||||||
|
+
|
||||||
|
+/* Define 2 symbols, _r_debug_extended and _r_debug, which is an alias
|
||||||
|
+ of _r_debug_extended, but with the size of struct r_debug. */
|
||||||
|
+
|
||||||
|
+ .globl _r_debug
|
||||||
|
+ .type _r_debug, %object
|
||||||
|
+ .size _r_debug, R_DEBUG_SIZE
|
||||||
|
+ .hidden _r_debug_extended
|
||||||
|
+ .globl _r_debug_extended
|
||||||
|
+ .type _r_debug_extended, %object
|
||||||
|
+ .size _r_debug_extended, R_DEBUG_EXTENDED_SIZE
|
||||||
|
+ .section .bss
|
||||||
|
+ .balign R_DEBUG_EXTENDED_ALIGN
|
||||||
|
+_r_debug:
|
||||||
|
+_r_debug_extended:
|
||||||
|
+ .zero R_DEBUG_EXTENDED_SIZE
|
||||||
|
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
|
||||||
|
index 2cd5f0975380445c..f637d4bb8de3db8c 100644
|
||||||
|
--- a/elf/dl-debug.c
|
||||||
|
+++ b/elf/dl-debug.c
|
||||||
|
@@ -30,37 +30,80 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
|
||||||
|
&& VERIFY_MEMBER (l_prev))
|
||||||
|
? 1 : -1];
|
||||||
|
|
||||||
|
-/* This structure communicates dl state to the debugger. The debugger
|
||||||
|
- normally finds it via the DT_DEBUG entry in the dynamic section, but in
|
||||||
|
- a statically-linked program there is no dynamic section for the debugger
|
||||||
|
- to examine and it looks for this particular symbol name. */
|
||||||
|
-struct r_debug _r_debug;
|
||||||
|
+/* Update the `r_map' member and return the address of `struct r_debug'
|
||||||
|
+ of the namespace NS. */
|
||||||
|
|
||||||
|
+struct r_debug *
|
||||||
|
+_dl_debug_update (Lmid_t ns)
|
||||||
|
+{
|
||||||
|
+ struct r_debug_extended *r;
|
||||||
|
+ if (ns == LM_ID_BASE)
|
||||||
|
+ r = &_r_debug_extended;
|
||||||
|
+ else
|
||||||
|
+ r = &GL(dl_ns)[ns]._ns_debug;
|
||||||
|
+ if (r->base.r_map == NULL)
|
||||||
|
+ atomic_store_release (&r->base.r_map,
|
||||||
|
+ (void *) GL(dl_ns)[ns]._ns_loaded);
|
||||||
|
+ return &r->base;
|
||||||
|
+}
|
||||||
|
|
||||||
|
-/* Initialize _r_debug if it has not already been done. The argument is
|
||||||
|
- the run-time load address of the dynamic linker, to be put in
|
||||||
|
- _r_debug.r_ldbase. Returns the address of _r_debug. */
|
||||||
|
+/* Initialize _r_debug_extended for the namespace NS. LDBASE is the
|
||||||
|
+ run-time load address of the dynamic linker, to be put in
|
||||||
|
+ _r_debug_extended.r_ldbase. Return the address of _r_debug. */
|
||||||
|
|
||||||
|
struct r_debug *
|
||||||
|
_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||||
|
{
|
||||||
|
- struct r_debug *r;
|
||||||
|
+ struct r_debug_extended *r, **pp = NULL;
|
||||||
|
|
||||||
|
if (ns == LM_ID_BASE)
|
||||||
|
- r = &_r_debug;
|
||||||
|
- else
|
||||||
|
- r = &GL(dl_ns)[ns]._ns_debug;
|
||||||
|
+ {
|
||||||
|
+ r = &_r_debug_extended;
|
||||||
|
+ /* Initialize r_version to 1. */
|
||||||
|
+ if (_r_debug_extended.base.r_version == 0)
|
||||||
|
+ _r_debug_extended.base.r_version = 1;
|
||||||
|
+ }
|
||||||
|
+ else if (DL_NNS > 1)
|
||||||
|
+ {
|
||||||
|
+ r = &GL(dl_ns)[ns]._ns_debug;
|
||||||
|
+ if (r->base.r_brk == 0)
|
||||||
|
+ {
|
||||||
|
+ /* Add the new namespace to the linked list. After a namespace
|
||||||
|
+ is initialized, r_brk becomes non-zero. A namespace becomes
|
||||||
|
+ empty (r_map == NULL) when it is unused. But it is never
|
||||||
|
+ removed from the linked list. */
|
||||||
|
+ struct r_debug_extended *p;
|
||||||
|
+ for (pp = &_r_debug_extended.r_next;
|
||||||
|
+ (p = *pp) != NULL;
|
||||||
|
+ pp = &p->r_next)
|
||||||
|
+ ;
|
||||||
|
+
|
||||||
|
+ r->base.r_version = 2;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (r->base.r_brk == 0)
|
||||||
|
+ {
|
||||||
|
+ /* Tell the debugger where to find the map of loaded objects.
|
||||||
|
+ This function is called from dlopen. Initialize the namespace
|
||||||
|
+ only once. */
|
||||||
|
+ r->base.r_ldbase = ldbase ?: _r_debug_extended.base.r_ldbase;
|
||||||
|
+ r->base.r_brk = (ElfW(Addr)) &_dl_debug_state;
|
||||||
|
+ r->r_next = NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (r->base.r_map == NULL)
|
||||||
|
+ atomic_store_release (&r->base.r_map,
|
||||||
|
+ (void *) GL(dl_ns)[ns]._ns_loaded);
|
||||||
|
|
||||||
|
- if (r->r_map == NULL || ldbase != 0)
|
||||||
|
+ if (pp != NULL)
|
||||||
|
{
|
||||||
|
- /* Tell the debugger where to find the map of loaded objects. */
|
||||||
|
- r->r_version = 1 /* R_DEBUG_VERSION XXX */;
|
||||||
|
- r->r_ldbase = ldbase ?: _r_debug.r_ldbase;
|
||||||
|
- r->r_map = (void *) GL(dl_ns)[ns]._ns_loaded;
|
||||||
|
- r->r_brk = (ElfW(Addr)) &_dl_debug_state;
|
||||||
|
+ atomic_store_release (pp, r);
|
||||||
|
+ /* Bump r_version to 2 for the new namespace. */
|
||||||
|
+ atomic_store_release (&_r_debug_extended.base.r_version, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
- return r;
|
||||||
|
+ return &r->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/elf/dl-load.c b/elf/dl-load.c
|
||||||
|
index eb6b658b698f5694..5b0734c816b351f0 100644
|
||||||
|
--- a/elf/dl-load.c
|
||||||
|
+++ b/elf/dl-load.c
|
||||||
|
@@ -950,7 +950,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||||
|
/* Initialize to keep the compiler happy. */
|
||||||
|
const char *errstring = NULL;
|
||||||
|
int errval = 0;
|
||||||
|
- struct r_debug *r = _dl_debug_initialize (0, nsid);
|
||||||
|
+ struct r_debug *r = _dl_debug_update (nsid);
|
||||||
|
bool make_consistent = false;
|
||||||
|
|
||||||
|
/* Get file information. To match the kernel behavior, do not fill
|
||||||
|
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||||
|
index 80af6518d4395906..eef724f7e9b2211d 100644
|
||||||
|
--- a/elf/dl-open.c
|
||||||
|
+++ b/elf/dl-open.c
|
||||||
|
@@ -596,7 +596,7 @@ dl_open_worker_begin (void *a)
|
||||||
|
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||||
|
add_to_global_update (new);
|
||||||
|
|
||||||
|
- assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
|
||||||
|
+ assert (_dl_debug_update (args->nsid)->r_state == RT_CONSISTENT);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@@ -634,7 +634,7 @@ dl_open_worker_begin (void *a)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Notify the debugger all new objects are now ready to go. */
|
||||||
|
- struct r_debug *r = _dl_debug_initialize (0, args->nsid);
|
||||||
|
+ struct r_debug *r = _dl_debug_update (args->nsid);
|
||||||
|
r->r_state = RT_CONSISTENT;
|
||||||
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (map_complete, 3, args->nsid, r, new);
|
||||||
|
@@ -840,7 +840,7 @@ no more namespaces available for dlmopen()"));
|
||||||
|
}
|
||||||
|
|
||||||
|
GL(dl_ns)[nsid].libc_map = NULL;
|
||||||
|
- _dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT;
|
||||||
|
+ _dl_debug_update (nsid)->r_state = RT_CONSISTENT;
|
||||||
|
}
|
||||||
|
/* Never allow loading a DSO in a namespace which is empty. Such
|
||||||
|
direct placements is only causing problems. Also don't allow
|
||||||
|
@@ -916,7 +916,7 @@ no more namespaces available for dlmopen()"));
|
||||||
|
_dl_signal_exception (errcode, &exception, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
- assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
|
||||||
|
+ assert (_dl_debug_update (args.nsid)->r_state == RT_CONSISTENT);
|
||||||
|
|
||||||
|
/* Release the lock. */
|
||||||
|
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||||
|
diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
|
||||||
|
index 757205affe65d9e1..5b85df8a2eed1888 100644
|
||||||
|
--- a/elf/dl-reloc-static-pie.c
|
||||||
|
+++ b/elf/dl-reloc-static-pie.c
|
||||||
|
@@ -62,7 +62,7 @@ _dl_relocate_static_pie (void)
|
||||||
|
ELF_DYNAMIC_RELOCATE (main_map, NULL, 0, 0, 0);
|
||||||
|
main_map->l_relocated = 1;
|
||||||
|
|
||||||
|
- /* Initialize _r_debug. */
|
||||||
|
+ /* Initialize _r_debug_extended. */
|
||||||
|
struct r_debug *r = _dl_debug_initialize (0, LM_ID_BASE);
|
||||||
|
r->r_state = RT_CONSISTENT;
|
||||||
|
|
||||||
|
diff --git a/elf/link.h b/elf/link.h
|
||||||
|
index 21a351686b9bf7c8..0906bbe33fbd9f8f 100644
|
||||||
|
--- a/elf/link.h
|
||||||
|
+++ b/elf/link.h
|
||||||
|
@@ -34,14 +34,13 @@
|
||||||
|
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
|
||||||
|
#include <bits/link.h>
|
||||||
|
|
||||||
|
-/* Rendezvous structure used by the run-time dynamic linker to communicate
|
||||||
|
- details of shared object loading to the debugger. If the executable's
|
||||||
|
- dynamic section has a DT_DEBUG element, the run-time linker sets that
|
||||||
|
- element's value to the address where this structure can be found. */
|
||||||
|
+/* The legacy rendezvous structure used by the run-time dynamic linker to
|
||||||
|
+ communicate details of shared object loading to the debugger. */
|
||||||
|
|
||||||
|
struct r_debug
|
||||||
|
{
|
||||||
|
- int r_version; /* Version number for this protocol. */
|
||||||
|
+ /* Version number for this protocol. It should be greater than 0. */
|
||||||
|
+ int r_version;
|
||||||
|
|
||||||
|
struct link_map *r_map; /* Head of the chain of loaded objects. */
|
||||||
|
|
||||||
|
@@ -63,16 +62,34 @@ struct r_debug
|
||||||
|
ElfW(Addr) r_ldbase; /* Base address the linker is loaded at. */
|
||||||
|
};
|
||||||
|
|
||||||
|
-/* This is the instance of that structure used by the dynamic linker. */
|
||||||
|
+/* This is the symbol of that structure provided by the dynamic linker. */
|
||||||
|
extern struct r_debug _r_debug;
|
||||||
|
|
||||||
|
+/* The extended rendezvous structure used by the run-time dynamic linker
|
||||||
|
+ to communicate details of shared object loading to the debugger. If
|
||||||
|
+ the executable's dynamic section has a DT_DEBUG element, the run-time
|
||||||
|
+ linker sets that element's value to the address where this structure
|
||||||
|
+ can be found. */
|
||||||
|
+
|
||||||
|
+struct r_debug_extended
|
||||||
|
+ {
|
||||||
|
+ struct r_debug base;
|
||||||
|
+
|
||||||
|
+ /* The following field is added by r_version == 2. */
|
||||||
|
+
|
||||||
|
+ /* Link to the next r_debug_extended structure. Each r_debug_extended
|
||||||
|
+ structure represents a different namespace. The first
|
||||||
|
+ r_debug_extended structure is for the default namespace. */
|
||||||
|
+ struct r_debug_extended *r_next;
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
/* This symbol refers to the "dynamic structure" in the `.dynamic' section
|
||||||
|
of whatever module refers to `_DYNAMIC'. So, to find its own
|
||||||
|
- `struct r_debug', a program could do:
|
||||||
|
+ `struct r_debug_extended', a program could do:
|
||||||
|
for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; ++dyn)
|
||||||
|
if (dyn->d_tag == DT_DEBUG)
|
||||||
|
- r_debug = (struct r_debug *) dyn->d_un.d_ptr;
|
||||||
|
- */
|
||||||
|
+ r_debug_extended = (struct r_debug_extended *) dyn->d_un.d_ptr;
|
||||||
|
+ */
|
||||||
|
extern ElfW(Dyn) _DYNAMIC[];
|
||||||
|
|
||||||
|
/* Structure describing a loaded shared object. The `l_next' and `l_prev'
|
||||||
|
diff --git a/elf/rtld-debugger-interface.txt b/elf/rtld-debugger-interface.txt
|
||||||
|
index 61bc99e4b086612f..f3476d8308616f84 100644
|
||||||
|
--- a/elf/rtld-debugger-interface.txt
|
||||||
|
+++ b/elf/rtld-debugger-interface.txt
|
||||||
|
@@ -9,6 +9,9 @@ structure can be found.
|
||||||
|
|
||||||
|
The r_debug structure contains (amongst others) the following fields:
|
||||||
|
|
||||||
|
+ int r_version:
|
||||||
|
+ Version number for this protocol. It should be greater than 0.
|
||||||
|
+
|
||||||
|
struct link_map *r_map:
|
||||||
|
A linked list of loaded objects.
|
||||||
|
|
||||||
|
@@ -32,6 +35,18 @@ but there is no way for the debugger to discover whether any of the
|
||||||
|
objects in the link-map have been relocated or not.
|
||||||
|
|
||||||
|
|
||||||
|
+Extension to the r_debug structure
|
||||||
|
+==================================
|
||||||
|
+
|
||||||
|
+The r_debug_extended structure is an extension of the r_debug interface.
|
||||||
|
+If r_version is 2, one additional field is available:
|
||||||
|
+
|
||||||
|
+ struct r_debug_extended *r_next;
|
||||||
|
+ Link to the next r_debug_extended structure. Each r_debug_extended
|
||||||
|
+ structure represents a different namespace. A namespace is active
|
||||||
|
+ if its r_map field isn't NULL. The first r_debug_extended structure
|
||||||
|
+ is for the default namespace.
|
||||||
|
+
|
||||||
|
Probe-based debugger interface
|
||||||
|
==============================
|
||||||
|
|
||||||
|
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||||
|
index d3d9e6b904ac78fd..7d8ed0ac1188d527 100644
|
||||||
|
--- a/elf/rtld.c
|
||||||
|
+++ b/elf/rtld.c
|
||||||
|
@@ -1725,7 +1725,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
objects. */
|
||||||
|
call_init_paths (&state);
|
||||||
|
|
||||||
|
- /* Initialize _r_debug. */
|
||||||
|
+ /* Initialize _r_debug_extended. */
|
||||||
|
struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr,
|
||||||
|
LM_ID_BASE);
|
||||||
|
r->r_state = RT_CONSISTENT;
|
||||||
|
@@ -2531,7 +2531,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
|
||||||
|
/* Notify the debugger all new objects are now ready to go. We must re-get
|
||||||
|
the address since by now the variable might be in another object. */
|
||||||
|
- r = _dl_debug_initialize (0, LM_ID_BASE);
|
||||||
|
+ r = _dl_debug_update (LM_ID_BASE);
|
||||||
|
r->r_state = RT_CONSISTENT;
|
||||||
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
|
||||||
|
diff --git a/elf/tst-dlmopen4.c b/elf/tst-dlmopen4.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..3fe150e50bc259f0
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-dlmopen4.c
|
||||||
|
@@ -0,0 +1,72 @@
|
||||||
|
+/* Test struct r_debug_extended via DT_DEBUG.
|
||||||
|
+ Copyright (C) 2021 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 <stdio.h>
|
||||||
|
+#include <link.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <gnu/lib-names.h>
|
||||||
|
+#include <support/xdlfcn.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/test-driver.h>
|
||||||
|
+
|
||||||
|
+#ifndef ELF_MACHINE_GET_R_DEBUG
|
||||||
|
+# define ELF_MACHINE_GET_R_DEBUG(d) \
|
||||||
|
+ (__extension__ ({ \
|
||||||
|
+ struct r_debug_extended *debug; \
|
||||||
|
+ if ((d)->d_tag == DT_DEBUG) \
|
||||||
|
+ debug = (struct r_debug_extended *) (d)->d_un.d_ptr; \
|
||||||
|
+ else \
|
||||||
|
+ debug = NULL; \
|
||||||
|
+ debug; }))
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ ElfW(Dyn) *d;
|
||||||
|
+ struct r_debug_extended *debug = NULL;
|
||||||
|
+
|
||||||
|
+ for (d = _DYNAMIC; d->d_tag != DT_NULL; ++d)
|
||||||
|
+ {
|
||||||
|
+ debug = ELF_MACHINE_GET_R_DEBUG (d);
|
||||||
|
+ if (debug != NULL)
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ TEST_VERIFY_EXIT (debug != NULL);
|
||||||
|
+ TEST_COMPARE (debug->base.r_version, 1);
|
||||||
|
+ TEST_VERIFY_EXIT (debug->r_next == NULL);
|
||||||
|
+
|
||||||
|
+ void *h = xdlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so",
|
||||||
|
+ RTLD_LAZY);
|
||||||
|
+
|
||||||
|
+ TEST_COMPARE (debug->base.r_version, 2);
|
||||||
|
+ TEST_VERIFY_EXIT (debug->r_next != NULL);
|
||||||
|
+ TEST_VERIFY_EXIT (debug->r_next->r_next == NULL);
|
||||||
|
+ TEST_VERIFY_EXIT (debug->r_next->base.r_map != NULL);
|
||||||
|
+ TEST_VERIFY_EXIT (debug->r_next->base.r_map->l_name != NULL);
|
||||||
|
+ const char *name = basename (debug->r_next->base.r_map->l_name);
|
||||||
|
+ TEST_COMPARE_STRING (name, "tst-dlmopen1mod.so");
|
||||||
|
+
|
||||||
|
+ xdlclose (h);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
|
diff --git a/include/link.h b/include/link.h
|
||||||
|
index 0dc63ef37d6a5666..0cf130ddb8af2e89 100644
|
||||||
|
--- a/include/link.h
|
||||||
|
+++ b/include/link.h
|
||||||
|
@@ -362,6 +362,10 @@ struct auditstate
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
+/* This is the hidden instance of struct r_debug_extended used by the
|
||||||
|
+ dynamic linker. */
|
||||||
|
+extern struct r_debug_extended _r_debug_extended attribute_hidden;
|
||||||
|
+
|
||||||
|
#if __ELF_NATIVE_CLASS == 32
|
||||||
|
# define symbind symbind32
|
||||||
|
# define LA_SYMBIND "la_symbind32"
|
||||||
|
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||||
|
index dc4e0555e4ed7f3c..695f3910234e87da 100644
|
||||||
|
--- a/sysdeps/generic/ldsodefs.h
|
||||||
|
+++ b/sysdeps/generic/ldsodefs.h
|
||||||
|
@@ -376,7 +376,7 @@ struct rtld_global
|
||||||
|
void (*free) (void *);
|
||||||
|
} _ns_unique_sym_table;
|
||||||
|
/* Keep track of changes to each namespace' list. */
|
||||||
|
- struct r_debug _ns_debug;
|
||||||
|
+ struct r_debug_extended _ns_debug;
|
||||||
|
} _dl_ns[DL_NNS];
|
||||||
|
/* One higher than index of last used namespace. */
|
||||||
|
EXTERN size_t _dl_nns;
|
||||||
|
@@ -1128,12 +1128,16 @@ extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||||
|
extern void _dl_debug_state (void);
|
||||||
|
rtld_hidden_proto (_dl_debug_state)
|
||||||
|
|
||||||
|
-/* Initialize `struct r_debug' if it has not already been done. The
|
||||||
|
- argument is the run-time load address of the dynamic linker, to be put
|
||||||
|
- in the `r_ldbase' member. Returns the address of the structure. */
|
||||||
|
+/* Initialize `struct r_debug_extended' for the namespace NS. LDBASE
|
||||||
|
+ is the run-time load address of the dynamic linker, to be put in the
|
||||||
|
+ `r_ldbase' member. Return the address of the structure. */
|
||||||
|
extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||||
|
attribute_hidden;
|
||||||
|
|
||||||
|
+/* Update the `r_map' member and return the address of `struct r_debug'
|
||||||
|
+ of the namespace NS. */
|
||||||
|
+extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden;
|
||||||
|
+
|
||||||
|
/* Initialize the basic data structure for the search paths. SOURCE
|
||||||
|
is either "LD_LIBRARY_PATH" or "--library-path".
|
||||||
|
GLIBC_HWCAPS_PREPEND adds additional glibc-hwcaps subdirectories to
|
||||||
158
SOURCES/glibc-RHEL-47403-10.patch
Normal file
158
SOURCES/glibc-RHEL-47403-10.patch
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
commit 7278d11f3a0cd528188c719bab75575b0aea2c6e
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Jul 4 21:46:05 2025 +0200
|
||||||
|
|
||||||
|
elf: Introduce separate _r_debug_array variable
|
||||||
|
|
||||||
|
It replaces the ns_debug member of the namespaces. Previously,
|
||||||
|
the base namespace had an unused ns_debug member.
|
||||||
|
|
||||||
|
This change also fixes a concurrency issue: Now _dl_debug_initialize
|
||||||
|
only updates r_next of the previous namespace's r_debug after the new
|
||||||
|
r_debug is initialized, so that only the initialized version is
|
||||||
|
observed. (Client code accessing _r_debug will benefit from load
|
||||||
|
dependency tracking in CPUs even without explicit barriers.)
|
||||||
|
|
||||||
|
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||||||
|
|
||||||
|
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
|
||||||
|
index f637d4bb8de3db8c..649386d5a6b885ed 100644
|
||||||
|
--- a/elf/dl-debug.c
|
||||||
|
+++ b/elf/dl-debug.c
|
||||||
|
@@ -30,17 +30,37 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
|
||||||
|
&& VERIFY_MEMBER (l_prev))
|
||||||
|
? 1 : -1];
|
||||||
|
|
||||||
|
+#ifdef SHARED
|
||||||
|
+/* r_debug structs for secondary namespaces. The first namespace is
|
||||||
|
+ handled separately because its r_debug structure must overlap with
|
||||||
|
+ the public _r_debug symbol, so the first array element corresponds
|
||||||
|
+ to LM_ID_BASE + 1. See elf/dl-debug-symbols.S. */
|
||||||
|
+struct r_debug_extended _r_debug_array[DL_NNS - 1];
|
||||||
|
+
|
||||||
|
+/* Return the r_debug object for the namespace NS. */
|
||||||
|
+static inline struct r_debug_extended *
|
||||||
|
+get_rdebug (Lmid_t ns)
|
||||||
|
+{
|
||||||
|
+ if (ns == LM_ID_BASE)
|
||||||
|
+ return &_r_debug_extended;
|
||||||
|
+ else
|
||||||
|
+ return &_r_debug_array[ns - 1];
|
||||||
|
+}
|
||||||
|
+#else /* !SHARED */
|
||||||
|
+static inline struct r_debug_extended *
|
||||||
|
+get_rdebug (Lmid_t ns)
|
||||||
|
+{
|
||||||
|
+ return &_r_debug_extended; /* There is just one namespace. */
|
||||||
|
+}
|
||||||
|
+#endif /* !SHARED */
|
||||||
|
+
|
||||||
|
/* Update the `r_map' member and return the address of `struct r_debug'
|
||||||
|
of the namespace NS. */
|
||||||
|
|
||||||
|
struct r_debug *
|
||||||
|
_dl_debug_update (Lmid_t ns)
|
||||||
|
{
|
||||||
|
- struct r_debug_extended *r;
|
||||||
|
- if (ns == LM_ID_BASE)
|
||||||
|
- r = &_r_debug_extended;
|
||||||
|
- else
|
||||||
|
- r = &GL(dl_ns)[ns]._ns_debug;
|
||||||
|
+ struct r_debug_extended *r = get_rdebug (ns);
|
||||||
|
if (r->base.r_map == NULL)
|
||||||
|
atomic_store_release (&r->base.r_map,
|
||||||
|
(void *) GL(dl_ns)[ns]._ns_loaded);
|
||||||
|
@@ -54,34 +74,7 @@ _dl_debug_update (Lmid_t ns)
|
||||||
|
struct r_debug *
|
||||||
|
_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||||
|
{
|
||||||
|
- struct r_debug_extended *r, **pp = NULL;
|
||||||
|
-
|
||||||
|
- if (ns == LM_ID_BASE)
|
||||||
|
- {
|
||||||
|
- r = &_r_debug_extended;
|
||||||
|
- /* Initialize r_version to 1. */
|
||||||
|
- if (_r_debug_extended.base.r_version == 0)
|
||||||
|
- _r_debug_extended.base.r_version = 1;
|
||||||
|
- }
|
||||||
|
- else if (DL_NNS > 1)
|
||||||
|
- {
|
||||||
|
- r = &GL(dl_ns)[ns]._ns_debug;
|
||||||
|
- if (r->base.r_brk == 0)
|
||||||
|
- {
|
||||||
|
- /* Add the new namespace to the linked list. After a namespace
|
||||||
|
- is initialized, r_brk becomes non-zero. A namespace becomes
|
||||||
|
- empty (r_map == NULL) when it is unused. But it is never
|
||||||
|
- removed from the linked list. */
|
||||||
|
- struct r_debug_extended *p;
|
||||||
|
- for (pp = &_r_debug_extended.r_next;
|
||||||
|
- (p = *pp) != NULL;
|
||||||
|
- pp = &p->r_next)
|
||||||
|
- ;
|
||||||
|
-
|
||||||
|
- r->base.r_version = 2;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
+ struct r_debug_extended *r = get_rdebug (ns);
|
||||||
|
if (r->base.r_brk == 0)
|
||||||
|
{
|
||||||
|
/* Tell the debugger where to find the map of loaded objects.
|
||||||
|
@@ -89,20 +82,36 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||||
|
only once. */
|
||||||
|
r->base.r_ldbase = ldbase ?: _r_debug_extended.base.r_ldbase;
|
||||||
|
r->base.r_brk = (ElfW(Addr)) &_dl_debug_state;
|
||||||
|
- r->r_next = NULL;
|
||||||
|
+
|
||||||
|
+#ifdef SHARED
|
||||||
|
+ /* Add the new namespace to the linked list. This assumes that
|
||||||
|
+ namespaces are allocated in increasing order. After a
|
||||||
|
+ namespace is initialized, r_brk becomes non-zero. A
|
||||||
|
+ namespace becomes empty (r_map == NULL) when it is unused.
|
||||||
|
+ But it is never removed from the linked list. */
|
||||||
|
+
|
||||||
|
+ if (ns != LM_ID_BASE)
|
||||||
|
+ {
|
||||||
|
+ r->base.r_version = 2;
|
||||||
|
+ if (ns - 1 == LM_ID_BASE)
|
||||||
|
+ {
|
||||||
|
+ atomic_store_release (&_r_debug_extended.r_next, r);
|
||||||
|
+ /* Now there are multiple namespaces. */
|
||||||
|
+ atomic_store_release (&_r_debug_extended.base.r_version, 2);
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ /* Update r_debug_extended of the previous namespace. */
|
||||||
|
+ atomic_store_release (&_r_debug_array[ns - 2].r_next, r);
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+#endif /* SHARED */
|
||||||
|
+ r->base.r_version = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->base.r_map == NULL)
|
||||||
|
atomic_store_release (&r->base.r_map,
|
||||||
|
(void *) GL(dl_ns)[ns]._ns_loaded);
|
||||||
|
|
||||||
|
- if (pp != NULL)
|
||||||
|
- {
|
||||||
|
- atomic_store_release (pp, r);
|
||||||
|
- /* Bump r_version to 2 for the new namespace. */
|
||||||
|
- atomic_store_release (&_r_debug_extended.base.r_version, 2);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
return &r->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||||
|
index 695f3910234e87da..e09edb01da3b5b90 100644
|
||||||
|
--- a/sysdeps/generic/ldsodefs.h
|
||||||
|
+++ b/sysdeps/generic/ldsodefs.h
|
||||||
|
@@ -375,8 +375,6 @@ struct rtld_global
|
||||||
|
size_t n_elements;
|
||||||
|
void (*free) (void *);
|
||||||
|
} _ns_unique_sym_table;
|
||||||
|
- /* Keep track of changes to each namespace' list. */
|
||||||
|
- struct r_debug_extended _ns_debug;
|
||||||
|
} _dl_ns[DL_NNS];
|
||||||
|
/* One higher than index of last used namespace. */
|
||||||
|
EXTERN size_t _dl_nns;
|
||||||
17
SOURCES/glibc-RHEL-47403-11.patch
Normal file
17
SOURCES/glibc-RHEL-47403-11.patch
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Downstream patch to keep ABI stable.
|
||||||
|
Bring back a dummy `struct r_debug` member in `GL (dl_ns)`, to preserve
|
||||||
|
`_rtld_global` layout.
|
||||||
|
|
||||||
|
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||||
|
index e09edb01da3b5b90..3d9b90a22bfa6a7d 100644
|
||||||
|
--- a/sysdeps/generic/ldsodefs.h
|
||||||
|
+++ b/sysdeps/generic/ldsodefs.h
|
||||||
|
@@ -375,6 +375,8 @@ struct rtld_global
|
||||||
|
size_t n_elements;
|
||||||
|
void (*free) (void *);
|
||||||
|
} _ns_unique_sym_table;
|
||||||
|
+ /* Dummy structure to keep the ABI stable. */
|
||||||
|
+ struct r_debug _ns_debug_unused;
|
||||||
|
} _dl_ns[DL_NNS];
|
||||||
|
/* One higher than index of last used namespace. */
|
||||||
|
EXTERN size_t _dl_nns;
|
||||||
26
SOURCES/glibc-RHEL-47403-2.patch
Normal file
26
SOURCES/glibc-RHEL-47403-2.patch
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
commit 7e84ac3a3ac9e7c4dc10de2ce65db971b9650e4d
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Mon Sep 20 15:50:00 2021 +0200
|
||||||
|
|
||||||
|
elf: Include <sysdep.h> in elf/dl-debug-symbols.S
|
||||||
|
|
||||||
|
This is necessary to generate assembler marker sections on some
|
||||||
|
targets.
|
||||||
|
|
||||||
|
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
|
||||||
|
|
||||||
|
diff --git a/elf/dl-debug-symbols.S b/elf/dl-debug-symbols.S
|
||||||
|
index b7e9f5d9470c4da2..28456ab1f237ea87 100644
|
||||||
|
--- a/elf/dl-debug-symbols.S
|
||||||
|
+++ b/elf/dl-debug-symbols.S
|
||||||
|
@@ -18,6 +18,10 @@
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include <rtld-sizes.h>
|
||||||
|
+#include <sysdep.h>
|
||||||
|
+
|
||||||
|
+/* Some targets define a macro to denote the zero register. */
|
||||||
|
+#undef zero
|
||||||
|
|
||||||
|
/* Define 2 symbols, _r_debug_extended and _r_debug, which is an alias
|
||||||
|
of _r_debug_extended, but with the size of struct r_debug. */
|
||||||
32
SOURCES/glibc-RHEL-47403-3.patch
Normal file
32
SOURCES/glibc-RHEL-47403-3.patch
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
commit 1b5e65ef6a442fdccf88d43c3048f98292d85631
|
||||||
|
Author: Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||||
|
Date: Sat Mar 25 21:27:01 2023 +0000
|
||||||
|
|
||||||
|
Minor: don't call _dl_debug_update (which can have side effects) inside assert
|
||||||
|
|
||||||
|
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||||
|
index eef724f7e9b2211d..0d2b4cd4785a226a 100644
|
||||||
|
--- a/elf/dl-open.c
|
||||||
|
+++ b/elf/dl-open.c
|
||||||
|
@@ -596,7 +596,9 @@ dl_open_worker_begin (void *a)
|
||||||
|
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||||
|
add_to_global_update (new);
|
||||||
|
|
||||||
|
- assert (_dl_debug_update (args->nsid)->r_state == RT_CONSISTENT);
|
||||||
|
+ const int r_state __attribute__ ((unused))
|
||||||
|
+ = _dl_debug_update (args->nsid)->r_state;
|
||||||
|
+ assert (r_state == RT_CONSISTENT);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@@ -916,7 +918,9 @@ no more namespaces available for dlmopen()"));
|
||||||
|
_dl_signal_exception (errcode, &exception, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
- assert (_dl_debug_update (args.nsid)->r_state == RT_CONSISTENT);
|
||||||
|
+ const int r_state __attribute__ ((unused))
|
||||||
|
+ = _dl_debug_update (args.nsid)->r_state;
|
||||||
|
+ assert (r_state == RT_CONSISTENT);
|
||||||
|
|
||||||
|
/* Release the lock. */
|
||||||
|
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||||
275
SOURCES/glibc-RHEL-47403-4.patch
Normal file
275
SOURCES/glibc-RHEL-47403-4.patch
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
commit 9897ced8e78db5d813166a7ccccfd5a42c69ef20
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Oct 25 16:50:10 2024 +0200
|
||||||
|
|
||||||
|
elf: Run constructors on cyclic recursive dlopen (bug 31986)
|
||||||
|
|
||||||
|
This is conceptually similar to the reported bug, but does not
|
||||||
|
depend on auditing. The fix is simple: just complete execution
|
||||||
|
of the constructors. This exposed the fact that the link map
|
||||||
|
for statically linked executables does not have l_init_called
|
||||||
|
set, even though constructors have run.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/Makefile (fix local test re-ordering)
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index b074cc29664b3e20..dc774b083eda202b 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -398,12 +398,15 @@ tests += \
|
||||||
|
tst-dl-is_dso \
|
||||||
|
tst-dlclose-lazy \
|
||||||
|
tst-dlmodcount \
|
||||||
|
- tst-dlmopen1 \
|
||||||
|
- tst-dlmopen3 \
|
||||||
|
- tst-dlmopen4 \
|
||||||
|
tst-dlmopen-dlerror \
|
||||||
|
tst-dlmopen-gethostbyname \
|
||||||
|
tst-dlmopen-twice \
|
||||||
|
+ tst-dlmopen1 \
|
||||||
|
+ tst-dlmopen3 \
|
||||||
|
+ tst-dlmopen4 \
|
||||||
|
+ tst-dlopen-recurse \
|
||||||
|
+ tst-dlopen-self \
|
||||||
|
+ tst-dlopen-tlsmodid \
|
||||||
|
tst-dlopen-tlsreinit1 \
|
||||||
|
tst-dlopen-tlsreinit2 \
|
||||||
|
tst-dlopen-tlsreinit3 \
|
||||||
|
@@ -411,8 +414,6 @@ tests += \
|
||||||
|
tst-dlopenfail \
|
||||||
|
tst-dlopenfail-2 \
|
||||||
|
tst-dlopenrpath \
|
||||||
|
- tst-dlopen-self \
|
||||||
|
- tst-dlopen-tlsmodid \
|
||||||
|
tst-dlsym-error \
|
||||||
|
tst-filterobj \
|
||||||
|
tst-filterobj-dlopen \
|
||||||
|
@@ -775,13 +776,15 @@ modules-names = \
|
||||||
|
tst-deep1mod1 \
|
||||||
|
tst-deep1mod2 \
|
||||||
|
tst-deep1mod3 \
|
||||||
|
- tst-dlmopen1mod \
|
||||||
|
tst-dlclose-lazy-mod1 \
|
||||||
|
tst-dlclose-lazy-mod2 \
|
||||||
|
tst-dlmopen-dlerror-mod \
|
||||||
|
tst-dlmopen-gethostbyname-mod \
|
||||||
|
tst-dlmopen-twice-mod1 \
|
||||||
|
tst-dlmopen-twice-mod2 \
|
||||||
|
+ tst-dlmopen1mod \
|
||||||
|
+ tst-dlopen-recursemod1 \
|
||||||
|
+ tst-dlopen-recursemod2 \
|
||||||
|
tst-dlopen-sgid-mod \
|
||||||
|
tst-dlopen-tlsreinitmod1 \
|
||||||
|
tst-dlopen-tlsreinitmod2 \
|
||||||
|
@@ -2856,6 +2859,9 @@ tst-dlopen-tlsreinit3-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||||
|
$(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so
|
||||||
|
tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||||
|
|
||||||
|
+$(objpfx)tst-dlopen-recurse.out: $(objpfx)tst-dlopen-recursemod1.so
|
||||||
|
+$(objpfx)tst-dlopen-recursemod1.so: $(objpfx)tst-dlopen-recursemod2.so
|
||||||
|
+
|
||||||
|
LDFLAGS-tst-hash-collision1-mod.so = -Wl,--hash-style=both
|
||||||
|
$(objpfx)tst-hash-collision1: $(objpfx)tst-hash-collision1-mod.so
|
||||||
|
LDFLAGS-tst-hash-collision1-mod-gnu.so = -Wl,--hash-style=gnu
|
||||||
|
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||||
|
index 0d2b4cd4785a226a..0b0bfb8acda28caa 100644
|
||||||
|
--- a/elf/dl-open.c
|
||||||
|
+++ b/elf/dl-open.c
|
||||||
|
@@ -600,6 +600,14 @@ dl_open_worker_begin (void *a)
|
||||||
|
= _dl_debug_update (args->nsid)->r_state;
|
||||||
|
assert (r_state == RT_CONSISTENT);
|
||||||
|
|
||||||
|
+ /* Do not return without calling the (supposedly new) map's
|
||||||
|
+ constructor. This case occurs if a dependency of a directly
|
||||||
|
+ opened map has a constructor that calls dlopen again on the
|
||||||
|
+ initially opened map. The new map is initialized last, so
|
||||||
|
+ checking only it is enough. */
|
||||||
|
+ if (!new->l_init_called)
|
||||||
|
+ _dl_catch_exception (NULL, call_dl_init, args);
|
||||||
|
+
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/elf/dl-support.c b/elf/dl-support.c
|
||||||
|
index 00abc2d8056c78b0..f4dc9c61a2637f8b 100644
|
||||||
|
--- a/elf/dl-support.c
|
||||||
|
+++ b/elf/dl-support.c
|
||||||
|
@@ -103,6 +103,7 @@ static struct link_map _dl_main_map =
|
||||||
|
.l_used = 1,
|
||||||
|
.l_tls_offset = NO_TLS_OFFSET,
|
||||||
|
.l_serial = 1,
|
||||||
|
+ .l_init_called = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Namespace information. */
|
||||||
|
diff --git a/elf/tst-dlopen-recurse.c b/elf/tst-dlopen-recurse.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..c7fb379d373c6e77
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-dlopen-recurse.c
|
||||||
|
@@ -0,0 +1,34 @@
|
||||||
|
+/* Test that recursive dlopen runs constructors before return (bug 31986).
|
||||||
|
+ 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/xdlfcn.h>
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ void *handle = xdlopen ("tst-dlopen-recursemod1.so", RTLD_NOW);
|
||||||
|
+ int *status = dlsym (handle, "recursemod1_status");
|
||||||
|
+ printf ("info: recursemod1_status == %d (from main)\n", *status);
|
||||||
|
+ TEST_COMPARE (*status, 2);
|
||||||
|
+ xdlclose (handle);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
|
diff --git a/elf/tst-dlopen-recursemod1.c b/elf/tst-dlopen-recursemod1.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..5e0cc0eb8c32d6d4
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-dlopen-recursemod1.c
|
||||||
|
@@ -0,0 +1,50 @@
|
||||||
|
+/* Directly opened test module that gets recursively opened again.
|
||||||
|
+ 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <support/xdlfcn.h>
|
||||||
|
+
|
||||||
|
+int recursemod1_status;
|
||||||
|
+
|
||||||
|
+/* Force linking against st-dlopen-recursemod2.so. Also allows
|
||||||
|
+ checking for relocation. */
|
||||||
|
+extern int recursemod2_status;
|
||||||
|
+int *force_recursemod2_reference = &recursemod2_status;
|
||||||
|
+
|
||||||
|
+static void __attribute__ ((constructor))
|
||||||
|
+init (void)
|
||||||
|
+{
|
||||||
|
+ ++recursemod1_status;
|
||||||
|
+ printf ("info: tst-dlopen-recursemod1.so constructor called (status %d)\n",
|
||||||
|
+ recursemod1_status);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __attribute__ ((destructor))
|
||||||
|
+fini (void)
|
||||||
|
+{
|
||||||
|
+ /* The recursemod1_status variable was incremented in the
|
||||||
|
+ tst-dlopen-recursemod2.so constructor. */
|
||||||
|
+ printf ("info: tst-dlopen-recursemod1.so destructor called (status %d)\n",
|
||||||
|
+ recursemod1_status);
|
||||||
|
+ if (recursemod1_status != 2)
|
||||||
|
+ {
|
||||||
|
+ puts ("error: recursemod1_status == 2 expected");
|
||||||
|
+ exit (1);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/elf/tst-dlopen-recursemod2.c b/elf/tst-dlopen-recursemod2.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..edd2f2526b877810
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-dlopen-recursemod2.c
|
||||||
|
@@ -0,0 +1,66 @@
|
||||||
|
+/* Indirectly opened module that recursively opens the directly opened module.
|
||||||
|
+ 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <dlfcn.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+
|
||||||
|
+int recursemod2_status;
|
||||||
|
+
|
||||||
|
+static void __attribute__ ((constructor))
|
||||||
|
+init (void)
|
||||||
|
+{
|
||||||
|
+ ++recursemod2_status;
|
||||||
|
+ printf ("info: tst-dlopen-recursemod2.so constructor called (status %d)\n",
|
||||||
|
+ recursemod2_status);
|
||||||
|
+ void *handle = dlopen ("tst-dlopen-recursemod1.so", RTLD_NOW);
|
||||||
|
+ if (handle == NULL)
|
||||||
|
+ {
|
||||||
|
+ printf ("error: dlopen: %s\n", dlerror ());
|
||||||
|
+ exit (1);
|
||||||
|
+ }
|
||||||
|
+ int *status = dlsym (handle, "recursemod1_status");
|
||||||
|
+ if (status == NULL)
|
||||||
|
+ {
|
||||||
|
+ printf ("error: dlsym: %s\n", dlerror ());
|
||||||
|
+ exit (1);
|
||||||
|
+ }
|
||||||
|
+ printf ("info: recursemod1_status == %d\n", *status);
|
||||||
|
+ if (*status != 1)
|
||||||
|
+ {
|
||||||
|
+ puts ("error: recursemod1_status == 1 expected");
|
||||||
|
+ exit (1);
|
||||||
|
+ }
|
||||||
|
+ ++*status;
|
||||||
|
+ printf ("info: recursemod1_status == %d\n", *status);
|
||||||
|
+
|
||||||
|
+ int **mod2_status = dlsym (handle, "force_recursemod2_reference");
|
||||||
|
+ if (mod2_status == NULL || *mod2_status != &recursemod2_status)
|
||||||
|
+ {
|
||||||
|
+ puts ("error: invalid recursemod2_status address in"
|
||||||
|
+ " tst-dlopen-recursemod1.so");
|
||||||
|
+ exit (1);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __attribute__ ((destructor))
|
||||||
|
+fini (void)
|
||||||
|
+{
|
||||||
|
+ printf ("info: tst-dlopen-recursemod2.so destructor called (status %d)\n",
|
||||||
|
+ recursemod2_status);
|
||||||
|
+}
|
||||||
103
SOURCES/glibc-RHEL-47403-5.patch
Normal file
103
SOURCES/glibc-RHEL-47403-5.patch
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
commit e096b7a1896886eb7dd2732ccbf1184b0eec9a63
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Oct 25 16:50:10 2024 +0200
|
||||||
|
|
||||||
|
elf: Signal LA_ACT_CONSISTENT to auditors after RT_CONSISTENT switch
|
||||||
|
|
||||||
|
Auditors can call into the dynamic loader again if
|
||||||
|
LA_ACT_CONSISTENT, and those recursive calls could observe
|
||||||
|
r_state != RT_CONSISTENT.
|
||||||
|
|
||||||
|
We should consider failing dlopen/dlmopen/dlclose if
|
||||||
|
r_state != RT_CONSISTENT. The dynamic linker is probably not
|
||||||
|
in a state in which it can handle reentrant calls. This
|
||||||
|
needs further investigation.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/rtld.c (kept SHARED guard downstream)
|
||||||
|
|
||||||
|
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||||
|
index bf699e58d753a1e2..8a4c3528a124d4e7 100644
|
||||||
|
--- a/elf/dl-close.c
|
||||||
|
+++ b/elf/dl-close.c
|
||||||
|
@@ -759,6 +759,11 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||||
|
/* TLS is cleaned up for the unloaded modules. */
|
||||||
|
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
|
||||||
|
|
||||||
|
+ /* Notify the debugger those objects are finalized and gone. */
|
||||||
|
+ r->r_state = RT_CONSISTENT;
|
||||||
|
+ _dl_debug_state ();
|
||||||
|
+ LIBC_PROBE (unmap_complete, 2, nsid, r);
|
||||||
|
+
|
||||||
|
#ifdef SHARED
|
||||||
|
/* Auditing checkpoint: we have deleted all objects. Also, do not notify
|
||||||
|
auditors of the cleanup of a failed audit module loading attempt. */
|
||||||
|
@@ -771,11 +776,6 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||||
|
--GL(dl_nns);
|
||||||
|
while (GL(dl_ns)[GL(dl_nns) - 1]._ns_loaded == NULL);
|
||||||
|
|
||||||
|
- /* Notify the debugger those objects are finalized and gone. */
|
||||||
|
- r->r_state = RT_CONSISTENT;
|
||||||
|
- _dl_debug_state ();
|
||||||
|
- LIBC_PROBE (unmap_complete, 2, nsid, r);
|
||||||
|
-
|
||||||
|
/* Recheck if we need to retry, release the lock. */
|
||||||
|
out:
|
||||||
|
if (dl_close_state == rerun)
|
||||||
|
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||||
|
index 0b0bfb8acda28caa..5095ea4f96b6cf49 100644
|
||||||
|
--- a/elf/dl-open.c
|
||||||
|
+++ b/elf/dl-open.c
|
||||||
|
@@ -638,17 +638,17 @@ dl_open_worker_begin (void *a)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
-#ifdef SHARED
|
||||||
|
- /* Auditing checkpoint: we have added all objects. */
|
||||||
|
- _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT);
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
/* Notify the debugger all new objects are now ready to go. */
|
||||||
|
struct r_debug *r = _dl_debug_update (args->nsid);
|
||||||
|
r->r_state = RT_CONSISTENT;
|
||||||
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (map_complete, 3, args->nsid, r, new);
|
||||||
|
|
||||||
|
+#ifdef SHARED
|
||||||
|
+ /* Auditing checkpoint: we have added all objects. */
|
||||||
|
+ _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
_dl_open_check (new);
|
||||||
|
|
||||||
|
/* Print scope information. */
|
||||||
|
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||||
|
index 7d8ed0ac1188d527..cd233174c9d944b2 100644
|
||||||
|
--- a/elf/rtld.c
|
||||||
|
+++ b/elf/rtld.c
|
||||||
|
@@ -2524,11 +2524,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
_dl_relocate_object might need to call `mprotect' for DT_TEXTREL. */
|
||||||
|
_dl_sysdep_start_cleanup ();
|
||||||
|
|
||||||
|
-#ifdef SHARED
|
||||||
|
- /* Auditing checkpoint: we have added all objects. */
|
||||||
|
- _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT);
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
/* Notify the debugger all new objects are now ready to go. We must re-get
|
||||||
|
the address since by now the variable might be in another object. */
|
||||||
|
r = _dl_debug_update (LM_ID_BASE);
|
||||||
|
@@ -2536,6 +2531,11 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
|
||||||
|
|
||||||
|
+#ifdef SHARED
|
||||||
|
+ /* Auditing checkpoint: we have added all objects. */
|
||||||
|
+ _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#if defined USE_LDCONFIG && !defined MAP_COPY
|
||||||
|
/* We must munmap() the cache file. */
|
||||||
|
_dl_unload_cache ();
|
||||||
342
SOURCES/glibc-RHEL-47403-6.patch
Normal file
342
SOURCES/glibc-RHEL-47403-6.patch
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
commit 43db5e2c0672cae7edea7c9685b22317eae25471
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Oct 25 16:50:10 2024 +0200
|
||||||
|
|
||||||
|
elf: Signal RT_CONSISTENT after relocation processing in dlopen (bug 31986)
|
||||||
|
|
||||||
|
Previously, a la_activity audit event was generated before
|
||||||
|
relocation processing completed. This does did not match what
|
||||||
|
happened during initial startup in elf/rtld.c (towards the end
|
||||||
|
of dl_main). It also caused various problems if an auditor
|
||||||
|
tried to open the same shared object again using dlmopen:
|
||||||
|
If it was the directly loaded object, it had a search scope
|
||||||
|
associated with it, so the early exit in dl_open_worker_begin
|
||||||
|
was taken even though the object was unrelocated. This caused
|
||||||
|
the r_state == RT_CONSISTENT assert to fail. Avoidance of the
|
||||||
|
assert also depends on reversing the order of r_state update
|
||||||
|
and auditor event (already implemented in a previous commit).
|
||||||
|
|
||||||
|
At the later point, args->map can be NULL due to failure,
|
||||||
|
so use the assigned namespace ID instead if that is available.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/Makefile (fixup context)
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index dc774b083eda202b..73deb69f5a3c9150 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -404,6 +404,7 @@ tests += \
|
||||||
|
tst-dlmopen1 \
|
||||||
|
tst-dlmopen3 \
|
||||||
|
tst-dlmopen4 \
|
||||||
|
+ tst-dlopen-auditdup \
|
||||||
|
tst-dlopen-recurse \
|
||||||
|
tst-dlopen-self \
|
||||||
|
tst-dlopen-tlsmodid \
|
||||||
|
@@ -783,6 +784,8 @@ modules-names = \
|
||||||
|
tst-dlmopen-twice-mod1 \
|
||||||
|
tst-dlmopen-twice-mod2 \
|
||||||
|
tst-dlmopen1mod \
|
||||||
|
+ tst-dlopen-auditdup-auditmod \
|
||||||
|
+ tst-dlopen-auditdupmod \
|
||||||
|
tst-dlopen-recursemod1 \
|
||||||
|
tst-dlopen-recursemod2 \
|
||||||
|
tst-dlopen-sgid-mod \
|
||||||
|
@@ -2861,6 +2864,9 @@ tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||||
|
|
||||||
|
$(objpfx)tst-dlopen-recurse.out: $(objpfx)tst-dlopen-recursemod1.so
|
||||||
|
$(objpfx)tst-dlopen-recursemod1.so: $(objpfx)tst-dlopen-recursemod2.so
|
||||||
|
+tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so
|
||||||
|
+$(objpfx)tst-dlopen-auditdup.out: \
|
||||||
|
+ $(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so
|
||||||
|
|
||||||
|
LDFLAGS-tst-hash-collision1-mod.so = -Wl,--hash-style=both
|
||||||
|
$(objpfx)tst-hash-collision1: $(objpfx)tst-hash-collision1-mod.so
|
||||||
|
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||||
|
index 5095ea4f96b6cf49..6ec1ca033bbe7859 100644
|
||||||
|
--- a/elf/dl-open.c
|
||||||
|
+++ b/elf/dl-open.c
|
||||||
|
@@ -575,6 +575,14 @@ dl_open_worker_begin (void *a)
|
||||||
|
_dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
|
||||||
|
new->l_name, new->l_ns, new->l_direct_opencount);
|
||||||
|
|
||||||
|
+#ifdef SHARED
|
||||||
|
+ /* No relocation processing on this execution path. But
|
||||||
|
+ relocation has not been performed for static
|
||||||
|
+ position-dependent executables, so disable the assert for
|
||||||
|
+ static linking. */
|
||||||
|
+ assert (new->l_relocated);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/* If the user requested the object to be in the global
|
||||||
|
namespace but it is not so far, prepare to add it now. This
|
||||||
|
can raise an exception to do a malloc failure. */
|
||||||
|
@@ -596,10 +604,6 @@ dl_open_worker_begin (void *a)
|
||||||
|
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||||
|
add_to_global_update (new);
|
||||||
|
|
||||||
|
- const int r_state __attribute__ ((unused))
|
||||||
|
- = _dl_debug_update (args->nsid)->r_state;
|
||||||
|
- assert (r_state == RT_CONSISTENT);
|
||||||
|
-
|
||||||
|
/* Do not return without calling the (supposedly new) map's
|
||||||
|
constructor. This case occurs if a dependency of a directly
|
||||||
|
opened map has a constructor that calls dlopen again on the
|
||||||
|
@@ -638,17 +642,6 @@ dl_open_worker_begin (void *a)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* Notify the debugger all new objects are now ready to go. */
|
||||||
|
- struct r_debug *r = _dl_debug_update (args->nsid);
|
||||||
|
- r->r_state = RT_CONSISTENT;
|
||||||
|
- _dl_debug_state ();
|
||||||
|
- LIBC_PROBE (map_complete, 3, args->nsid, r, new);
|
||||||
|
-
|
||||||
|
-#ifdef SHARED
|
||||||
|
- /* Auditing checkpoint: we have added all objects. */
|
||||||
|
- _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT);
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
_dl_open_check (new);
|
||||||
|
|
||||||
|
/* Print scope information. */
|
||||||
|
@@ -695,6 +688,7 @@ dl_open_worker_begin (void *a)
|
||||||
|
created dlmopen namespaces. Do not do this for static dlopen
|
||||||
|
because libc has relocations against ld.so, which may not have
|
||||||
|
been relocated at this point. */
|
||||||
|
+ struct r_debug *r = _dl_debug_update (args->nsid);
|
||||||
|
#ifdef SHARED
|
||||||
|
if (GL(dl_ns)[args->nsid].libc_map != NULL)
|
||||||
|
_dl_open_relocate_one_object (args, r, GL(dl_ns)[args->nsid].libc_map,
|
||||||
|
@@ -782,6 +776,26 @@ dl_open_worker (void *a)
|
||||||
|
|
||||||
|
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
|
||||||
|
|
||||||
|
+ /* Auditing checkpoint and debugger signalling. Do this even on
|
||||||
|
+ error, so that dlopen exists with consistent state. */
|
||||||
|
+ if (args->nsid >= 0 || args->map != NULL)
|
||||||
|
+ {
|
||||||
|
+ Lmid_t nsid = args->map != NULL ? args->map->l_ns : args->nsid;
|
||||||
|
+ struct r_debug *r = _dl_debug_update (nsid);
|
||||||
|
+#ifdef SHARED
|
||||||
|
+ bool was_not_consistent = r->r_state != RT_CONSISTENT;
|
||||||
|
+#endif
|
||||||
|
+ r->r_state = RT_CONSISTENT;
|
||||||
|
+ _dl_debug_state ();
|
||||||
|
+ LIBC_PROBE (map_complete, 3, nsid, r, new);
|
||||||
|
+
|
||||||
|
+#ifdef SHARED
|
||||||
|
+ if (was_not_consistent)
|
||||||
|
+ /* Avoid redudant/recursive signalling. */
|
||||||
|
+ _dl_audit_activity_nsid (nsid, LA_ACT_CONSISTENT);
|
||||||
|
+#endif
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (__glibc_unlikely (ex.errstring != NULL))
|
||||||
|
/* Reraise the error. */
|
||||||
|
_dl_signal_exception (err, &ex, NULL);
|
||||||
|
diff --git a/elf/tst-dlopen-auditdup-auditmod.c b/elf/tst-dlopen-auditdup-auditmod.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..9b67295e94d03e7a
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-dlopen-auditdup-auditmod.c
|
||||||
|
@@ -0,0 +1,100 @@
|
||||||
|
+/* Auditor that opens again an object that just has been opened.
|
||||||
|
+ 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <dlfcn.h>
|
||||||
|
+#include <link.h>
|
||||||
|
+#include <stdbool.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+
|
||||||
|
+unsigned int
|
||||||
|
+la_version (unsigned int v)
|
||||||
|
+{
|
||||||
|
+ return LAV_CURRENT;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static bool trigger_on_la_activity;
|
||||||
|
+
|
||||||
|
+unsigned int
|
||||||
|
+la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
|
||||||
|
+{
|
||||||
|
+ printf ("info: la_objopen: \"%s\"\n", map->l_name);
|
||||||
|
+ if (strstr (map->l_name, "/tst-dlopen-auditdupmod.so") != NULL)
|
||||||
|
+ trigger_on_la_activity = true;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+la_activity (uintptr_t *cookie, unsigned int flag)
|
||||||
|
+{
|
||||||
|
+ static unsigned int calls;
|
||||||
|
+ ++calls;
|
||||||
|
+ printf ("info: la_activity: call %u (flag %u)\n", calls, flag);
|
||||||
|
+ fflush (stdout);
|
||||||
|
+ if (trigger_on_la_activity)
|
||||||
|
+ {
|
||||||
|
+ /* Avoid triggering on the dlmopen call below. */
|
||||||
|
+ static bool recursion;
|
||||||
|
+ if (recursion)
|
||||||
|
+ return;
|
||||||
|
+ recursion = true;
|
||||||
|
+
|
||||||
|
+ puts ("info: about to dlmopen tst-dlopen-auditdupmod.so");
|
||||||
|
+ fflush (stdout);
|
||||||
|
+ void *handle = dlmopen (LM_ID_BASE, "tst-dlopen-auditdupmod.so",
|
||||||
|
+ RTLD_NOW);
|
||||||
|
+ if (handle == NULL)
|
||||||
|
+ {
|
||||||
|
+ printf ("error: dlmopen: %s\n", dlerror ());
|
||||||
|
+ fflush (stdout);
|
||||||
|
+ _exit (1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Check that the constructor has run. */
|
||||||
|
+ int *status = dlsym (handle, "auditdupmod_status");
|
||||||
|
+ if (status == NULL)
|
||||||
|
+ {
|
||||||
|
+ printf ("error: dlsym: %s\n", dlerror ());
|
||||||
|
+ fflush (stdout);
|
||||||
|
+ _exit (1);
|
||||||
|
+ }
|
||||||
|
+ printf ("info: auditdupmod_status == %d\n", *status);
|
||||||
|
+ if (*status != 1)
|
||||||
|
+ {
|
||||||
|
+ puts ("error: auditdupmod_status == 1 expected");
|
||||||
|
+ fflush (stdout);
|
||||||
|
+ _exit (1);
|
||||||
|
+ }
|
||||||
|
+ /* Checked in the destructor and the main program. */
|
||||||
|
+ ++*status;
|
||||||
|
+ printf ("info: auditdupmod_status == %d\n", *status);
|
||||||
|
+
|
||||||
|
+ /* Check that the module has been relocated. */
|
||||||
|
+ int **status_address = dlsym (handle, "auditdupmod_status_address");
|
||||||
|
+ if (status_address == NULL || *status_address != status)
|
||||||
|
+ {
|
||||||
|
+ puts ("error: invalid auditdupmod_status address in"
|
||||||
|
+ " tst-dlopen-auditdupmod.so");
|
||||||
|
+ fflush (stdout);
|
||||||
|
+ _exit (1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ fflush (stdout);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/elf/tst-dlopen-auditdup.c b/elf/tst-dlopen-auditdup.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..d022c58ae3091da1
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-dlopen-auditdup.c
|
||||||
|
@@ -0,0 +1,36 @@
|
||||||
|
+/* Test that recursive dlopen from auditor works (bug 31986).
|
||||||
|
+ 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/xdlfcn.h>
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ puts ("info: about to dlopen tst-dlopen-auditdupmod.so");
|
||||||
|
+ fflush (stdout);
|
||||||
|
+ void *handle = xdlopen ("tst-dlopen-auditdupmod.so", RTLD_NOW);
|
||||||
|
+ int *status = xdlsym (handle, "auditdupmod_status");
|
||||||
|
+ printf ("info: auditdupmod_status == %d (from main)\n", *status);
|
||||||
|
+ TEST_COMPARE (*status, 2);
|
||||||
|
+ xdlclose (handle);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
|
diff --git a/elf/tst-dlopen-auditdupmod.c b/elf/tst-dlopen-auditdupmod.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..59b7e21daa8212df
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-dlopen-auditdupmod.c
|
||||||
|
@@ -0,0 +1,48 @@
|
||||||
|
+/* Directly opened test module that gets reopened from the auditor.
|
||||||
|
+ 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <support/xdlfcn.h>
|
||||||
|
+
|
||||||
|
+int auditdupmod_status;
|
||||||
|
+
|
||||||
|
+/* Used to check for successful relocation processing. */
|
||||||
|
+int *auditdupmod_status_address = &auditdupmod_status;
|
||||||
|
+
|
||||||
|
+static void __attribute__ ((constructor))
|
||||||
|
+init (void)
|
||||||
|
+{
|
||||||
|
+ ++auditdupmod_status;
|
||||||
|
+ printf ("info: tst-dlopen-auditdupmod.so constructor called (status %d)\n",
|
||||||
|
+ auditdupmod_status);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __attribute__ ((destructor))
|
||||||
|
+fini (void)
|
||||||
|
+{
|
||||||
|
+ /* The tst-dlopen-auditdup-auditmod.so auditor incremented
|
||||||
|
+ auditdupmod_status. */
|
||||||
|
+ printf ("info: tst-dlopen-auditdupmod.so destructor called (status %d)\n",
|
||||||
|
+ auditdupmod_status);
|
||||||
|
+ if (auditdupmod_status != 2)
|
||||||
|
+ {
|
||||||
|
+ puts ("error: auditdupmod_status == 2 expected");
|
||||||
|
+ exit (1);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
272
SOURCES/glibc-RHEL-47403-7.patch
Normal file
272
SOURCES/glibc-RHEL-47403-7.patch
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
commit 95129e6b8fabdaa8cd8a4a5cc20be0f4cb0ba59f
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Mon Oct 28 14:45:30 2024 +0100
|
||||||
|
|
||||||
|
Revert "elf: Run constructors on cyclic recursive dlopen (bug 31986)"
|
||||||
|
|
||||||
|
This reverts commit 9897ced8e78db5d813166a7ccccfd5a42c69ef20.
|
||||||
|
|
||||||
|
Adjust the test expectations in elf/tst-dlopen-auditdup-auditmod.c
|
||||||
|
accordingly.
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/Makefile (fixup context)
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index 73deb69f5a3c9150..a358ad7ff0eb2af7 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -405,7 +405,6 @@ tests += \
|
||||||
|
tst-dlmopen3 \
|
||||||
|
tst-dlmopen4 \
|
||||||
|
tst-dlopen-auditdup \
|
||||||
|
- tst-dlopen-recurse \
|
||||||
|
tst-dlopen-self \
|
||||||
|
tst-dlopen-tlsmodid \
|
||||||
|
tst-dlopen-tlsreinit1 \
|
||||||
|
@@ -786,8 +785,6 @@ modules-names = \
|
||||||
|
tst-dlmopen1mod \
|
||||||
|
tst-dlopen-auditdup-auditmod \
|
||||||
|
tst-dlopen-auditdupmod \
|
||||||
|
- tst-dlopen-recursemod1 \
|
||||||
|
- tst-dlopen-recursemod2 \
|
||||||
|
tst-dlopen-sgid-mod \
|
||||||
|
tst-dlopen-tlsreinitmod1 \
|
||||||
|
tst-dlopen-tlsreinitmod2 \
|
||||||
|
@@ -2862,8 +2859,6 @@ tst-dlopen-tlsreinit3-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||||
|
$(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so
|
||||||
|
tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||||
|
|
||||||
|
-$(objpfx)tst-dlopen-recurse.out: $(objpfx)tst-dlopen-recursemod1.so
|
||||||
|
-$(objpfx)tst-dlopen-recursemod1.so: $(objpfx)tst-dlopen-recursemod2.so
|
||||||
|
tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so
|
||||||
|
$(objpfx)tst-dlopen-auditdup.out: \
|
||||||
|
$(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so
|
||||||
|
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||||
|
index 6ec1ca033bbe7859..6557c2fd7ca0bbfe 100644
|
||||||
|
--- a/elf/dl-open.c
|
||||||
|
+++ b/elf/dl-open.c
|
||||||
|
@@ -604,14 +604,6 @@ dl_open_worker_begin (void *a)
|
||||||
|
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||||
|
add_to_global_update (new);
|
||||||
|
|
||||||
|
- /* Do not return without calling the (supposedly new) map's
|
||||||
|
- constructor. This case occurs if a dependency of a directly
|
||||||
|
- opened map has a constructor that calls dlopen again on the
|
||||||
|
- initially opened map. The new map is initialized last, so
|
||||||
|
- checking only it is enough. */
|
||||||
|
- if (!new->l_init_called)
|
||||||
|
- _dl_catch_exception (NULL, call_dl_init, args);
|
||||||
|
-
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/elf/dl-support.c b/elf/dl-support.c
|
||||||
|
index f4dc9c61a2637f8b..00abc2d8056c78b0 100644
|
||||||
|
--- a/elf/dl-support.c
|
||||||
|
+++ b/elf/dl-support.c
|
||||||
|
@@ -103,7 +103,6 @@ static struct link_map _dl_main_map =
|
||||||
|
.l_used = 1,
|
||||||
|
.l_tls_offset = NO_TLS_OFFSET,
|
||||||
|
.l_serial = 1,
|
||||||
|
- .l_init_called = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Namespace information. */
|
||||||
|
diff --git a/elf/tst-dlopen-auditdup-auditmod.c b/elf/tst-dlopen-auditdup-auditmod.c
|
||||||
|
index 9b67295e94d03e7a..270a595ec4de1439 100644
|
||||||
|
--- a/elf/tst-dlopen-auditdup-auditmod.c
|
||||||
|
+++ b/elf/tst-dlopen-auditdup-auditmod.c
|
||||||
|
@@ -66,7 +66,11 @@ la_activity (uintptr_t *cookie, unsigned int flag)
|
||||||
|
_exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* Check that the constructor has run. */
|
||||||
|
+ /* Check that the constructor has not run. Running the
|
||||||
|
+ constructor would require constructing its dependencies, but
|
||||||
|
+ the constructor call that triggered this auditing activity
|
||||||
|
+ has not completed, and constructors among the dependencies
|
||||||
|
+ may not be able to deal with that. */
|
||||||
|
int *status = dlsym (handle, "auditdupmod_status");
|
||||||
|
if (status == NULL)
|
||||||
|
{
|
||||||
|
@@ -75,9 +79,9 @@ la_activity (uintptr_t *cookie, unsigned int flag)
|
||||||
|
_exit (1);
|
||||||
|
}
|
||||||
|
printf ("info: auditdupmod_status == %d\n", *status);
|
||||||
|
- if (*status != 1)
|
||||||
|
+ if (*status != 0)
|
||||||
|
{
|
||||||
|
- puts ("error: auditdupmod_status == 1 expected");
|
||||||
|
+ puts ("error: auditdupmod_status == 0 expected");
|
||||||
|
fflush (stdout);
|
||||||
|
_exit (1);
|
||||||
|
}
|
||||||
|
diff --git a/elf/tst-dlopen-recurse.c b/elf/tst-dlopen-recurse.c
|
||||||
|
deleted file mode 100644
|
||||||
|
index c7fb379d373c6e77..0000000000000000
|
||||||
|
--- a/elf/tst-dlopen-recurse.c
|
||||||
|
+++ /dev/null
|
||||||
|
@@ -1,34 +0,0 @@
|
||||||
|
-/* Test that recursive dlopen runs constructors before return (bug 31986).
|
||||||
|
- 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
|
||||||
|
- <https://www.gnu.org/licenses/>. */
|
||||||
|
-
|
||||||
|
-#include <stdio.h>
|
||||||
|
-#include <support/check.h>
|
||||||
|
-#include <support/xdlfcn.h>
|
||||||
|
-
|
||||||
|
-static int
|
||||||
|
-do_test (void)
|
||||||
|
-{
|
||||||
|
- void *handle = xdlopen ("tst-dlopen-recursemod1.so", RTLD_NOW);
|
||||||
|
- int *status = dlsym (handle, "recursemod1_status");
|
||||||
|
- printf ("info: recursemod1_status == %d (from main)\n", *status);
|
||||||
|
- TEST_COMPARE (*status, 2);
|
||||||
|
- xdlclose (handle);
|
||||||
|
- return 0;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-#include <support/test-driver.c>
|
||||||
|
diff --git a/elf/tst-dlopen-recursemod1.c b/elf/tst-dlopen-recursemod1.c
|
||||||
|
deleted file mode 100644
|
||||||
|
index 5e0cc0eb8c32d6d4..0000000000000000
|
||||||
|
--- a/elf/tst-dlopen-recursemod1.c
|
||||||
|
+++ /dev/null
|
||||||
|
@@ -1,50 +0,0 @@
|
||||||
|
-/* Directly opened test module that gets recursively opened again.
|
||||||
|
- 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
|
||||||
|
- <https://www.gnu.org/licenses/>. */
|
||||||
|
-
|
||||||
|
-#include <stdio.h>
|
||||||
|
-#include <stdlib.h>
|
||||||
|
-#include <support/xdlfcn.h>
|
||||||
|
-
|
||||||
|
-int recursemod1_status;
|
||||||
|
-
|
||||||
|
-/* Force linking against st-dlopen-recursemod2.so. Also allows
|
||||||
|
- checking for relocation. */
|
||||||
|
-extern int recursemod2_status;
|
||||||
|
-int *force_recursemod2_reference = &recursemod2_status;
|
||||||
|
-
|
||||||
|
-static void __attribute__ ((constructor))
|
||||||
|
-init (void)
|
||||||
|
-{
|
||||||
|
- ++recursemod1_status;
|
||||||
|
- printf ("info: tst-dlopen-recursemod1.so constructor called (status %d)\n",
|
||||||
|
- recursemod1_status);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-static void __attribute__ ((destructor))
|
||||||
|
-fini (void)
|
||||||
|
-{
|
||||||
|
- /* The recursemod1_status variable was incremented in the
|
||||||
|
- tst-dlopen-recursemod2.so constructor. */
|
||||||
|
- printf ("info: tst-dlopen-recursemod1.so destructor called (status %d)\n",
|
||||||
|
- recursemod1_status);
|
||||||
|
- if (recursemod1_status != 2)
|
||||||
|
- {
|
||||||
|
- puts ("error: recursemod1_status == 2 expected");
|
||||||
|
- exit (1);
|
||||||
|
- }
|
||||||
|
-}
|
||||||
|
diff --git a/elf/tst-dlopen-recursemod2.c b/elf/tst-dlopen-recursemod2.c
|
||||||
|
deleted file mode 100644
|
||||||
|
index edd2f2526b877810..0000000000000000
|
||||||
|
--- a/elf/tst-dlopen-recursemod2.c
|
||||||
|
+++ /dev/null
|
||||||
|
@@ -1,66 +0,0 @@
|
||||||
|
-/* Indirectly opened module that recursively opens the directly opened module.
|
||||||
|
- 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
|
||||||
|
- <https://www.gnu.org/licenses/>. */
|
||||||
|
-
|
||||||
|
-#include <dlfcn.h>
|
||||||
|
-#include <stdio.h>
|
||||||
|
-#include <stdlib.h>
|
||||||
|
-
|
||||||
|
-int recursemod2_status;
|
||||||
|
-
|
||||||
|
-static void __attribute__ ((constructor))
|
||||||
|
-init (void)
|
||||||
|
-{
|
||||||
|
- ++recursemod2_status;
|
||||||
|
- printf ("info: tst-dlopen-recursemod2.so constructor called (status %d)\n",
|
||||||
|
- recursemod2_status);
|
||||||
|
- void *handle = dlopen ("tst-dlopen-recursemod1.so", RTLD_NOW);
|
||||||
|
- if (handle == NULL)
|
||||||
|
- {
|
||||||
|
- printf ("error: dlopen: %s\n", dlerror ());
|
||||||
|
- exit (1);
|
||||||
|
- }
|
||||||
|
- int *status = dlsym (handle, "recursemod1_status");
|
||||||
|
- if (status == NULL)
|
||||||
|
- {
|
||||||
|
- printf ("error: dlsym: %s\n", dlerror ());
|
||||||
|
- exit (1);
|
||||||
|
- }
|
||||||
|
- printf ("info: recursemod1_status == %d\n", *status);
|
||||||
|
- if (*status != 1)
|
||||||
|
- {
|
||||||
|
- puts ("error: recursemod1_status == 1 expected");
|
||||||
|
- exit (1);
|
||||||
|
- }
|
||||||
|
- ++*status;
|
||||||
|
- printf ("info: recursemod1_status == %d\n", *status);
|
||||||
|
-
|
||||||
|
- int **mod2_status = dlsym (handle, "force_recursemod2_reference");
|
||||||
|
- if (mod2_status == NULL || *mod2_status != &recursemod2_status)
|
||||||
|
- {
|
||||||
|
- puts ("error: invalid recursemod2_status address in"
|
||||||
|
- " tst-dlopen-recursemod1.so");
|
||||||
|
- exit (1);
|
||||||
|
- }
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-static void __attribute__ ((destructor))
|
||||||
|
-fini (void)
|
||||||
|
-{
|
||||||
|
- printf ("info: tst-dlopen-recursemod2.so destructor called (status %d)\n",
|
||||||
|
- recursemod2_status);
|
||||||
|
-}
|
||||||
218
SOURCES/glibc-RHEL-47403-8.patch
Normal file
218
SOURCES/glibc-RHEL-47403-8.patch
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
commit d604f9c500570e80febfcc6a52b63a002b466f35
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Tue Mar 11 15:30:52 2025 +0100
|
||||||
|
|
||||||
|
elf: Test dlopen (NULL, RTLD_LAZY) from an ELF constructor
|
||||||
|
|
||||||
|
This call must not complete initialization of all shared objects
|
||||||
|
in the global scope because the ELF constructor which makes the call
|
||||||
|
likely has not finished initialization. Calling more constructors
|
||||||
|
at this point would expose those to a partially constructed
|
||||||
|
dependency.
|
||||||
|
|
||||||
|
This completes the revert of commit 9897ced8e78db5d813166a7ccccfd5a
|
||||||
|
("elf: Run constructors on cyclic recursive dlopen (bug 31986)").
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/Makefile (fixup context)
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index a358ad7ff0eb2af7..3a50ca90366aec94 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -405,6 +405,7 @@ tests += \
|
||||||
|
tst-dlmopen3 \
|
||||||
|
tst-dlmopen4 \
|
||||||
|
tst-dlopen-auditdup \
|
||||||
|
+ tst-dlopen-constructor-null \
|
||||||
|
tst-dlopen-self \
|
||||||
|
tst-dlopen-tlsmodid \
|
||||||
|
tst-dlopen-tlsreinit1 \
|
||||||
|
@@ -785,6 +786,8 @@ modules-names = \
|
||||||
|
tst-dlmopen1mod \
|
||||||
|
tst-dlopen-auditdup-auditmod \
|
||||||
|
tst-dlopen-auditdupmod \
|
||||||
|
+ tst-dlopen-constructor-null-mod1 \
|
||||||
|
+ tst-dlopen-constructor-null-mod2 \
|
||||||
|
tst-dlopen-sgid-mod \
|
||||||
|
tst-dlopen-tlsreinitmod1 \
|
||||||
|
tst-dlopen-tlsreinitmod2 \
|
||||||
|
@@ -2937,3 +2940,9 @@ $(objpfx)tst-nolink-libc-2: $(objpfx)tst-nolink-libc.o
|
||||||
|
-Wl,--dynamic-linker=$(objpfx)ld.so
|
||||||
|
$(objpfx)tst-nolink-libc-2.out: $(objpfx)tst-nolink-libc-2 $(objpfx)ld.so
|
||||||
|
$< > $@ 2>&1; $(evaluate-test)
|
||||||
|
+
|
||||||
|
+$(objpfx)tst-dlopen-constructor-null: \
|
||||||
|
+ $(objpfx)tst-dlopen-constructor-null-mod1.so \
|
||||||
|
+ $(objpfx)tst-dlopen-constructor-null-mod2.so
|
||||||
|
+$(objpfx)tst-dlopen-constructor-null-mod2.so: \
|
||||||
|
+ $(objpfx)tst-dlopen-constructor-null-mod1.so
|
||||||
|
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||||
|
index 6557c2fd7ca0bbfe..c225654822ee3520 100644
|
||||||
|
--- a/elf/dl-open.c
|
||||||
|
+++ b/elf/dl-open.c
|
||||||
|
@@ -604,6 +604,16 @@ dl_open_worker_begin (void *a)
|
||||||
|
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||||
|
add_to_global_update (new);
|
||||||
|
|
||||||
|
+ /* It is not possible to run the ELF constructor for the new
|
||||||
|
+ link map if it has not executed yet: If this dlopen call came
|
||||||
|
+ from an ELF constructor that has not put that object into a
|
||||||
|
+ consistent state, completing initialization for the entire
|
||||||
|
+ scope will expose objects that have this partially
|
||||||
|
+ constructed object among its dependencies to this
|
||||||
|
+ inconsistent state. This could happen even with a benign
|
||||||
|
+ dlopen (NULL, RTLD_LAZY) call from a constructor of an
|
||||||
|
+ initially loaded shared object. */
|
||||||
|
+
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/elf/tst-dlopen-constructor-null-mod1.c b/elf/tst-dlopen-constructor-null-mod1.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..70a7a0ad46a1a666
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-dlopen-constructor-null-mod1.c
|
||||||
|
@@ -0,0 +1,55 @@
|
||||||
|
+/* Module calling dlopen (NULL, RTLD_LAZY) to obtain the global scope.
|
||||||
|
+ 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <dlfcn.h>
|
||||||
|
+#include <stddef.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+
|
||||||
|
+int mod1_status;
|
||||||
|
+
|
||||||
|
+static void __attribute__ ((constructor))
|
||||||
|
+init (void)
|
||||||
|
+{
|
||||||
|
+ puts ("info: tst-dlopen-constructor-null-mod1.so constructor");
|
||||||
|
+
|
||||||
|
+ void *handle = dlopen (NULL, RTLD_LAZY);
|
||||||
|
+ if (handle == NULL)
|
||||||
|
+ {
|
||||||
|
+ printf ("error: %s\n", dlerror ());
|
||||||
|
+ exit (1);
|
||||||
|
+ }
|
||||||
|
+ puts ("info: dlopen returned");
|
||||||
|
+ if (dlsym (handle, "malloc") != malloc)
|
||||||
|
+ {
|
||||||
|
+ puts ("error: dlsym did not produce expected result");
|
||||||
|
+ exit (1);
|
||||||
|
+ }
|
||||||
|
+ dlclose (handle);
|
||||||
|
+
|
||||||
|
+ /* Check that the second module's constructor has not executed. */
|
||||||
|
+ if (getenv ("mod2_status") != NULL)
|
||||||
|
+ {
|
||||||
|
+ printf ("error: mod2_status environment variable set: %s\n",
|
||||||
|
+ getenv ("mod2_status"));
|
||||||
|
+ exit (1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Communicate to the second module that the constructor executed. */
|
||||||
|
+ mod1_status = 1;
|
||||||
|
+}
|
||||||
|
diff --git a/elf/tst-dlopen-constructor-null-mod2.c b/elf/tst-dlopen-constructor-null-mod2.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..d6e945beaec04815
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-dlopen-constructor-null-mod2.c
|
||||||
|
@@ -0,0 +1,37 @@
|
||||||
|
+/* Module whose constructor should not be invoked by dlopen (NULL, RTLD_LAZY).
|
||||||
|
+ 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+
|
||||||
|
+extern int mod1_status;
|
||||||
|
+int mod2_status;
|
||||||
|
+
|
||||||
|
+static void __attribute__ ((constructor))
|
||||||
|
+init (void)
|
||||||
|
+{
|
||||||
|
+ printf ("info: tst-dlopen-constructor-null-mod2.so constructor"
|
||||||
|
+ " (mod1_status=%d)", mod1_status);
|
||||||
|
+ if (!(mod1_status == 1 && mod2_status == 0))
|
||||||
|
+ {
|
||||||
|
+ puts ("error: mod1_status == 1 && mod2_status == 0 expected");
|
||||||
|
+ exit (1);
|
||||||
|
+ }
|
||||||
|
+ setenv ("mod2_status", "constructed", 1);
|
||||||
|
+ mod2_status = 1;
|
||||||
|
+}
|
||||||
|
diff --git a/elf/tst-dlopen-constructor-null.c b/elf/tst-dlopen-constructor-null.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..db90643325c5235f
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-dlopen-constructor-null.c
|
||||||
|
@@ -0,0 +1,38 @@
|
||||||
|
+/* Verify that dlopen (NULL, RTLD_LAZY) does not complete initialization.
|
||||||
|
+ 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+/* This test mimics what the glvndSetupPthreads function in libglvnd
|
||||||
|
+ does. */
|
||||||
|
+
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+
|
||||||
|
+/* Defined and initialized in the shared objects. */
|
||||||
|
+extern int mod1_status;
|
||||||
|
+extern int mod2_status;
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ TEST_COMPARE (mod1_status, 1);
|
||||||
|
+ TEST_COMPARE (mod2_status, 1);
|
||||||
|
+ TEST_COMPARE_STRING (getenv ("mod2_status"), "constructed");
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
24
SOURCES/glibc-RHEL-47403-9.patch
Normal file
24
SOURCES/glibc-RHEL-47403-9.patch
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
commit ac73067cb7a328bf106ecd041c020fc61be7e087
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Oct 25 17:41:53 2024 +0200
|
||||||
|
|
||||||
|
elf: Fix map_complete Systemtap probe in dl_open_worker
|
||||||
|
|
||||||
|
The refactoring did not take the change of variable into account.
|
||||||
|
Fixes commit 43db5e2c0672cae7edea7c9685b22317eae25471
|
||||||
|
("elf: Signal RT_CONSISTENT after relocation processing in dlopen
|
||||||
|
(bug 31986)").
|
||||||
|
|
||||||
|
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||||
|
index c225654822ee3520..1e61e402455da666 100644
|
||||||
|
--- a/elf/dl-open.c
|
||||||
|
+++ b/elf/dl-open.c
|
||||||
|
@@ -789,7 +789,7 @@ dl_open_worker (void *a)
|
||||||
|
#endif
|
||||||
|
r->r_state = RT_CONSISTENT;
|
||||||
|
_dl_debug_state ();
|
||||||
|
- LIBC_PROBE (map_complete, 3, nsid, r, new);
|
||||||
|
+ LIBC_PROBE (map_complete, 3, nsid, r, args->map);
|
||||||
|
|
||||||
|
#ifdef SHARED
|
||||||
|
if (was_not_consistent)
|
||||||
120
SOURCES/glibc-RHEL-48820-1.patch
Normal file
120
SOURCES/glibc-RHEL-48820-1.patch
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Wed Nov 6 10:33:44 2024 +0100
|
||||||
|
|
||||||
|
elf: rtld_multiple_ref is always true
|
||||||
|
|
||||||
|
For a long time, libc.so.6 has dependend on ld.so, which
|
||||||
|
means that there is a reference to ld.so in all processes,
|
||||||
|
and rtld_multiple_ref is always true. In fact, if
|
||||||
|
rtld_multiple_ref were false, some of the ld.so setup code
|
||||||
|
would not run.
|
||||||
|
|
||||||
|
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/rtld.c (
|
||||||
|
- prelink support not removed downstream
|
||||||
|
- "elf: Add _dl_find_object function" not ported
|
||||||
|
downstream
|
||||||
|
)
|
||||||
|
|
||||||
|
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||||
|
index d02ecc834c9a4d43..711bb77d70da6563 100644
|
||||||
|
--- a/elf/rtld.c
|
||||||
|
+++ b/elf/rtld.c
|
||||||
|
@@ -2002,43 +2002,37 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
if (main_map->l_searchlist.r_list[i] == &GL(dl_rtld_map))
|
||||||
|
break;
|
||||||
|
|
||||||
|
- bool rtld_multiple_ref = false;
|
||||||
|
- if (__glibc_likely (i < main_map->l_searchlist.r_nlist))
|
||||||
|
- {
|
||||||
|
- /* Some DT_NEEDED entry referred to the interpreter object itself, so
|
||||||
|
- put it back in the list of visible objects. We insert it into the
|
||||||
|
- chain in symbol search order because gdb uses the chain's order as
|
||||||
|
- its symbol search order. */
|
||||||
|
- rtld_multiple_ref = true;
|
||||||
|
+ /* Insert the link map for the dynamic loader into the chain in
|
||||||
|
+ symbol search order because gdb uses the chain's order as its
|
||||||
|
+ symbol search order. */
|
||||||
|
|
||||||
|
- GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
|
||||||
|
- if (__glibc_likely (state.mode == rtld_mode_normal))
|
||||||
|
- {
|
||||||
|
- GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist
|
||||||
|
- ? main_map->l_searchlist.r_list[i + 1]
|
||||||
|
- : NULL);
|
||||||
|
+ GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
|
||||||
|
+ if (__glibc_likely (state.mode == rtld_mode_normal))
|
||||||
|
+ {
|
||||||
|
+ GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist
|
||||||
|
+ ? main_map->l_searchlist.r_list[i + 1]
|
||||||
|
+ : NULL);
|
||||||
|
#ifdef NEED_DL_SYSINFO_DSO
|
||||||
|
- if (GLRO(dl_sysinfo_map) != NULL
|
||||||
|
- && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map)
|
||||||
|
- && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map))
|
||||||
|
- GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map);
|
||||||
|
+ if (GLRO(dl_sysinfo_map) != NULL
|
||||||
|
+ && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map)
|
||||||
|
+ && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map))
|
||||||
|
+ GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map);
|
||||||
|
#endif
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- /* In trace mode there might be an invisible object (which we
|
||||||
|
- could not find) after the previous one in the search list.
|
||||||
|
- In this case it doesn't matter much where we put the
|
||||||
|
- interpreter object, so we just initialize the list pointer so
|
||||||
|
- that the assertion below holds. */
|
||||||
|
- GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next;
|
||||||
|
-
|
||||||
|
- assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next);
|
||||||
|
- GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map);
|
||||||
|
- if (GL(dl_rtld_map).l_next != NULL)
|
||||||
|
- {
|
||||||
|
- assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev);
|
||||||
|
- GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map);
|
||||||
|
- }
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ /* In trace mode there might be an invisible object (which we
|
||||||
|
+ could not find) after the previous one in the search list.
|
||||||
|
+ In this case it doesn't matter much where we put the
|
||||||
|
+ interpreter object, so we just initialize the list pointer so
|
||||||
|
+ that the assertion below holds. */
|
||||||
|
+ GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next;
|
||||||
|
+
|
||||||
|
+ assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next);
|
||||||
|
+ GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map);
|
||||||
|
+ if (GL(dl_rtld_map).l_next != NULL)
|
||||||
|
+ {
|
||||||
|
+ assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev);
|
||||||
|
+ GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now let us see whether all libraries are available in the
|
||||||
|
@@ -2212,8 +2206,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
|
||||||
|
- && rtld_multiple_ref)
|
||||||
|
+ if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
|
||||||
|
{
|
||||||
|
/* Mark the link map as not yet relocated again. */
|
||||||
|
GL(dl_rtld_map).l_relocated = 0;
|
||||||
|
@@ -2500,10 +2493,9 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
/* Make sure no new search directories have been added. */
|
||||||
|
assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs));
|
||||||
|
|
||||||
|
- if (! prelinked && rtld_multiple_ref)
|
||||||
|
+ if (! prelinked)
|
||||||
|
{
|
||||||
|
- /* There was an explicit ref to the dynamic linker as a shared lib.
|
||||||
|
- Re-relocate ourselves with user-controlled symbol definitions.
|
||||||
|
+ /* Re-relocate ourselves with user-controlled symbol definitions.
|
||||||
|
|
||||||
|
We must do this after TLS initialization in case after this
|
||||||
|
re-relocation, we might call a user-supplied function
|
||||||
52
SOURCES/glibc-RHEL-48820-2.patch
Normal file
52
SOURCES/glibc-RHEL-48820-2.patch
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
commit a79642204537dec8a1e1c58d1e0a074b3c624f46
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Wed Nov 6 10:33:44 2024 +0100
|
||||||
|
|
||||||
|
elf: Do not define consider_profiling, consider_symbind as macros
|
||||||
|
|
||||||
|
This avoids surprises when refactoring the code if these identifiers
|
||||||
|
are re-used later in the file.
|
||||||
|
|
||||||
|
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
|
||||||
|
index 0254e589c06fbf4c..ded506da9e180eac 100644
|
||||||
|
--- a/elf/dl-reloc.c
|
||||||
|
+++ b/elf/dl-reloc.c
|
||||||
|
@@ -207,8 +207,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||||
|
int lazy = reloc_mode & RTLD_LAZY;
|
||||||
|
int skip_ifunc = reloc_mode & __RTLD_NOIFUNC;
|
||||||
|
|
||||||
|
-#ifdef SHARED
|
||||||
|
bool consider_symbind = false;
|
||||||
|
+#ifdef SHARED
|
||||||
|
/* If we are auditing, install the same handlers we need for profiling. */
|
||||||
|
if ((reloc_mode & __RTLD_AUDIT) == 0)
|
||||||
|
{
|
||||||
|
@@ -227,9 +227,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||||
|
}
|
||||||
|
#elif defined PROF
|
||||||
|
/* Never use dynamic linker profiling for gprof profiling code. */
|
||||||
|
-# define consider_profiling 0
|
||||||
|
-#else
|
||||||
|
-# define consider_symbind 0
|
||||||
|
+ consider_profiling = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If DT_BIND_NOW is set relocate all references in this object. We
|
||||||
|
@@ -287,7 +285,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||||
|
|
||||||
|
ELF_DYNAMIC_RELOCATE (l, scope, lazy, consider_profiling, skip_ifunc);
|
||||||
|
|
||||||
|
-#ifndef PROF
|
||||||
|
if ((consider_profiling || consider_symbind)
|
||||||
|
&& l->l_info[DT_PLTRELSZ] != NULL)
|
||||||
|
{
|
||||||
|
@@ -308,7 +305,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||||
|
_dl_fatal_printf (errstring, RTLD_PROGNAME, l->l_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
-#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark the object so we know this work has been done. */
|
||||||
77
SOURCES/glibc-RHEL-48820-3.patch
Normal file
77
SOURCES/glibc-RHEL-48820-3.patch
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
commit f2326c2ec0a0a8db7bc7f4db8cce3002768fc3b6
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Wed Nov 6 10:33:44 2024 +0100
|
||||||
|
|
||||||
|
elf: Introduce _dl_relocate_object_no_relro
|
||||||
|
|
||||||
|
And make _dl_protect_relro apply RELRO conditionally.
|
||||||
|
|
||||||
|
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
|
||||||
|
index ded506da9e180eac..239f5505f805b008 100644
|
||||||
|
--- a/elf/dl-reloc.c
|
||||||
|
+++ b/elf/dl-reloc.c
|
||||||
|
@@ -189,12 +189,9 @@ _dl_nothread_init_static_tls (struct link_map *map)
|
||||||
|
#include "dynamic-link.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
-_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||||
|
- int reloc_mode, int consider_profiling)
|
||||||
|
+_dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
|
||||||
|
+ int reloc_mode, int consider_profiling)
|
||||||
|
{
|
||||||
|
- if (l->l_relocated)
|
||||||
|
- return;
|
||||||
|
-
|
||||||
|
struct textrels
|
||||||
|
{
|
||||||
|
caddr_t start;
|
||||||
|
@@ -325,17 +322,24 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||||
|
|
||||||
|
textrels = textrels->next;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- /* In case we can protect the data now that the relocations are
|
||||||
|
- done, do it. */
|
||||||
|
- if (l->l_relro_size != 0)
|
||||||
|
- _dl_protect_relro (l);
|
||||||
|
}
|
||||||
|
|
||||||
|
+void
|
||||||
|
+_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||||
|
+ int reloc_mode, int consider_profiling)
|
||||||
|
+{
|
||||||
|
+ if (l->l_relocated)
|
||||||
|
+ return;
|
||||||
|
+ _dl_relocate_object_no_relro (l, scope, reloc_mode, consider_profiling);
|
||||||
|
+ _dl_protect_relro (l);
|
||||||
|
+}
|
||||||
|
|
||||||
|
void
|
||||||
|
_dl_protect_relro (struct link_map *l)
|
||||||
|
{
|
||||||
|
+ if (l->l_relro_size == 0)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
ElfW(Addr) start = ALIGN_DOWN((l->l_addr
|
||||||
|
+ l->l_relro_addr),
|
||||||
|
GLRO(dl_pagesize));
|
||||||
|
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||||
|
index 537d1293c7b5543b..dc4e0555e4ed7f3c 100644
|
||||||
|
--- a/sysdeps/generic/ldsodefs.h
|
||||||
|
+++ b/sysdeps/generic/ldsodefs.h
|
||||||
|
@@ -1073,6 +1073,13 @@ extern void _dl_relocate_object (struct link_map *map,
|
||||||
|
int reloc_mode, int consider_profiling)
|
||||||
|
attribute_hidden;
|
||||||
|
|
||||||
|
+/* Perform relocation, but do not apply RELRO. Does not check
|
||||||
|
+ L->relocated. Otherwise the same as _dl_relocate_object. */
|
||||||
|
+void _dl_relocate_object_no_relro (struct link_map *map,
|
||||||
|
+ struct r_scope_elem *scope[],
|
||||||
|
+ int reloc_mode, int consider_profiling)
|
||||||
|
+ attribute_hidden;
|
||||||
|
+
|
||||||
|
/* Protect PT_GNU_RELRO area. */
|
||||||
|
extern void _dl_protect_relro (struct link_map *map) attribute_hidden;
|
||||||
|
|
||||||
203
SOURCES/glibc-RHEL-48820-4.patch
Normal file
203
SOURCES/glibc-RHEL-48820-4.patch
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
commit c1560f3f75c0e892b5522c16f91b4e303f677094
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Wed Nov 6 10:33:44 2024 +0100
|
||||||
|
|
||||||
|
elf: Switch to main malloc after final ld.so self-relocation
|
||||||
|
|
||||||
|
Before commit ee1ada1bdb8074de6e1bdc956ab19aef7b6a7872
|
||||||
|
("elf: Rework exception handling in the dynamic loader
|
||||||
|
[BZ #25486]"), the previous order called the main calloc
|
||||||
|
to allocate a shadow GOT/PLT array for auditing support.
|
||||||
|
This happened before libc.so.6 ELF constructors were run, so
|
||||||
|
a user malloc could run without libc.so.6 having been
|
||||||
|
initialized fully. One observable effect was that
|
||||||
|
environ was NULL at this point.
|
||||||
|
|
||||||
|
It does not seem to be possible at present to trigger such
|
||||||
|
an allocation, but it seems more robust to delay switching
|
||||||
|
to main malloc after ld.so self-relocation is complete.
|
||||||
|
The elf/tst-rtld-no-malloc-audit test case fails with a
|
||||||
|
2.34-era glibc that does not have this fix.
|
||||||
|
|
||||||
|
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/Makefile (fixup context)
|
||||||
|
elf/rtld.c (Align change with glibc-RHEL-48820-1)
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index 41adea8d1c6d13ca..0c8e0d794bac640f 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -439,6 +439,9 @@ tests += \
|
||||||
|
tst-recursive-tls \
|
||||||
|
tst-relsort1 \
|
||||||
|
tst-ro-dynamic \
|
||||||
|
+ tst-rtld-no-malloc \
|
||||||
|
+ tst-rtld-no-malloc-audit \
|
||||||
|
+ tst-rtld-no-malloc-preload \
|
||||||
|
tst-rtld-run-static \
|
||||||
|
tst-single_threaded \
|
||||||
|
tst-single_threaded-pthread \
|
||||||
|
@@ -2896,3 +2899,9 @@ tst-tls22-mod2.so-no-z-defs = yes
|
||||||
|
tst-tls22-mod2-gnu2.so-no-z-defs = yes
|
||||||
|
|
||||||
|
$(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
|
||||||
|
+
|
||||||
|
+# Reuse an audit module which provides ample debug logging.
|
||||||
|
+tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||||
|
+
|
||||||
|
+# Any shared object should do.
|
||||||
|
+tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
|
||||||
|
diff --git a/elf/dl-support.c b/elf/dl-support.c
|
||||||
|
index 1fea55c443505890..00abc2d8056c78b0 100644
|
||||||
|
--- a/elf/dl-support.c
|
||||||
|
+++ b/elf/dl-support.c
|
||||||
|
@@ -353,8 +353,7 @@ _dl_non_dynamic_init (void)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup relro on the binary itself. */
|
||||||
|
- if (_dl_main_map.l_relro_size != 0)
|
||||||
|
- _dl_protect_relro (&_dl_main_map);
|
||||||
|
+ _dl_protect_relro (&_dl_main_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DL_SYSINFO_IMPLEMENTATION
|
||||||
|
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||||
|
index 711bb77d70da6563..3436dd918e699080 100644
|
||||||
|
--- a/elf/rtld.c
|
||||||
|
+++ b/elf/rtld.c
|
||||||
|
@@ -2495,26 +2495,23 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
|
||||||
|
if (! prelinked)
|
||||||
|
{
|
||||||
|
- /* Re-relocate ourselves with user-controlled symbol definitions.
|
||||||
|
-
|
||||||
|
- We must do this after TLS initialization in case after this
|
||||||
|
- re-relocation, we might call a user-supplied function
|
||||||
|
- (e.g. calloc from _dl_relocate_object) that uses TLS data. */
|
||||||
|
-
|
||||||
|
- /* The malloc implementation has been relocated, so resolving
|
||||||
|
- its symbols (and potentially calling IFUNC resolvers) is safe
|
||||||
|
- at this point. */
|
||||||
|
- __rtld_malloc_init_real (main_map);
|
||||||
|
-
|
||||||
|
/* Likewise for the locking implementation. */
|
||||||
|
__rtld_mutex_init ();
|
||||||
|
|
||||||
|
+ /* Re-relocate ourselves with user-controlled symbol definitions. */
|
||||||
|
+
|
||||||
|
RTLD_TIMING_VAR (start);
|
||||||
|
rtld_timer_start (&start);
|
||||||
|
|
||||||
|
- /* Mark the link map as not yet relocated again. */
|
||||||
|
- GL(dl_rtld_map).l_relocated = 0;
|
||||||
|
- _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
|
||||||
|
+ _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
|
||||||
|
+
|
||||||
|
+ /* The malloc implementation has been relocated, so resolving
|
||||||
|
+ its symbols (and potentially calling IFUNC resolvers) is safe
|
||||||
|
+ at this point. */
|
||||||
|
+ __rtld_malloc_init_real (main_map);
|
||||||
|
+
|
||||||
|
+ if (GL(dl_rtld_map).l_relro_size != 0)
|
||||||
|
+ _dl_protect_relro (&GL(dl_rtld_map));
|
||||||
|
|
||||||
|
rtld_timer_accum (&relocate_time, start);
|
||||||
|
}
|
||||||
|
diff --git a/elf/tst-rtld-no-malloc-audit.c b/elf/tst-rtld-no-malloc-audit.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..a028377ad1fea027
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-rtld-no-malloc-audit.c
|
||||||
|
@@ -0,0 +1 @@
|
||||||
|
+#include "tst-rtld-no-malloc.c"
|
||||||
|
diff --git a/elf/tst-rtld-no-malloc-preload.c b/elf/tst-rtld-no-malloc-preload.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..a028377ad1fea027
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-rtld-no-malloc-preload.c
|
||||||
|
@@ -0,0 +1 @@
|
||||||
|
+#include "tst-rtld-no-malloc.c"
|
||||||
|
diff --git a/elf/tst-rtld-no-malloc.c b/elf/tst-rtld-no-malloc.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..5f24d4bd72c4af0c
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-rtld-no-malloc.c
|
||||||
|
@@ -0,0 +1,76 @@
|
||||||
|
+/* Test that program loading does not call malloc.
|
||||||
|
+ 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+print (const char *s)
|
||||||
|
+{
|
||||||
|
+ const char *end = s + strlen (s);
|
||||||
|
+ while (s < end)
|
||||||
|
+ {
|
||||||
|
+ ssize_t ret = write (STDOUT_FILENO, s, end - s);
|
||||||
|
+ if (ret <= 0)
|
||||||
|
+ _exit (2);
|
||||||
|
+ s += ret;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __attribute__ ((noreturn))
|
||||||
|
+unexpected_call (const char *function)
|
||||||
|
+{
|
||||||
|
+ print ("error: unexpected call to ");
|
||||||
|
+ print (function);
|
||||||
|
+ print ("\n");
|
||||||
|
+ _exit (1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* These are the malloc functions implement in elf/dl-minimal.c. */
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+free (void *ignored)
|
||||||
|
+{
|
||||||
|
+ unexpected_call ("free");
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void *
|
||||||
|
+calloc (size_t ignored1, size_t ignored2)
|
||||||
|
+{
|
||||||
|
+ unexpected_call ("calloc");
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void *
|
||||||
|
+malloc (size_t ignored)
|
||||||
|
+{
|
||||||
|
+ unexpected_call ("malloc");
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void *
|
||||||
|
+realloc (void *ignored1, size_t ignored2)
|
||||||
|
+{
|
||||||
|
+ unexpected_call ("realloc");
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int
|
||||||
|
+main (void)
|
||||||
|
+{
|
||||||
|
+ /* Do not use the test wrapper, to avoid spurious malloc calls from it. */
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
228
SOURCES/glibc-RHEL-48820-5.patch
Normal file
228
SOURCES/glibc-RHEL-48820-5.patch
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
commit 706209867f1ba89c458033408d419e92d8055f58
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Tue Jan 7 09:18:07 2025 +0100
|
||||||
|
|
||||||
|
elf: Second ld.so relocation only if libc.so has been loaded
|
||||||
|
|
||||||
|
Commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f (“elf:
|
||||||
|
rtld_multiple_ref is always true”) removed some code that happened
|
||||||
|
to enable compatibility with programs that do not link against
|
||||||
|
libc.so. Such programs cannot call dlopen or any dynamic linker
|
||||||
|
functions (except __tls_get_addr), so this is not really useful.
|
||||||
|
Still ld.so should not crash with a null-pointer dereference
|
||||||
|
or undefined symbol reference in these cases.
|
||||||
|
|
||||||
|
In the main relocation loop, call _dl_relocate_object unconditionally
|
||||||
|
because it already checks if the object has been relocated.
|
||||||
|
|
||||||
|
If libc.so was loaded, self-relocate ld.so against it and call
|
||||||
|
__rtld_mutex_init and __rtld_malloc_init_real to activate the full
|
||||||
|
implementations. Those are available only if libc.so is there,
|
||||||
|
so skip these initialization steps if libc.so is absent. Without
|
||||||
|
libc.so, the global scope can be completely empty. This can cause
|
||||||
|
ld.so self-relocation to fail because if it uses symbol-based
|
||||||
|
relocations, which is why the second ld.so self-relocation is not
|
||||||
|
performed if libc.so is missing.
|
||||||
|
|
||||||
|
The previous concern regarding GOT updates through self-relocation
|
||||||
|
no longer applies because function pointers are updated
|
||||||
|
explicitly through __rtld_mutex_init and __rtld_malloc_init_real,
|
||||||
|
and not through relocation. However, the second ld.so self-relocation
|
||||||
|
is still delayed, in case there are other symbols being used.
|
||||||
|
|
||||||
|
Fixes commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f (“elf:
|
||||||
|
rtld_multiple_ref is always true”).
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/Makefile (fixup context)
|
||||||
|
elf/rtld.c (
|
||||||
|
- Patch off due to prelink code
|
||||||
|
- "elf: Move _dl_rtld_map, _dl_rtld_audit_state out of GL" not
|
||||||
|
ported downstream
|
||||||
|
)
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index 0c8e0d794bac640f..d30f7f67e73a646e 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -2905,3 +2905,20 @@ tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||||
|
|
||||||
|
# Any shared object should do.
|
||||||
|
tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
|
||||||
|
+
|
||||||
|
+# These rules link and run the special elf/tst-nolink-libc-* tests if
|
||||||
|
+# a port adds them to the tests variables. Neither test variant is
|
||||||
|
+# linked against libc.so, but tst-nolink-libc-1 is linked against
|
||||||
|
+# ld.so. The test is always run directly, not under the dynamic
|
||||||
|
+# linker.
|
||||||
|
+CFLAGS-tst-nolink-libc.c += $(no-stack-protector)
|
||||||
|
+$(objpfx)tst-nolink-libc-1: $(objpfx)tst-nolink-libc.o $(objpfx)ld.so
|
||||||
|
+ $(LINK.o) -nostdlib -nostartfiles -o $@ $< \
|
||||||
|
+ -Wl,--dynamic-linker=$(objpfx)ld.so,--no-as-needed $(objpfx)ld.so
|
||||||
|
+$(objpfx)tst-nolink-libc-1.out: $(objpfx)tst-nolink-libc-1 $(objpfx)ld.so
|
||||||
|
+ $< > $@ 2>&1; $(evaluate-test)
|
||||||
|
+$(objpfx)tst-nolink-libc-2: $(objpfx)tst-nolink-libc.o
|
||||||
|
+ $(LINK.o) -nostdlib -nostartfiles -o $@ $< \
|
||||||
|
+ -Wl,--dynamic-linker=$(objpfx)ld.so
|
||||||
|
+$(objpfx)tst-nolink-libc-2.out: $(objpfx)tst-nolink-libc-2 $(objpfx)ld.so
|
||||||
|
+ $< > $@ 2>&1; $(evaluate-test)
|
||||||
|
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||||
|
index 3436dd918e699080..d3d9e6b904ac78fd 100644
|
||||||
|
--- a/elf/rtld.c
|
||||||
|
+++ b/elf/rtld.c
|
||||||
|
@@ -2410,25 +2410,25 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
- /* Now we have all the objects loaded. Relocate them all except for
|
||||||
|
- the dynamic linker itself. We do this in reverse order so that copy
|
||||||
|
- relocs of earlier objects overwrite the data written by later
|
||||||
|
- objects. We do not re-relocate the dynamic linker itself in this
|
||||||
|
- loop because that could result in the GOT entries for functions we
|
||||||
|
- call being changed, and that would break us. It is safe to relocate
|
||||||
|
- the dynamic linker out of order because it has no copy relocations.
|
||||||
|
- Likewise for libc, which is relocated early to ensure that IFUNC
|
||||||
|
- resolvers in libc work. */
|
||||||
|
+ /* Now we have all the objects loaded. */
|
||||||
|
|
||||||
|
int consider_profiling = GLRO(dl_profile) != NULL;
|
||||||
|
|
||||||
|
/* If we are profiling we also must do lazy reloaction. */
|
||||||
|
GLRO(dl_lazy) |= consider_profiling;
|
||||||
|
|
||||||
|
+ /* If libc.so has been loaded, relocate it early, after the dynamic
|
||||||
|
+ loader itself. The initial self-relocation of ld.so should be
|
||||||
|
+ sufficient for IFUNC resolvers in libc.so. */
|
||||||
|
if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL)
|
||||||
|
- _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map,
|
||||||
|
- GL(dl_ns)[LM_ID_BASE].libc_map->l_scope,
|
||||||
|
- GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling);
|
||||||
|
+ {
|
||||||
|
+ RTLD_TIMING_VAR (start);
|
||||||
|
+ rtld_timer_start (&start);
|
||||||
|
+ _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map,
|
||||||
|
+ GL(dl_ns)[LM_ID_BASE].libc_map->l_scope,
|
||||||
|
+ GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling);
|
||||||
|
+ rtld_timer_accum (&relocate_time, start);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
RTLD_TIMING_VAR (start);
|
||||||
|
rtld_timer_start (&start);
|
||||||
|
@@ -2450,9 +2450,8 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
/* Also allocated with the fake malloc(). */
|
||||||
|
l->l_free_initfini = 0;
|
||||||
|
|
||||||
|
- if (l != &GL(dl_rtld_map))
|
||||||
|
- _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0,
|
||||||
|
- consider_profiling);
|
||||||
|
+ _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0,
|
||||||
|
+ consider_profiling);
|
||||||
|
|
||||||
|
/* Add object to slot information data if necessasy. */
|
||||||
|
if (l->l_tls_blocksize != 0 && __rtld_tls_init_tp_called)
|
||||||
|
@@ -2495,25 +2494,22 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||||
|
|
||||||
|
if (! prelinked)
|
||||||
|
{
|
||||||
|
- /* Likewise for the locking implementation. */
|
||||||
|
- __rtld_mutex_init ();
|
||||||
|
-
|
||||||
|
- /* Re-relocate ourselves with user-controlled symbol definitions. */
|
||||||
|
-
|
||||||
|
- RTLD_TIMING_VAR (start);
|
||||||
|
- rtld_timer_start (&start);
|
||||||
|
-
|
||||||
|
- _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
|
||||||
|
-
|
||||||
|
- /* The malloc implementation has been relocated, so resolving
|
||||||
|
- its symbols (and potentially calling IFUNC resolvers) is safe
|
||||||
|
- at this point. */
|
||||||
|
- __rtld_malloc_init_real (main_map);
|
||||||
|
+ /* If libc.so was loaded, relocate ld.so against it. Complete ld.so
|
||||||
|
+ initialization with mutex symbols from libc.so and malloc symbols
|
||||||
|
+ from the global scope. */
|
||||||
|
+ if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL)
|
||||||
|
+ {
|
||||||
|
+ RTLD_TIMING_VAR (start);
|
||||||
|
+ rtld_timer_start (&start);
|
||||||
|
+ _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
|
||||||
|
+ rtld_timer_accum (&relocate_time, start);
|
||||||
|
|
||||||
|
- if (GL(dl_rtld_map).l_relro_size != 0)
|
||||||
|
- _dl_protect_relro (&GL(dl_rtld_map));
|
||||||
|
+ __rtld_mutex_init ();
|
||||||
|
+ __rtld_malloc_init_real (main_map);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- rtld_timer_accum (&relocate_time, start);
|
||||||
|
+ /* All ld.so initialization is complete. Apply RELRO. */
|
||||||
|
+ _dl_protect_relro (&GL(dl_rtld_map));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Relocation is complete. Perform early libc initialization. This
|
||||||
|
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
|
||||||
|
index 460ba54a8afcc515..94eb2665b27371a4 100644
|
||||||
|
--- a/sysdeps/unix/sysv/linux/Makefile
|
||||||
|
+++ b/sysdeps/unix/sysv/linux/Makefile
|
||||||
|
@@ -393,7 +393,15 @@ libof-lddlibc4 = lddlibc4
|
||||||
|
others += pldd
|
||||||
|
install-bin += pldd
|
||||||
|
$(objpfx)pldd: $(objpfx)xmalloc.o
|
||||||
|
+
|
||||||
|
+test-internal-extras += tst-nolink-libc
|
||||||
|
+ifeq ($(run-built-tests),yes)
|
||||||
|
+tests-special += \
|
||||||
|
+ $(objpfx)tst-nolink-libc-1.out \
|
||||||
|
+ $(objpfx)tst-nolink-libc-2.out \
|
||||||
|
+ # tests-special
|
||||||
|
endif
|
||||||
|
+endif # $(subdir) == elf
|
||||||
|
|
||||||
|
ifeq ($(subdir),rt)
|
||||||
|
CFLAGS-mq_send.c += -fexceptions
|
||||||
|
diff --git a/sysdeps/unix/sysv/linux/arm/Makefile b/sysdeps/unix/sysv/linux/arm/Makefile
|
||||||
|
index 32db854cbd6bdfd6..ab7ced85408ee515 100644
|
||||||
|
--- a/sysdeps/unix/sysv/linux/arm/Makefile
|
||||||
|
+++ b/sysdeps/unix/sysv/linux/arm/Makefile
|
||||||
|
@@ -1,5 +1,8 @@
|
||||||
|
ifeq ($(subdir),elf)
|
||||||
|
sysdep-rtld-routines += aeabi_read_tp libc-do-syscall
|
||||||
|
+# The test uses INTERNAL_SYSCALL_CALL. In thumb mode, this uses
|
||||||
|
+# an undefined reference to __libc_do_syscall.
|
||||||
|
+CFLAGS-tst-nolink-libc.c += -marm
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(subdir),misc)
|
||||||
|
diff --git a/sysdeps/unix/sysv/linux/tst-nolink-libc.c b/sysdeps/unix/sysv/linux/tst-nolink-libc.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..817f37784b4080f9
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/sysdeps/unix/sysv/linux/tst-nolink-libc.c
|
||||||
|
@@ -0,0 +1,25 @@
|
||||||
|
+/* Test program not linked against libc.so and not using any glibc 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <sysdep.h>
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+_start (void)
|
||||||
|
+{
|
||||||
|
+ INTERNAL_SYSCALL_CALL (exit_group, 0);
|
||||||
|
+}
|
||||||
28
SOURCES/glibc-RHEL-48820-6.patch
Normal file
28
SOURCES/glibc-RHEL-48820-6.patch
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
commit 39183f47d8bc9eda711c9797b18d69d7a02af91c
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Wed Jan 8 16:55:31 2025 +0100
|
||||||
|
|
||||||
|
elf: Minimize library dependencies of tst-nolink-libc.c
|
||||||
|
|
||||||
|
On 32-bit Arm, -fasynchronous-unwind-tables creates a reference
|
||||||
|
to the symbol __aeabi_unwind_cpp_pr0. Compile the tests without
|
||||||
|
this flag even if it is passed as part of CC, to avoid linker
|
||||||
|
failures.
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index d30f7f67e73a646e..dc93f631a682a006 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -2910,8 +2910,10 @@ tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
|
||||||
|
# a port adds them to the tests variables. Neither test variant is
|
||||||
|
# linked against libc.so, but tst-nolink-libc-1 is linked against
|
||||||
|
# ld.so. The test is always run directly, not under the dynamic
|
||||||
|
-# linker.
|
||||||
|
-CFLAGS-tst-nolink-libc.c += $(no-stack-protector)
|
||||||
|
+# linker. It is necessary to minimize run-time dependencies, by
|
||||||
|
+# disabling stack protection and unwinding.
|
||||||
|
+CFLAGS-tst-nolink-libc.c += $(no-stack-protector) \
|
||||||
|
+ -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables
|
||||||
|
$(objpfx)tst-nolink-libc-1: $(objpfx)tst-nolink-libc.o $(objpfx)ld.so
|
||||||
|
$(LINK.o) -nostdlib -nostartfiles -o $@ $< \
|
||||||
|
-Wl,--dynamic-linker=$(objpfx)ld.so,--no-as-needed $(objpfx)ld.so
|
||||||
30
SOURCES/glibc-RHEL-48820-7.patch
Normal file
30
SOURCES/glibc-RHEL-48820-7.patch
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
commit d30f41d2c9031b0540641af692e56002eab5599f
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Thu Jun 26 11:38:00 2025 +0200
|
||||||
|
|
||||||
|
elf: Add missing DSO dependencies for tst-rtld-no-malloc-{audit,preload}
|
||||||
|
|
||||||
|
Fixes commit c1560f3f75c0e892b5522c16f91b4e303f677094
|
||||||
|
("elf: Switch to main malloc after final ld.so self-relocation").
|
||||||
|
|
||||||
|
Reviewed-by: Frédéric Bérat <fberat@redhat.com>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/Makefile (fixup context)
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index dc93f631a682a006..15bec14364266c77 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -2902,9 +2902,11 @@ $(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
|
||||||
|
|
||||||
|
# Reuse an audit module which provides ample debug logging.
|
||||||
|
tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||||
|
+$(objpfx)tst-rtld-no-malloc-audit.out: $(objpfx)tst-auditmod1.so
|
||||||
|
|
||||||
|
# Any shared object should do.
|
||||||
|
tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
|
||||||
|
+$(objpfx)tst-rtld-no-malloc-preload.out: $(objpfx)tst-auditmod1.so
|
||||||
|
|
||||||
|
# These rules link and run the special elf/tst-nolink-libc-* tests if
|
||||||
|
# a port adds them to the tests variables. Neither test variant is
|
||||||
55
SOURCES/glibc-RHEL-49549-1.patch
Normal file
55
SOURCES/glibc-RHEL-49549-1.patch
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
commit 152f863926e77c6f9c9a8b8779c8084eb844ec44
|
||||||
|
Author: Andreas Schwab <schwab@suse.de>
|
||||||
|
Date: Thu Mar 23 16:18:50 2023 +0100
|
||||||
|
|
||||||
|
_dl_map_object_from_fd: Remove unnecessary debugger notification in error path
|
||||||
|
|
||||||
|
After commit ed3ce71f5c ("elf: Move la_activity (LA_ACT_ADD) after
|
||||||
|
_dl_add_to_namespace_list() (BZ #28062)") it is no longer necessary to
|
||||||
|
reset the debugger state in the error case, since the debugger
|
||||||
|
notification only happens after no more errors can occur.
|
||||||
|
|
||||||
|
diff --git a/elf/dl-load.c b/elf/dl-load.c
|
||||||
|
index 5b0734c816b351f0..98a91d40b74cb76b 100644
|
||||||
|
--- a/elf/dl-load.c
|
||||||
|
+++ b/elf/dl-load.c
|
||||||
|
@@ -950,8 +950,6 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||||
|
/* Initialize to keep the compiler happy. */
|
||||||
|
const char *errstring = NULL;
|
||||||
|
int errval = 0;
|
||||||
|
- struct r_debug *r = _dl_debug_update (nsid);
|
||||||
|
- bool make_consistent = false;
|
||||||
|
|
||||||
|
/* Get file information. To match the kernel behavior, do not fill
|
||||||
|
in this information for the executable in case of an explicit
|
||||||
|
@@ -983,14 +981,6 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||||
|
free ((void *) l->l_phdr);
|
||||||
|
free (l);
|
||||||
|
free (realname);
|
||||||
|
-
|
||||||
|
- if (make_consistent && r != NULL)
|
||||||
|
- {
|
||||||
|
- r->r_state = RT_CONSISTENT;
|
||||||
|
- _dl_debug_state ();
|
||||||
|
- LIBC_PROBE (map_failed, 2, nsid, r);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
_dl_signal_error (errval, name, NULL, errstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1476,6 +1466,7 @@ cannot enable executable stack as shared object requires");
|
||||||
|
_dl_add_to_namespace_list (l, nsid);
|
||||||
|
|
||||||
|
/* Signal that we are going to add new objects. */
|
||||||
|
+ struct r_debug *r = _dl_debug_update (nsid);
|
||||||
|
if (r->r_state == RT_CONSISTENT)
|
||||||
|
{
|
||||||
|
#ifdef SHARED
|
||||||
|
@@ -1492,7 +1483,6 @@ cannot enable executable stack as shared object requires");
|
||||||
|
r->r_state = RT_ADD;
|
||||||
|
_dl_debug_state ();
|
||||||
|
LIBC_PROBE (map_start, 2, nsid, r);
|
||||||
|
- make_consistent = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
assert (r->r_state == RT_ADD);
|
||||||
174
SOURCES/glibc-RHEL-49549-2.patch
Normal file
174
SOURCES/glibc-RHEL-49549-2.patch
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
commit ab5aa2ee3d3f978e474803cbbc5fe805ad30e293
|
||||||
|
Author: Andreas Schwab <schwab@suse.de>
|
||||||
|
Date: Thu Mar 23 16:46:20 2023 +0100
|
||||||
|
|
||||||
|
dlopen: skip debugger notification for DSO loaded from sprof (bug 30258)
|
||||||
|
|
||||||
|
Avoid inconsistent state in the debugger interface.
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/Makefile: Test differences.
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index 86d4dd9960088ee1..721f254d121118c0 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -528,6 +528,7 @@ tests-container += \
|
||||||
|
|
||||||
|
test-srcs = \
|
||||||
|
tst-pathopt \
|
||||||
|
+ tst-sprof-basic \
|
||||||
|
# tests-srcs
|
||||||
|
|
||||||
|
ifeq (yes,$(have-fpie))
|
||||||
|
@@ -860,6 +861,7 @@ modules-names = \
|
||||||
|
tst-sonamemove-linkmod1 \
|
||||||
|
tst-sonamemove-runmod1 \
|
||||||
|
tst-sonamemove-runmod2 \
|
||||||
|
+ tst-sprof-mod \
|
||||||
|
tst-tls19mod1 \
|
||||||
|
tst-tls19mod2 \
|
||||||
|
tst-tls19mod3 \
|
||||||
|
@@ -1114,6 +1116,7 @@ tests-special += \
|
||||||
|
$(objpfx)tst-rtld-help.out \
|
||||||
|
$(objpfx)tst-rtld-load-self.out \
|
||||||
|
$(objpfx)tst-rtld-preload.out \
|
||||||
|
+ $(objpfx)tst-sprof-basic.out \
|
||||||
|
# tests-special
|
||||||
|
endif
|
||||||
|
tests-special += \
|
||||||
|
@@ -2946,3 +2949,11 @@ $(objpfx)tst-dlopen-constructor-null: \
|
||||||
|
$(objpfx)tst-dlopen-constructor-null-mod2.so
|
||||||
|
$(objpfx)tst-dlopen-constructor-null-mod2.so: \
|
||||||
|
$(objpfx)tst-dlopen-constructor-null-mod1.so
|
||||||
|
+
|
||||||
|
+LDFLAGS-tst-sprof-mod.so = -Wl,-soname,tst-sprof-mod.so
|
||||||
|
+$(objpfx)tst-sprof-basic: $(objpfx)tst-sprof-mod.so
|
||||||
|
+$(objpfx)tst-sprof-basic.out: tst-sprof-basic.sh $(objpfx)tst-sprof-basic
|
||||||
|
+ $(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' \
|
||||||
|
+ '$(run-program-env)' > $@; \
|
||||||
|
+ $(evaluate-test)
|
||||||
|
+generated += tst-sprof-mod.so.profile
|
||||||
|
diff --git a/elf/dl-load.c b/elf/dl-load.c
|
||||||
|
index 98a91d40b74cb76b..5c1be6e80cd52e2f 100644
|
||||||
|
--- a/elf/dl-load.c
|
||||||
|
+++ b/elf/dl-load.c
|
||||||
|
@@ -1465,6 +1465,10 @@ cannot enable executable stack as shared object requires");
|
||||||
|
/* Now that the object is fully initialized add it to the object list. */
|
||||||
|
_dl_add_to_namespace_list (l, nsid);
|
||||||
|
|
||||||
|
+ /* Skip auditing and debugger notification when called from 'sprof'. */
|
||||||
|
+ if (mode & __RTLD_SPROF)
|
||||||
|
+ return l;
|
||||||
|
+
|
||||||
|
/* Signal that we are going to add new objects. */
|
||||||
|
struct r_debug *r = _dl_debug_update (nsid);
|
||||||
|
if (r->r_state == RT_CONSISTENT)
|
||||||
|
diff --git a/elf/tst-sprof-basic.c b/elf/tst-sprof-basic.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..5e4083305a4acdd6
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-sprof-basic.c
|
||||||
|
@@ -0,0 +1,25 @@
|
||||||
|
+/* Copyright (C) 2023 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/>. */
|
||||||
|
+
|
||||||
|
+void hello (void);
|
||||||
|
+
|
||||||
|
+int
|
||||||
|
+main (void)
|
||||||
|
+{
|
||||||
|
+ hello ();
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
diff --git a/elf/tst-sprof-basic.sh b/elf/tst-sprof-basic.sh
|
||||||
|
new file mode 100755
|
||||||
|
index 0000000000000000..901db61708c1b8ec
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-sprof-basic.sh
|
||||||
|
@@ -0,0 +1,41 @@
|
||||||
|
+#!/bin/sh
|
||||||
|
+# Test basic functionality of sprof
|
||||||
|
+# Copyright (C) 2023 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/>.
|
||||||
|
+
|
||||||
|
+set -e
|
||||||
|
+
|
||||||
|
+common_objpfx=$1
|
||||||
|
+test_wrapper_env=$2
|
||||||
|
+run_program_env=$3
|
||||||
|
+
|
||||||
|
+sprof_mod=tst-sprof-mod.so
|
||||||
|
+
|
||||||
|
+${test_wrapper_env} \
|
||||||
|
+${run_program_env} \
|
||||||
|
+LD_PROFILE=$sprof_mod \
|
||||||
|
+LD_PROFILE_OUTPUT=${common_objpfx}elf \
|
||||||
|
+LD_LIBRARY_PATH=${common_objpfx}.:${common_objpfx}elf \
|
||||||
|
+ ${common_objpfx}elf/ld.so ${common_objpfx}elf/tst-sprof-basic
|
||||||
|
+
|
||||||
|
+${test_wrapper_env} \
|
||||||
|
+${run_program_env} \
|
||||||
|
+LD_LIBRARY_PATH=${common_objpfx}.:${common_objpfx}elf \
|
||||||
|
+ ${common_objpfx}elf/ld.so ${common_objpfx}elf/sprof -p $sprof_mod \
|
||||||
|
+ ${common_objpfx}elf/${sprof_mod}.profile
|
||||||
|
+
|
||||||
|
+exit $?
|
||||||
|
diff --git a/elf/tst-sprof-mod.c b/elf/tst-sprof-mod.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..8b3f5e8e07f42ae6
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/tst-sprof-mod.c
|
||||||
|
@@ -0,0 +1,24 @@
|
||||||
|
+/* Copyright (C) 2023 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 <stdio.h>
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+hello (void)
|
||||||
|
+{
|
||||||
|
+ printf ("Hello World\n");
|
||||||
|
+}
|
||||||
30
SOURCES/glibc-RHEL-49549-3.patch
Normal file
30
SOURCES/glibc-RHEL-49549-3.patch
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
commit f563971b5bf7191acfdd5702fe00878752c2056d
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Tue Sep 26 11:40:12 2023 +0200
|
||||||
|
|
||||||
|
elf: Add dummy declaration of _dl_audit_objclose for !SHARED
|
||||||
|
|
||||||
|
This allows us to avoid some #ifdef SHARED conditionals.
|
||||||
|
|
||||||
|
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||||
|
index 3d9b90a22bfa6a7d..21dbe2d21ed8e605 100644
|
||||||
|
--- a/sysdeps/generic/ldsodefs.h
|
||||||
|
+++ b/sysdeps/generic/ldsodefs.h
|
||||||
|
@@ -1457,7 +1457,14 @@ void DL_ARCH_FIXUP_ATTRIBUTE _dl_audit_pltexit (struct link_map *l,
|
||||||
|
const void *inregs,
|
||||||
|
void *outregs)
|
||||||
|
attribute_hidden;
|
||||||
|
-#endif /* SHARED */
|
||||||
|
+
|
||||||
|
+#else /* !SHARED */
|
||||||
|
+static inline void
|
||||||
|
+_dl_audit_objclose (struct link_map *l)
|
||||||
|
+{
|
||||||
|
+ /* No audit implementation for !SHARED. */
|
||||||
|
+}
|
||||||
|
+#endif /* !SHARED */
|
||||||
|
|
||||||
|
#if PTHREAD_IN_LIBC && defined SHARED
|
||||||
|
/* Recursive locking implementation for use within the dynamic loader.
|
||||||
102
SOURCES/glibc-RHEL-49549-4.patch
Normal file
102
SOURCES/glibc-RHEL-49549-4.patch
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
commit ed2b8d3a866eb37e069f6a71bdf10421cd4c5e54
|
||||||
|
Author: Adam Sampson <ats@offog.org>
|
||||||
|
Date: Mon May 6 18:16:32 2024 +0100
|
||||||
|
|
||||||
|
ldconfig: Move endswithn into a new header file
|
||||||
|
|
||||||
|
is_gdb_python_file is doing a similar test, so it can use this helper
|
||||||
|
function as well.
|
||||||
|
|
||||||
|
Signed-off-by: Adam Sampson <ats@offog.org>
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/elf/endswith.h b/elf/endswith.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..c6430c48be0c1071
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/endswith.h
|
||||||
|
@@ -0,0 +1,33 @@
|
||||||
|
+/* Copyright (C) 2023-2024 Free Software Foundation, Inc.
|
||||||
|
+ This file is part of the GNU C Library.
|
||||||
|
+
|
||||||
|
+ This program is free software; you can redistribute it and/or modify
|
||||||
|
+ it under the terms of the GNU General Public License as published
|
||||||
|
+ by the Free Software Foundation; version 2 of the License, or
|
||||||
|
+ (at your option) any later version.
|
||||||
|
+
|
||||||
|
+ This program 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 General Public License for more details.
|
||||||
|
+
|
||||||
|
+ You should have received a copy of the GNU General Public License
|
||||||
|
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#ifndef _ENDSWITH_H
|
||||||
|
+#define _ENDSWITH_H
|
||||||
|
+
|
||||||
|
+#include <string.h>
|
||||||
|
+
|
||||||
|
+/* Return true if the N bytes at NAME end with with the characters in
|
||||||
|
+ the string SUFFIX. (NAME[N + 1] does not have to be a null byte.)
|
||||||
|
+ Expected to be called with a string literal for SUFFIX. */
|
||||||
|
+static inline bool
|
||||||
|
+endswithn (const char *name, size_t n, const char *suffix)
|
||||||
|
+{
|
||||||
|
+ return (n >= strlen (suffix)
|
||||||
|
+ && memcmp (name + n - strlen (suffix), suffix,
|
||||||
|
+ strlen (suffix)) == 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#endif /* _ENDSWITH_H */
|
||||||
|
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
|
||||||
|
index 4a96c409994d96c8..185c8115ae6b4060 100644
|
||||||
|
--- a/elf/ldconfig.c
|
||||||
|
+++ b/elf/ldconfig.c
|
||||||
|
@@ -41,6 +41,7 @@
|
||||||
|
#include <libgen.h>
|
||||||
|
|
||||||
|
#include <ldconfig.h>
|
||||||
|
+#include <endswith.h>
|
||||||
|
#include <dl-cache.h>
|
||||||
|
#include <dl-hwcaps.h>
|
||||||
|
#include <dl-is_dso.h>
|
||||||
|
@@ -778,17 +779,6 @@ struct dlib_entry
|
||||||
|
struct dlib_entry *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
-/* Return true if the N bytes at NAME end with with the characters in
|
||||||
|
- the string SUFFIX. (NAME[N + 1] does not have to be a null byte.)
|
||||||
|
- Expected to be called with a string literal for SUFFIX. */
|
||||||
|
-static inline bool
|
||||||
|
-endswithn (const char *name, size_t n, const char *suffix)
|
||||||
|
-{
|
||||||
|
- return (n >= strlen (suffix)
|
||||||
|
- && memcmp (name + n - strlen (suffix), suffix,
|
||||||
|
- strlen (suffix)) == 0);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
/* Skip some temporary DSO files. These files may be partially written
|
||||||
|
and lead to ldconfig crashes when examined. */
|
||||||
|
static bool
|
||||||
|
diff --git a/elf/readlib.c b/elf/readlib.c
|
||||||
|
index 8901de2684835653..2701535e3f24a201 100644
|
||||||
|
--- a/elf/readlib.c
|
||||||
|
+++ b/elf/readlib.c
|
||||||
|
@@ -35,6 +35,7 @@
|
||||||
|
#include <gnu/lib-names.h>
|
||||||
|
|
||||||
|
#include <ldconfig.h>
|
||||||
|
+#include <endswith.h>
|
||||||
|
|
||||||
|
#define Elf32_CLASS ELFCLASS32
|
||||||
|
#define Elf64_CLASS ELFCLASS64
|
||||||
|
@@ -68,7 +69,7 @@ static bool
|
||||||
|
is_gdb_python_file (const char *name)
|
||||||
|
{
|
||||||
|
size_t len = strlen (name);
|
||||||
|
- return len > 7 && strcmp (name + len - 7, "-gdb.py") == 0;
|
||||||
|
+ return endswithn (name, len, "-gdb.py");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns 0 if everything is ok, != 0 in case of error. */
|
||||||
76
SOURCES/glibc-RHEL-49549-5.patch
Normal file
76
SOURCES/glibc-RHEL-49549-5.patch
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
commit 4a50fdf8b2c1106b50cd9056b4c6f3a72cdeed5f
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Tue Sep 3 17:52:47 2024 +0200
|
||||||
|
|
||||||
|
elf: Update DSO list, write audit log to elf/tst-audit23.out
|
||||||
|
|
||||||
|
After commit 1d5024f4f052c12e404d42d3b5bfe9c3e9fd27c4
|
||||||
|
("support: Build with exceptions and asynchronous unwind tables
|
||||||
|
[BZ #30587]"), libgcc_s is expected to show up in the DSO
|
||||||
|
list on 32-bit Arm. Do not update max_objs because vdso is not
|
||||||
|
tracked (and which is the reason why the test currently passes
|
||||||
|
even with libgcc_s present).
|
||||||
|
|
||||||
|
Also write the log output from the auditor to standard output,
|
||||||
|
for easier test debugging.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
|
||||||
|
index 4904cf1340a97ee1..6ac1f20af60a2ebb 100644
|
||||||
|
--- a/elf/tst-audit23.c
|
||||||
|
+++ b/elf/tst-audit23.c
|
||||||
|
@@ -85,13 +85,28 @@ do_test (int argc, char *argv[])
|
||||||
|
= support_capture_subprogram (spargv[0], spargv);
|
||||||
|
support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr);
|
||||||
|
|
||||||
|
+ {
|
||||||
|
+ FILE *fp = fmemopen (result.err.buffer, result.err.length, "r");
|
||||||
|
+ TEST_VERIFY (fp != NULL);
|
||||||
|
+ unsigned int line = 0;
|
||||||
|
+ char *buffer = NULL;
|
||||||
|
+ size_t buffer_length = 0;
|
||||||
|
+ puts ("info: *** audit log start ***");
|
||||||
|
+ while (xgetline (&buffer, &buffer_length, fp))
|
||||||
|
+ printf ("%6u\t%s", ++line, buffer);
|
||||||
|
+ puts ("info: *** audit log end ***");
|
||||||
|
+ free (buffer);
|
||||||
|
+ xfclose (fp);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* The expected la_objopen/la_objclose:
|
||||||
|
1. executable
|
||||||
|
2. loader
|
||||||
|
3. libc.so
|
||||||
|
- 4. tst-audit23mod.so
|
||||||
|
- 5. libc.so (LM_ID_NEWLM).
|
||||||
|
- 6. vdso (optional and ignored). */
|
||||||
|
+ 4. libgcc_s.so (one some architectures, for libsupport)
|
||||||
|
+ 5. tst-audit23mod.so
|
||||||
|
+ 6. libc.so (LM_ID_NEWLM).
|
||||||
|
+ vdso (optional and ignored). */
|
||||||
|
enum { max_objs = 6 };
|
||||||
|
struct la_obj_t
|
||||||
|
{
|
||||||
|
@@ -115,8 +130,10 @@ do_test (int argc, char *argv[])
|
||||||
|
TEST_VERIFY (out != NULL);
|
||||||
|
char *buffer = NULL;
|
||||||
|
size_t buffer_length = 0;
|
||||||
|
+ unsigned int line = 0;
|
||||||
|
while (xgetline (&buffer, &buffer_length, out))
|
||||||
|
{
|
||||||
|
+ ++line;
|
||||||
|
if (startswith (buffer, "la_activity: "))
|
||||||
|
{
|
||||||
|
uintptr_t cookie;
|
||||||
|
@@ -174,8 +191,8 @@ do_test (int argc, char *argv[])
|
||||||
|
if (is_vdso (lname))
|
||||||
|
continue;
|
||||||
|
if (nobjs == max_objs)
|
||||||
|
- FAIL_EXIT1 ("non expected la_objopen: %s %"PRIxPTR" %ld",
|
||||||
|
- lname, laddr, lmid);
|
||||||
|
+ FAIL_EXIT1 ("(line %u) non expected la_objopen: %s %"PRIxPTR" %ld",
|
||||||
|
+ line, lname, laddr, lmid);
|
||||||
|
objs[nobjs].lname = lname;
|
||||||
|
objs[nobjs].laddr = laddr;
|
||||||
|
objs[nobjs].lmid = lmid;
|
||||||
34
SOURCES/glibc-RHEL-49549-6.patch
Normal file
34
SOURCES/glibc-RHEL-49549-6.patch
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
commit a20bc2f6233a726c7df8eaa332b6e498bd59321f
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Nov 29 15:36:40 2024 +0100
|
||||||
|
|
||||||
|
elf: Add the endswith function to <endswith.h>
|
||||||
|
|
||||||
|
And include <stdbool.h> for a definition of bool.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/elf/endswith.h b/elf/endswith.h
|
||||||
|
index c6430c48be0c1071..3954e57f8eff0faa 100644
|
||||||
|
--- a/elf/endswith.h
|
||||||
|
+++ b/elf/endswith.h
|
||||||
|
@@ -17,6 +17,7 @@
|
||||||
|
#ifndef _ENDSWITH_H
|
||||||
|
#define _ENDSWITH_H
|
||||||
|
|
||||||
|
+#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Return true if the N bytes at NAME end with with the characters in
|
||||||
|
@@ -30,4 +31,11 @@ endswithn (const char *name, size_t n, const char *suffix)
|
||||||
|
strlen (suffix)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* Same as endswithn, but uses the entire SUBJECT for matching. */
|
||||||
|
+static inline bool
|
||||||
|
+endswith (const char *subject, const char *suffix)
|
||||||
|
+{
|
||||||
|
+ return endswithn (subject, strlen (subject), suffix);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#endif /* _ENDSWITH_H */
|
||||||
131
SOURCES/glibc-RHEL-49549-7.patch
Normal file
131
SOURCES/glibc-RHEL-49549-7.patch
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
commit 8f36b1469677afe37168f9af1b77402d7a70c673
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Aug 9 15:31:18 2024 +0200
|
||||||
|
|
||||||
|
elf: Signal la_objopen for the proxy link map in dlmopen (bug 31985)
|
||||||
|
|
||||||
|
Previously, the ld.so link map was silently added to the namespace.
|
||||||
|
This change produces an auditing event for it.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/elf/dl-load.c b/elf/dl-load.c
|
||||||
|
index 5c1be6e80cd52e2f..6714807946b60188 100644
|
||||||
|
--- a/elf/dl-load.c
|
||||||
|
+++ b/elf/dl-load.c
|
||||||
|
@@ -928,6 +928,37 @@ _dl_process_pt_gnu_property (struct link_map *l, int fd, const ElfW(Phdr) *ph)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void
|
||||||
|
+_dl_notify_new_object (int mode, Lmid_t nsid, struct link_map *l)
|
||||||
|
+{
|
||||||
|
+ /* Signal that we are going to add new objects. */
|
||||||
|
+ struct r_debug *r = _dl_debug_update (nsid);
|
||||||
|
+ if (r->r_state == RT_CONSISTENT)
|
||||||
|
+ {
|
||||||
|
+#ifdef SHARED
|
||||||
|
+ /* Auditing checkpoint: we are going to add new objects. Since this
|
||||||
|
+ is called after _dl_add_to_namespace_list the namespace is guaranteed
|
||||||
|
+ to not be empty. */
|
||||||
|
+ if ((mode & __RTLD_AUDIT) == 0)
|
||||||
|
+ _dl_audit_activity_nsid (nsid, LA_ACT_ADD);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+ /* Notify the debugger we have added some objects. We need to
|
||||||
|
+ call _dl_debug_initialize in a static program in case dynamic
|
||||||
|
+ linking has not been used before. */
|
||||||
|
+ r->r_state = RT_ADD;
|
||||||
|
+ _dl_debug_state ();
|
||||||
|
+ LIBC_PROBE (map_start, 2, nsid, r);
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ assert (r->r_state == RT_ADD);
|
||||||
|
+
|
||||||
|
+#ifdef SHARED
|
||||||
|
+ /* Auditing checkpoint: we have a new object. */
|
||||||
|
+ if (!GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
|
||||||
|
+ _dl_audit_objopen (l, nsid);
|
||||||
|
+#endif
|
||||||
|
+}
|
||||||
|
|
||||||
|
/* Map in the shared object NAME, actually located in REALNAME, and already
|
||||||
|
opened on FD. */
|
||||||
|
@@ -1024,6 +1055,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||||
|
/* Add the map for the mirrored object to the object list. */
|
||||||
|
_dl_add_to_namespace_list (l, nsid);
|
||||||
|
|
||||||
|
+ _dl_notify_new_object (mode, nsid, l);
|
||||||
|
+
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@@ -1469,33 +1502,7 @@ cannot enable executable stack as shared object requires");
|
||||||
|
if (mode & __RTLD_SPROF)
|
||||||
|
return l;
|
||||||
|
|
||||||
|
- /* Signal that we are going to add new objects. */
|
||||||
|
- struct r_debug *r = _dl_debug_update (nsid);
|
||||||
|
- if (r->r_state == RT_CONSISTENT)
|
||||||
|
- {
|
||||||
|
-#ifdef SHARED
|
||||||
|
- /* Auditing checkpoint: we are going to add new objects. Since this
|
||||||
|
- is called after _dl_add_to_namespace_list the namespace is guaranteed
|
||||||
|
- to not be empty. */
|
||||||
|
- if ((mode & __RTLD_AUDIT) == 0)
|
||||||
|
- _dl_audit_activity_nsid (nsid, LA_ACT_ADD);
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
- /* Notify the debugger we have added some objects. We need to
|
||||||
|
- call _dl_debug_initialize in a static program in case dynamic
|
||||||
|
- linking has not been used before. */
|
||||||
|
- r->r_state = RT_ADD;
|
||||||
|
- _dl_debug_state ();
|
||||||
|
- LIBC_PROBE (map_start, 2, nsid, r);
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- assert (r->r_state == RT_ADD);
|
||||||
|
-
|
||||||
|
-#ifdef SHARED
|
||||||
|
- /* Auditing checkpoint: we have a new object. */
|
||||||
|
- if (!GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
|
||||||
|
- _dl_audit_objopen (l, nsid);
|
||||||
|
-#endif
|
||||||
|
+ _dl_notify_new_object (mode, nsid, l);
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
|
||||||
|
index 6ac1f20af60a2ebb..0c7ca3112381a31e 100644
|
||||||
|
--- a/elf/tst-audit23.c
|
||||||
|
+++ b/elf/tst-audit23.c
|
||||||
|
@@ -17,6 +17,7 @@
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include <array_length.h>
|
||||||
|
+#include <endswith.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <link.h>
|
||||||
|
@@ -106,8 +107,9 @@ do_test (int argc, char *argv[])
|
||||||
|
4. libgcc_s.so (one some architectures, for libsupport)
|
||||||
|
5. tst-audit23mod.so
|
||||||
|
6. libc.so (LM_ID_NEWLM).
|
||||||
|
+ 7. loader (proxy link map in new namespace)
|
||||||
|
vdso (optional and ignored). */
|
||||||
|
- enum { max_objs = 6 };
|
||||||
|
+ enum { max_objs = 7 };
|
||||||
|
struct la_obj_t
|
||||||
|
{
|
||||||
|
char *lname;
|
||||||
|
@@ -236,7 +238,9 @@ do_test (int argc, char *argv[])
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nobjs; i++)
|
||||||
|
{
|
||||||
|
- TEST_COMPARE (objs[i].closed, true);
|
||||||
|
+ /* This subtest currently does not pass because of bug 32065. */
|
||||||
|
+ if (! (endswith (objs[i].lname, LD_SO) && objs[i].lmid != LM_ID_BASE))
|
||||||
|
+ TEST_COMPARE (objs[i].closed, true);
|
||||||
|
free (objs[i].lname);
|
||||||
|
}
|
||||||
|
|
||||||
76
SOURCES/glibc-RHEL-49549-8.patch
Normal file
76
SOURCES/glibc-RHEL-49549-8.patch
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
commit c4b160744cb39eca20dc36b39c7fa6e10352706c
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Fri Aug 9 16:06:40 2024 +0200
|
||||||
|
|
||||||
|
elf: Call la_objclose for proxy link maps in _dl_fini (bug 32065)
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
|
||||||
|
index fa876da0ffa1cf97..133dbac385b34fbb 100644
|
||||||
|
--- a/elf/dl-fini.c
|
||||||
|
+++ b/elf/dl-fini.c
|
||||||
|
@@ -74,6 +74,7 @@ _dl_fini (void)
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
struct link_map *l;
|
||||||
|
+ struct link_map *proxy_link_map = NULL;
|
||||||
|
assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
|
||||||
|
for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
|
||||||
|
/* Do not handle ld.so in secondary namespaces. */
|
||||||
|
@@ -89,6 +90,11 @@ _dl_fini (void)
|
||||||
|
are not dlclose()ed from underneath us. */
|
||||||
|
++l->l_direct_opencount;
|
||||||
|
}
|
||||||
|
+ else
|
||||||
|
+ /* Used below to call la_objclose for the ld.so proxy
|
||||||
|
+ link map. */
|
||||||
|
+ proxy_link_map = l;
|
||||||
|
+
|
||||||
|
assert (ns != LM_ID_BASE || i == nloaded);
|
||||||
|
assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
|
||||||
|
unsigned int nmaps = i;
|
||||||
|
@@ -158,6 +164,9 @@ _dl_fini (void)
|
||||||
|
--l->l_direct_opencount;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (proxy_link_map != NULL)
|
||||||
|
+ _dl_audit_objclose (proxy_link_map);
|
||||||
|
+
|
||||||
|
#ifdef SHARED
|
||||||
|
_dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT);
|
||||||
|
#endif
|
||||||
|
diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
|
||||||
|
index 0c7ca3112381a31e..d5137fd44dacde3c 100644
|
||||||
|
--- a/elf/tst-audit23.c
|
||||||
|
+++ b/elf/tst-audit23.c
|
||||||
|
@@ -236,13 +236,26 @@ do_test (int argc, char *argv[])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Lmid_t lmid_other = LM_ID_NEWLM;
|
||||||
|
+ unsigned int other_namespace_count = 0;
|
||||||
|
for (size_t i = 0; i < nobjs; i++)
|
||||||
|
{
|
||||||
|
- /* This subtest currently does not pass because of bug 32065. */
|
||||||
|
- if (! (endswith (objs[i].lname, LD_SO) && objs[i].lmid != LM_ID_BASE))
|
||||||
|
- TEST_COMPARE (objs[i].closed, true);
|
||||||
|
+ if (objs[i].lmid != LM_ID_BASE)
|
||||||
|
+ {
|
||||||
|
+ if (lmid_other == LM_ID_NEWLM)
|
||||||
|
+ lmid_other = objs[i].lmid;
|
||||||
|
+ TEST_COMPARE (objs[i].lmid, lmid_other);
|
||||||
|
+ ++other_namespace_count;
|
||||||
|
+ if (!(endswith (objs[i].lname, "/" LIBC_SO)
|
||||||
|
+ || endswith (objs[i].lname, "/" LD_SO)))
|
||||||
|
+ FAIL ("unexpected object in secondary namespace: %s",
|
||||||
|
+ objs[i].lname);
|
||||||
|
+ }
|
||||||
|
+ TEST_COMPARE (objs[i].closed, true);
|
||||||
|
free (objs[i].lname);
|
||||||
|
}
|
||||||
|
+ /* Both libc.so and ld.so should be present. */
|
||||||
|
+ TEST_COMPARE (other_namespace_count, 2);
|
||||||
|
|
||||||
|
/* la_activity(LA_ACT_CONSISTENT) should be the last callback received.
|
||||||
|
Since only one link map may be not-CONSISTENT at a time, this also
|
||||||
140
SOURCES/glibc-RHEL-49549-9.patch
Normal file
140
SOURCES/glibc-RHEL-49549-9.patch
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
commit 495b96e064da605630a23092d1e484ade4bdc093
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Tue Sep 3 17:57:46 2024 +0200
|
||||||
|
|
||||||
|
elf: Reorder audit events in dlcose to match _dl_fini (bug 32066)
|
||||||
|
|
||||||
|
This was discovered after extending elf/tst-audit23 to cover
|
||||||
|
dlclose of the dlmopen namespace.
|
||||||
|
|
||||||
|
Auditors already experience the new order during process
|
||||||
|
shutdown (_dl_fini), so no LAV_CURRENT bump or backwards
|
||||||
|
compatibility code seems necessary.
|
||||||
|
|
||||||
|
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
|
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||||
|
index 8a4c3528a124d4e7..236d89f67f3bf410 100644
|
||||||
|
--- a/elf/dl-close.c
|
||||||
|
+++ b/elf/dl-close.c
|
||||||
|
@@ -303,6 +303,12 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SHARED
|
||||||
|
+ /* Auditing checkpoint: we will start deleting objects.
|
||||||
|
+ This is supposed to happen before la_objclose (see _dl_fini),
|
||||||
|
+ but only once per non-recursive dlclose call. */
|
||||||
|
+ if (!unload_any)
|
||||||
|
+ _dl_audit_activity_nsid (nsid, LA_ACT_DELETE);
|
||||||
|
+
|
||||||
|
/* Auditing checkpoint: we remove an object. */
|
||||||
|
_dl_audit_objclose (imap);
|
||||||
|
#endif
|
||||||
|
@@ -463,12 +469,8 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||||
|
if (!unload_any)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
-#ifdef SHARED
|
||||||
|
- /* Auditing checkpoint: we will start deleting objects. */
|
||||||
|
- _dl_audit_activity_nsid (nsid, LA_ACT_DELETE);
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
- /* Notify the debugger we are about to remove some loaded objects. */
|
||||||
|
+ /* Notify the debugger we are about to remove some loaded objects.
|
||||||
|
+ LA_ACT_DELETE has already been signalled above for !unload_any. */
|
||||||
|
struct r_debug *r = _dl_debug_update (nsid);
|
||||||
|
r->r_state = RT_DELETE;
|
||||||
|
_dl_debug_state ();
|
||||||
|
diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
|
||||||
|
index d5137fd44dacde3c..5e3afd397bb2d3d1 100644
|
||||||
|
--- a/elf/tst-audit23.c
|
||||||
|
+++ b/elf/tst-audit23.c
|
||||||
|
@@ -31,16 +31,21 @@
|
||||||
|
#include <support/xstdio.h>
|
||||||
|
#include <support/xdlfcn.h>
|
||||||
|
#include <support/support.h>
|
||||||
|
+#include <support/test-driver.h>
|
||||||
|
|
||||||
|
static int restart;
|
||||||
|
+static int do_dlclose;
|
||||||
|
#define CMDLINE_OPTIONS \
|
||||||
|
- { "restart", no_argument, &restart, 1 },
|
||||||
|
+ { "restart", no_argument, &restart, 1 }, \
|
||||||
|
+ { "dlclose", no_argument, &do_dlclose, 1 }, \
|
||||||
|
|
||||||
|
static int
|
||||||
|
handle_restart (void)
|
||||||
|
{
|
||||||
|
xdlopen ("tst-audit23mod.so", RTLD_NOW);
|
||||||
|
- xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
|
||||||
|
+ void *handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
|
||||||
|
+ if (do_dlclose)
|
||||||
|
+ xdlclose (handle);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@@ -60,8 +65,8 @@ is_vdso (const char *str)
|
||||||
|
|| startswith (str, "linux-vdso");
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int
|
||||||
|
-do_test (int argc, char *argv[])
|
||||||
|
+static void
|
||||||
|
+do_one_test (int argc, char *argv[], bool pass_dlclose_flag)
|
||||||
|
{
|
||||||
|
/* We must have either:
|
||||||
|
- One or four parameters left if called initially:
|
||||||
|
@@ -69,16 +74,15 @@ do_test (int argc, char *argv[])
|
||||||
|
+ "--library-path" optional
|
||||||
|
+ the library path optional
|
||||||
|
+ the application name */
|
||||||
|
- if (restart)
|
||||||
|
- return handle_restart ();
|
||||||
|
-
|
||||||
|
- char *spargv[9];
|
||||||
|
+ char *spargv[10];
|
||||||
|
TEST_VERIFY_EXIT (((argc - 1) + 3) < array_length (spargv));
|
||||||
|
int i = 0;
|
||||||
|
for (; i < argc - 1; i++)
|
||||||
|
spargv[i] = argv[i + 1];
|
||||||
|
spargv[i++] = (char *) "--direct";
|
||||||
|
spargv[i++] = (char *) "--restart";
|
||||||
|
+ if (pass_dlclose_flag)
|
||||||
|
+ spargv[i++] = (char *) "--dlclose";
|
||||||
|
spargv[i] = NULL;
|
||||||
|
|
||||||
|
setenv ("LD_AUDIT", "tst-auditmod23.so", 0);
|
||||||
|
@@ -146,8 +150,14 @@ do_test (int argc, char *argv[])
|
||||||
|
|
||||||
|
/* The cookie identifies the object at the head of the link map,
|
||||||
|
so we only add a new namespace if it changes from the previous
|
||||||
|
- one. This works since dlmopen is the last in the test body. */
|
||||||
|
- if (cookie != last_act_cookie && last_act_cookie != -1)
|
||||||
|
+ one. This works since dlmopen is the last in the test body.
|
||||||
|
+
|
||||||
|
+ Currently, this does not work as expected because there
|
||||||
|
+ is no head link map if a namespace is completely deleted.
|
||||||
|
+ No LA_ACT_CONSISTENT event is generated in that case.
|
||||||
|
+ See the comment in _dl_audit_activity_nsid and bug 32068. */
|
||||||
|
+ if (cookie != last_act_cookie && last_act_cookie != -1
|
||||||
|
+ && !pass_dlclose_flag)
|
||||||
|
TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
|
||||||
|
|
||||||
|
if (this_act == LA_ACT_ADD && acts[nacts] != cookie)
|
||||||
|
@@ -265,7 +275,16 @@ do_test (int argc, char *argv[])
|
||||||
|
|
||||||
|
free (buffer);
|
||||||
|
xfclose (out);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (int argc, char *argv[])
|
||||||
|
+{
|
||||||
|
+ if (restart)
|
||||||
|
+ return handle_restart ();
|
||||||
|
|
||||||
|
+ do_one_test (argc, argv, false);
|
||||||
|
+ do_one_test (argc, argv, true);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
647
SOURCES/glibc-RHEL-50086-1.patch
Normal file
647
SOURCES/glibc-RHEL-50086-1.patch
Normal file
@ -0,0 +1,647 @@
|
|||||||
|
commit 4f6dae219578d6df475864e273da40bde9d30806
|
||||||
|
Author: Stefan Liebler <stli@linux.ibm.com>
|
||||||
|
Date: Tue Apr 29 13:28:58 2025 +0200
|
||||||
|
|
||||||
|
S390: Add new s390 platform z17.
|
||||||
|
|
||||||
|
The glibc-hwcaps subdirectories are extended by "z17". Libraries are loaded if
|
||||||
|
the z17 facility bits are active:
|
||||||
|
- Miscellaneous-instruction-extensions facility 4
|
||||||
|
- Vector-enhancements-facility 3
|
||||||
|
- Vector-Packed-Decimal-Enhancement Facility 3
|
||||||
|
- CPU: Concurrent-Functions Facility
|
||||||
|
|
||||||
|
tst-glibc-hwcaps.c is extended in order to test z17 via new marker6.
|
||||||
|
In case of running on a z17 with a kernel not recognizing z17 yet,
|
||||||
|
AT_PLATFORM will be z900 but vector-bit in AT_HWCAP is set. This situation
|
||||||
|
is now recognized and this testcase does not fail.
|
||||||
|
|
||||||
|
A fatal glibc error is dumped if glibc was build with architecture
|
||||||
|
level set for z17, but run on an older machine (See dl-hwcap-check.h).
|
||||||
|
Note, you might get an SIGILL before this check if you don't use:
|
||||||
|
configure --with-rtld-early-cflags=-march=<older-machine>
|
||||||
|
|
||||||
|
ld.so --list-diagnostics now also dumps information about s390.cpu_features.
|
||||||
|
|
||||||
|
Independent from z17, the s390x kernel won't introduce new HWCAP-Bits if there
|
||||||
|
is no special handling needed in kernel itself. For z17, we don't have new
|
||||||
|
HWCAP flags, but have to check the facility bits retrieved by
|
||||||
|
stfle-instruction.
|
||||||
|
|
||||||
|
Instead of storing all the stfle-bits (currently four 64bit values) in the
|
||||||
|
cpu_features struct, we now only store those bits, which are needed within
|
||||||
|
glibc itself. Note that we have this list twice, one with original values and
|
||||||
|
the other one which can be filtered with GLIBC_TUNABLES=glibc.cpu.hwcaps.
|
||||||
|
Those new fields are stored in so far reserved space in cpu_features struct.
|
||||||
|
Thus processes started in between the update of glibc package and we e.g. have
|
||||||
|
a new ld.so and an old libc.so, won't crash. The glibc internal ifunc-resolvers
|
||||||
|
would not select the best optimized variant.
|
||||||
|
|
||||||
|
The users of stfle-bits are also updated:
|
||||||
|
- parsing of GLIBC_TUNABLES=glibc.cpu.hwcaps
|
||||||
|
- glibc internal ifunc-resolvers
|
||||||
|
- __libc_ifunc_impl_list
|
||||||
|
- sysconf
|
||||||
|
|
||||||
|
Note: Conflicts were resolved by Stefan Liebler.
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
elf/Makefile (fixup context)
|
||||||
|
sysdeps/s390/cpu-features.c (partial re-implement downstream)
|
||||||
|
sysdeps/s390/multiarch/ifunc-impl-list.c (fixup context)
|
||||||
|
sysdeps/s390/s390-64/dl-hwcaps-subdirs.c (fixup context)
|
||||||
|
|
||||||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||||||
|
index ba11f3a8b81e7218..84151f2e59704a43 100644
|
||||||
|
--- a/elf/Makefile
|
||||||
|
+++ b/elf/Makefile
|
||||||
|
@@ -667,6 +667,12 @@ modules-names = \
|
||||||
|
libmarkermod5-3 \
|
||||||
|
libmarkermod5-4 \
|
||||||
|
libmarkermod5-5 \
|
||||||
|
+ libmarkermod6-1 \
|
||||||
|
+ libmarkermod6-2 \
|
||||||
|
+ libmarkermod6-3 \
|
||||||
|
+ libmarkermod6-4 \
|
||||||
|
+ libmarkermod6-5 \
|
||||||
|
+ libmarkermod6-6 \
|
||||||
|
ltglobmod1 \
|
||||||
|
ltglobmod2 \
|
||||||
|
neededobj1 \
|
||||||
|
@@ -2624,6 +2630,7 @@ LDFLAGS-libmarkermod2-1.so += -Wl,-soname,libmarkermod2.so
|
||||||
|
LDFLAGS-libmarkermod3-1.so += -Wl,-soname,libmarkermod3.so
|
||||||
|
LDFLAGS-libmarkermod4-1.so += -Wl,-soname,libmarkermod4.so
|
||||||
|
LDFLAGS-libmarkermod5-1.so += -Wl,-soname,libmarkermod5.so
|
||||||
|
+LDFLAGS-libmarkermod6-1.so += -Wl,-soname,libmarkermod6.so
|
||||||
|
$(objpfx)libmarkermod%.os : markermodMARKER-VALUE.c
|
||||||
|
$(compile-command.c) \
|
||||||
|
-DMARKER=marker$(firstword $(subst -, ,$*)) \
|
||||||
|
@@ -2638,6 +2645,8 @@ $(objpfx)libmarkermod4.so: $(objpfx)libmarkermod4-1.so
|
||||||
|
cp $< $@
|
||||||
|
$(objpfx)libmarkermod5.so: $(objpfx)libmarkermod5-1.so
|
||||||
|
cp $< $@
|
||||||
|
+$(objpfx)libmarkermod6.so: $(objpfx)libmarkermod6-1.so
|
||||||
|
+ cp $< $@
|
||||||
|
|
||||||
|
# tst-glibc-hwcaps-prepend checks that --glibc-hwcaps-prepend is
|
||||||
|
# preferred over auto-detected subdirectories.
|
||||||
|
diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script
|
||||||
|
index d58fc8c5de3c5198..af89e9c6f811f483 100644
|
||||||
|
--- a/elf/tst-glibc-hwcaps-cache.script
|
||||||
|
+++ b/elf/tst-glibc-hwcaps-cache.script
|
||||||
|
@@ -5,6 +5,7 @@ cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so
|
||||||
|
cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so
|
||||||
|
cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so
|
||||||
|
cp $B/elf/libmarkermod5-1.so $L/libmarkermod5.so
|
||||||
|
+cp $B/elf/libmarkermod6-1.so $L/libmarkermod6.so
|
||||||
|
|
||||||
|
mkdirp 0770 $L/glibc-hwcaps/power9
|
||||||
|
cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/power9/libmarkermod2.so
|
||||||
|
@@ -26,6 +27,12 @@ cp $B/elf/libmarkermod5-2.so $L/glibc-hwcaps/z13/libmarkermod5.so
|
||||||
|
cp $B/elf/libmarkermod5-3.so $L/glibc-hwcaps/z14/libmarkermod5.so
|
||||||
|
cp $B/elf/libmarkermod5-4.so $L/glibc-hwcaps/z15/libmarkermod5.so
|
||||||
|
cp $B/elf/libmarkermod5-5.so $L/glibc-hwcaps/z16/libmarkermod5.so
|
||||||
|
+mkdirp 0770 $L/glibc-hwcaps/z17
|
||||||
|
+cp $B/elf/libmarkermod6-2.so $L/glibc-hwcaps/z13/libmarkermod6.so
|
||||||
|
+cp $B/elf/libmarkermod6-3.so $L/glibc-hwcaps/z14/libmarkermod6.so
|
||||||
|
+cp $B/elf/libmarkermod6-4.so $L/glibc-hwcaps/z15/libmarkermod6.so
|
||||||
|
+cp $B/elf/libmarkermod6-5.so $L/glibc-hwcaps/z16/libmarkermod6.so
|
||||||
|
+cp $B/elf/libmarkermod6-6.so $L/glibc-hwcaps/z17/libmarkermod6.so
|
||||||
|
|
||||||
|
mkdirp 0770 $L/glibc-hwcaps/x86-64-v2
|
||||||
|
cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so
|
||||||
|
diff --git a/sysdeps/s390/cpu-features.c b/sysdeps/s390/cpu-features.c
|
||||||
|
index afeb9b56382efa96..e9e7e726b71fb09a 100644
|
||||||
|
--- a/sysdeps/s390/cpu-features.c
|
||||||
|
+++ b/sysdeps/s390/cpu-features.c
|
||||||
|
@@ -28,7 +28,7 @@ extern __typeof (memcmp) MEMCMP_DEFAULT;
|
||||||
|
#if HAVE_TUNABLES
|
||||||
|
# define S390_COPY_CPU_FEATURES(SRC_PTR, DEST_PTR) \
|
||||||
|
(DEST_PTR)->hwcap = (SRC_PTR)->hwcap; \
|
||||||
|
- (DEST_PTR)->stfle_bits[0] = (SRC_PTR)->stfle_bits[0];
|
||||||
|
+ (DEST_PTR)->stfle_filtered = (SRC_PTR)->stfle_filtered;
|
||||||
|
|
||||||
|
static void
|
||||||
|
TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
|
||||||
|
@@ -100,7 +100,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
|
||||||
|
disable = true;
|
||||||
|
hwcap_mask = HWCAP_S390_VXRS | HWCAP_S390_VXRS_EXT
|
||||||
|
| HWCAP_S390_VXRS_EXT2;
|
||||||
|
- stfle_bits0_mask = S390_STFLE_MASK_ARCH13_MIE3;
|
||||||
|
+ stfle_bits0_mask = S390_STFLE_BIT61_ARCH13_MIE3;
|
||||||
|
}
|
||||||
|
else if ((feature_len == 3 && *feature == 'z'
|
||||||
|
&& MEMCMP_DEFAULT (feature, "z13", 3) == 0)
|
||||||
|
@@ -110,7 +110,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
|
||||||
|
reset_features = true;
|
||||||
|
disable = true;
|
||||||
|
hwcap_mask = HWCAP_S390_VXRS_EXT | HWCAP_S390_VXRS_EXT2;
|
||||||
|
- stfle_bits0_mask = S390_STFLE_MASK_ARCH13_MIE3;
|
||||||
|
+ stfle_bits0_mask = S390_STFLE_BIT61_ARCH13_MIE3;
|
||||||
|
}
|
||||||
|
else if ((feature_len == 3 && *feature == 'z'
|
||||||
|
&& MEMCMP_DEFAULT (feature, "z14", 3) == 0)
|
||||||
|
@@ -120,14 +120,16 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
|
||||||
|
reset_features = true;
|
||||||
|
disable = true;
|
||||||
|
hwcap_mask = HWCAP_S390_VXRS_EXT2;
|
||||||
|
- stfle_bits0_mask = S390_STFLE_MASK_ARCH13_MIE3;
|
||||||
|
+ stfle_bits0_mask = S390_STFLE_BIT61_ARCH13_MIE3;
|
||||||
|
}
|
||||||
|
else if ((feature_len == 3 && *feature == 'z'
|
||||||
|
&& (MEMCMP_DEFAULT (feature, "z15", 3) == 0
|
||||||
|
- || MEMCMP_DEFAULT (feature, "z16", 3) == 0))
|
||||||
|
+ || MEMCMP_DEFAULT (feature, "z16", 3) == 0
|
||||||
|
+ || MEMCMP_DEFAULT (feature, "z17", 3) == 0))
|
||||||
|
|| (feature_len == 6
|
||||||
|
&& (MEMCMP_DEFAULT (feature, "arch13", 6) == 0
|
||||||
|
- || MEMCMP_DEFAULT (feature, "arch14", 6) == 0)))
|
||||||
|
+ || MEMCMP_DEFAULT (feature, "arch14", 6) == 0
|
||||||
|
+ || MEMCMP_DEFAULT (feature, "arch15", 6) == 0)))
|
||||||
|
{
|
||||||
|
/* For z15 or newer we don't have to disable something,
|
||||||
|
but we have to reset to the original values. */
|
||||||
|
@@ -165,7 +167,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
|
||||||
|
if (feature_len == 10
|
||||||
|
&& MEMCMP_DEFAULT (feature, "STFLE_MIE3", 10) == 0)
|
||||||
|
{
|
||||||
|
- stfle_bits0_mask = S390_STFLE_MASK_ARCH13_MIE3;
|
||||||
|
+ stfle_bits0_mask = S390_STFLE_BIT61_ARCH13_MIE3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -186,9 +188,9 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
|
||||||
|
if (stfle_bits0_mask != 0ULL)
|
||||||
|
{
|
||||||
|
if (disable)
|
||||||
|
- cpu_features_curr.stfle_bits[0] &= ~stfle_bits0_mask;
|
||||||
|
+ cpu_features_curr.stfle_filtered &= ~stfle_bits0_mask;
|
||||||
|
else
|
||||||
|
- cpu_features_curr.stfle_bits[0] |= stfle_bits0_mask;
|
||||||
|
+ cpu_features_curr.stfle_filtered |= stfle_bits0_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Jump over current token ... */
|
||||||
|
@@ -202,14 +204,18 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
|
||||||
|
/* Copy back the features after checking that no unsupported features were
|
||||||
|
enabled by user. */
|
||||||
|
cpu_features->hwcap = cpu_features_curr.hwcap & cpu_features_orig.hwcap;
|
||||||
|
- cpu_features->stfle_bits[0] = cpu_features_curr.stfle_bits[0]
|
||||||
|
- & cpu_features_orig.stfle_bits[0];
|
||||||
|
+ cpu_features->stfle_filtered = cpu_features_curr.stfle_filtered
|
||||||
|
+ & cpu_features_orig.stfle_filtered;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
-init_cpu_features (struct cpu_features *cpu_features)
|
||||||
|
+init_cpu_features_no_tunables (struct cpu_features *cpu_features)
|
||||||
|
{
|
||||||
|
+ /* Only initialize once. */
|
||||||
|
+ if (cpu_features->hwcap != 0)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
/* Fill cpu_features as passed by kernel and machine. */
|
||||||
|
cpu_features->hwcap = GLRO(dl_hwcap);
|
||||||
|
|
||||||
|
@@ -218,20 +224,57 @@ init_cpu_features (struct cpu_features *cpu_features)
|
||||||
|
&& (cpu_features->hwcap & HWCAP_S390_ZARCH)
|
||||||
|
&& (cpu_features->hwcap & HWCAP_S390_HIGH_GPRS)))
|
||||||
|
{
|
||||||
|
- register unsigned long reg0 __asm__("0") = 0;
|
||||||
|
+ unsigned long long stfle_bits[4] = { 0 };
|
||||||
|
+ register unsigned long reg0 __asm__("0") = 3;
|
||||||
|
__asm__ __volatile__(".machine push" "\n\t"
|
||||||
|
".machine \"z9-109\"" "\n\t"
|
||||||
|
".machinemode \"zarch_nohighgprs\"\n\t"
|
||||||
|
"stfle %0" "\n\t"
|
||||||
|
".machine pop" "\n"
|
||||||
|
- : "=QS" (cpu_features->stfle_bits[0]),
|
||||||
|
+ : "=QS" (stfle_bits[0]),
|
||||||
|
"+d" (reg0)
|
||||||
|
: : "cc");
|
||||||
|
+
|
||||||
|
+ unsigned long long internal_stfle_bits = 0;
|
||||||
|
+
|
||||||
|
+ /* Facility bit 34: z10: General instructions extension. */
|
||||||
|
+ if ((stfle_bits[0] & (1ULL << (63 - 34))) != 0)
|
||||||
|
+ internal_stfle_bits |= S390_STFLE_BIT34_Z10;
|
||||||
|
+
|
||||||
|
+ /* Facility bit 45: z196: Distinct operands, popcount, ... */
|
||||||
|
+ if ((stfle_bits[0] & (1ULL << (63 - 45))) != 0)
|
||||||
|
+ internal_stfle_bits |= S390_STFLE_BIT45_Z196;
|
||||||
|
+
|
||||||
|
+ /* Facility bit 61: arch13/z15: Miscellaneous-Instruction-Extensions
|
||||||
|
+ Facility 3, e.g. mvcrl. */
|
||||||
|
+ if ((stfle_bits[0] & (1ULL << (63 - 61))) != 0)
|
||||||
|
+ internal_stfle_bits |= S390_STFLE_BIT61_ARCH13_MIE3;
|
||||||
|
+
|
||||||
|
+ /* Facility bit 84: arch15/z17: Miscellaneous-instruction-extensions 4 */
|
||||||
|
+ if ((stfle_bits[1] & (1ULL << (127 - 84))) != 0)
|
||||||
|
+ internal_stfle_bits |= S390_STFLE_BIT84_ARCH15_MIE4;
|
||||||
|
+
|
||||||
|
+ /* Facility bit 198: arch15/z17: Vector-enhancements-facility 3 */
|
||||||
|
+ if ((stfle_bits[3] & (1ULL << (255 - 198))) != 0)
|
||||||
|
+ internal_stfle_bits |= S390_STFLE_BIT198_ARCH15_VXRS_EXT3;
|
||||||
|
+
|
||||||
|
+ /* Facility bit 199: arch15/z17: Vector-Packed-Decimal-Enhancement 3 */
|
||||||
|
+ if ((stfle_bits[3] & (1ULL << (255 - 199))) != 0)
|
||||||
|
+ internal_stfle_bits |= S390_STFLE_BIT199_ARCH15_VXRS_PDE3;
|
||||||
|
+
|
||||||
|
+ /* Facility bit 201: arch15/z17: CPU: Concurrent-Functions Facility */
|
||||||
|
+ if ((stfle_bits[3] & (1ULL << (255 - 201))) != 0)
|
||||||
|
+ internal_stfle_bits |= S390_STFLE_BIT201_ARCH15_CON;
|
||||||
|
+
|
||||||
|
+ cpu_features->stfle_orig = internal_stfle_bits;
|
||||||
|
+ cpu_features->stfle_filtered = internal_stfle_bits;
|
||||||
|
}
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
- cpu_features->stfle_bits[0] = 0ULL;
|
||||||
|
- }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void
|
||||||
|
+init_cpu_features (struct cpu_features *cpu_features)
|
||||||
|
+{
|
||||||
|
+ init_cpu_features_no_tunables (cpu_features);
|
||||||
|
|
||||||
|
#if HAVE_TUNABLES
|
||||||
|
TUNABLE_GET (glibc, cpu, hwcaps, tunable_val_t *, TUNABLE_CALLBACK (set_hwcaps));
|
||||||
|
diff --git a/sysdeps/s390/cpu-features.h b/sysdeps/s390/cpu-features.h
|
||||||
|
index 5e6b58f7c5bb07e4..f98654a7223cfc5b 100644
|
||||||
|
--- a/sysdeps/s390/cpu-features.h
|
||||||
|
+++ b/sysdeps/s390/cpu-features.h
|
||||||
|
@@ -18,29 +18,58 @@
|
||||||
|
#ifndef __CPU_FEATURES_S390X_H
|
||||||
|
# define __CPU_FEATURES_S390X_H
|
||||||
|
|
||||||
|
-#define S390_STFLE_BITS_Z10 34 /* General instructions extension */
|
||||||
|
-#define S390_STFLE_BITS_Z196 45 /* Distinct operands, pop ... */
|
||||||
|
-#define S390_STFLE_BITS_ARCH13_MIE3 61 /* Miscellaneous-Instruction-Extensions
|
||||||
|
- Facility 3, e.g. mvcrl. */
|
||||||
|
+/* The following stfle bit definitions are intended to be used for the
|
||||||
|
+ glibc internal stfle_orig and stfle_filtered fields in cpu_features
|
||||||
|
+ struct. They can't be used on the double words retrieved by the
|
||||||
|
+ stfle-instruction. */
|
||||||
|
|
||||||
|
-#define S390_STFLE_MASK_ARCH13_MIE3 (1ULL << (63 - S390_STFLE_BITS_ARCH13_MIE3))
|
||||||
|
+/* Facility bit 34: z10: General instructions extension. */
|
||||||
|
+#define S390_STFLE_BIT34_Z10 (1ULL << 0)
|
||||||
|
|
||||||
|
+/* Facility bit 45: z196: Distinct operands, popcount, ... */
|
||||||
|
+#define S390_STFLE_BIT45_Z196 (1ULL << 1)
|
||||||
|
|
||||||
|
-#define S390_IS_ARCH13_MIE3(STFLE_BITS_ARRAY) \
|
||||||
|
- (((STFLE_BITS_ARRAY)[0] & S390_STFLE_MASK_ARCH13_MIE3) != 0)
|
||||||
|
+/* Facility bit 61: arch13/z15: Miscellaneous-Instruction-Extensions
|
||||||
|
+ Facility 3, e.g. mvcrl. */
|
||||||
|
+#define S390_STFLE_BIT61_ARCH13_MIE3 (1ULL << 2)
|
||||||
|
|
||||||
|
-#define S390_IS_Z196(STFLE_BITS_ARRAY) \
|
||||||
|
- (((STFLE_BITS_ARRAY)[0] & (1ULL << (63 - S390_STFLE_BITS_Z196))) != 0)
|
||||||
|
+/* Facility bit 84: arch15/z17: Miscellaneous-instruction-extensions
|
||||||
|
+ facility 4 */
|
||||||
|
+#define S390_STFLE_BIT84_ARCH15_MIE4 (1ULL << 3)
|
||||||
|
|
||||||
|
-#define S390_IS_Z10(STFLE_BITS_ARRAY) \
|
||||||
|
- (((STFLE_BITS_ARRAY)[0] & (1ULL << (63 - S390_STFLE_BITS_Z10))) != 0)
|
||||||
|
+/* Facility bit 198: arch15/z17: Vector-enhancements-facility 3 */
|
||||||
|
+#define S390_STFLE_BIT198_ARCH15_VXRS_EXT3 (1ULL << 4)
|
||||||
|
+
|
||||||
|
+/* Facility bit 199: arch15/z17: Vector-Packed-Decimal-Enhancement
|
||||||
|
+ Facility 3 */
|
||||||
|
+#define S390_STFLE_BIT199_ARCH15_VXRS_PDE3 (1ULL << 5)
|
||||||
|
+
|
||||||
|
+/* Facility bit 201: arch15/z17: CPU: Concurrent-Functions Facility */
|
||||||
|
+#define S390_STFLE_BIT201_ARCH15_CON (1ULL << 6)
|
||||||
|
+
|
||||||
|
+#define S390_IS_ARCH15(STFLE_BITS) \
|
||||||
|
+ ((((STFLE_BITS) & S390_STFLE_BIT84_ARCH15_MIE4) != 0) \
|
||||||
|
+ && (((STFLE_BITS) & S390_STFLE_BIT198_ARCH15_VXRS_EXT3) != 0) \
|
||||||
|
+ && (((STFLE_BITS) & S390_STFLE_BIT199_ARCH15_VXRS_PDE3) != 0) \
|
||||||
|
+ && (((STFLE_BITS) & S390_STFLE_BIT201_ARCH15_CON) != 0))
|
||||||
|
+
|
||||||
|
+#define S390_IS_ARCH13_MIE3(STFLE_BITS) \
|
||||||
|
+ (((STFLE_BITS) & S390_STFLE_BIT61_ARCH13_MIE3) != 0)
|
||||||
|
+
|
||||||
|
+#define S390_IS_Z196(STFLE_BITS) \
|
||||||
|
+ (((STFLE_BITS) & S390_STFLE_BIT45_Z196) != 0)
|
||||||
|
+
|
||||||
|
+#define S390_IS_Z10(STFLE_BITS) \
|
||||||
|
+ (((STFLE_BITS) & S390_STFLE_BIT34_Z10) != 0)
|
||||||
|
|
||||||
|
struct cpu_features
|
||||||
|
{
|
||||||
|
unsigned long int hwcap;
|
||||||
|
unsigned long int __reserved_hwcap2;
|
||||||
|
- unsigned long long stfle_bits[3];
|
||||||
|
- unsigned long long __reserved[11];
|
||||||
|
+ unsigned long long __reserved;
|
||||||
|
+ unsigned long long stfle_orig;
|
||||||
|
+ unsigned long long stfle_filtered;
|
||||||
|
+ unsigned long long __reserved2[11];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __CPU_FEATURES_S390X_H */
|
||||||
|
diff --git a/sysdeps/s390/dl-diagnostics-cpu.c b/sysdeps/s390/dl-diagnostics-cpu.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..426af2df7a34b55e
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/sysdeps/s390/dl-diagnostics-cpu.c
|
||||||
|
@@ -0,0 +1,37 @@
|
||||||
|
+/* Print CPU diagnostics data in ld.so. s390 version.
|
||||||
|
+ 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 <dl-diagnostics.h>
|
||||||
|
+#include <ldsodefs.h>
|
||||||
|
+#include <cpu-features.h>
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+print_cpu_features_value (const char *label, uint64_t value)
|
||||||
|
+{
|
||||||
|
+ _dl_printf ("s390.cpu_features.");
|
||||||
|
+ _dl_diagnostics_print_labeled_value (label, value);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+_dl_diagnostics_cpu (void)
|
||||||
|
+{
|
||||||
|
+ const struct cpu_features *cpu_features = &GLRO(dl_s390_cpu_features);
|
||||||
|
+ print_cpu_features_value ("hwcap", cpu_features->hwcap);
|
||||||
|
+ print_cpu_features_value ("stfle_orig", cpu_features->stfle_orig);
|
||||||
|
+ print_cpu_features_value ("stfle_filtered", cpu_features->stfle_filtered);
|
||||||
|
+}
|
||||||
|
diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c
|
||||||
|
index af2c75f5df7c7e1d..4c5fdf6069c4027b 100644
|
||||||
|
--- a/sysdeps/s390/multiarch/ifunc-impl-list.c
|
||||||
|
+++ b/sysdeps/s390/multiarch/ifunc-impl-list.c
|
||||||
|
@@ -83,9 +83,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||||||
|
|
||||||
|
/* Get hardware information. */
|
||||||
|
const struct cpu_features *features = &GLRO(dl_s390_cpu_features);
|
||||||
|
- unsigned long int dl_hwcap = features->hwcap;
|
||||||
|
- const unsigned long long * __attribute__((unused)) stfle_bits
|
||||||
|
- = features->stfle_bits;
|
||||||
|
+ unsigned long int dl_hwcap __attribute__ ((unused)) = features->hwcap;
|
||||||
|
+ const unsigned long long __attribute__((unused)) stfle_bits
|
||||||
|
+ = features->stfle_filtered;
|
||||||
|
|
||||||
|
#if HAVE_MEMSET_IFUNC
|
||||||
|
IFUNC_IMPL (i, name, memset,
|
||||||
|
diff --git a/sysdeps/s390/multiarch/ifunc-resolve.h b/sysdeps/s390/multiarch/ifunc-resolve.h
|
||||||
|
index c22d59d2a341fff7..16b358ec2e895a4c 100644
|
||||||
|
--- a/sysdeps/s390/multiarch/ifunc-resolve.h
|
||||||
|
+++ b/sysdeps/s390/multiarch/ifunc-resolve.h
|
||||||
|
@@ -22,7 +22,7 @@
|
||||||
|
#include <cpu-features.h>
|
||||||
|
|
||||||
|
#define s390_libc_ifunc_expr_stfle_init() \
|
||||||
|
- const unsigned long long *stfle_bits = features->stfle_bits;
|
||||||
|
+ const unsigned long long stfle_bits = features->stfle_filtered;
|
||||||
|
|
||||||
|
#define s390_libc_ifunc_expr_init() \
|
||||||
|
const struct cpu_features *features = &GLRO(dl_s390_cpu_features); \
|
||||||
|
diff --git a/sysdeps/s390/s390-64/Makefile b/sysdeps/s390/s390-64/Makefile
|
||||||
|
index 66ed844e68df5159..991025cd2a97c203 100644
|
||||||
|
--- a/sysdeps/s390/s390-64/Makefile
|
||||||
|
+++ b/sysdeps/s390/s390-64/Makefile
|
||||||
|
@@ -11,7 +11,8 @@ $(objpfx)tst-glibc-hwcaps: \
|
||||||
|
$(objpfx)libmarkermod2-1.so \
|
||||||
|
$(objpfx)libmarkermod3-1.so \
|
||||||
|
$(objpfx)libmarkermod4-1.so \
|
||||||
|
- $(objpfx)libmarkermod5-1.so
|
||||||
|
+ $(objpfx)libmarkermod5-1.so \
|
||||||
|
+ $(objpfx)libmarkermod6-1.so
|
||||||
|
$(objpfx)tst-glibc-hwcaps.out: \
|
||||||
|
$(objpfx)libmarkermod2.so \
|
||||||
|
$(objpfx)glibc-hwcaps/z13/libmarkermod2.so \
|
||||||
|
@@ -26,7 +27,14 @@ $(objpfx)tst-glibc-hwcaps.out: \
|
||||||
|
$(objpfx)glibc-hwcaps/z13/libmarkermod5.so \
|
||||||
|
$(objpfx)glibc-hwcaps/z14/libmarkermod5.so \
|
||||||
|
$(objpfx)glibc-hwcaps/z15/libmarkermod5.so \
|
||||||
|
- $(objpfx)glibc-hwcaps/z16/libmarkermod5.so
|
||||||
|
+ $(objpfx)glibc-hwcaps/z16/libmarkermod5.so \
|
||||||
|
+ $(objpfx)libmarkermod6.so \
|
||||||
|
+ $(objpfx)glibc-hwcaps/z13/libmarkermod6.so \
|
||||||
|
+ $(objpfx)glibc-hwcaps/z14/libmarkermod6.so \
|
||||||
|
+ $(objpfx)glibc-hwcaps/z15/libmarkermod6.so \
|
||||||
|
+ $(objpfx)glibc-hwcaps/z16/libmarkermod6.so \
|
||||||
|
+ $(objpfx)glibc-hwcaps/z17/libmarkermod6.so
|
||||||
|
+
|
||||||
|
|
||||||
|
$(objpfx)glibc-hwcaps/z13/libmarkermod2.so: $(objpfx)libmarkermod2-2.so
|
||||||
|
$(make-target-directory)
|
||||||
|
@@ -58,6 +66,21 @@ $(objpfx)glibc-hwcaps/z15/libmarkermod5.so: $(objpfx)libmarkermod5-4.so
|
||||||
|
$(objpfx)glibc-hwcaps/z16/libmarkermod5.so: $(objpfx)libmarkermod5-5.so
|
||||||
|
$(make-target-directory)
|
||||||
|
cp $< $@
|
||||||
|
+$(objpfx)glibc-hwcaps/z13/libmarkermod6.so: $(objpfx)libmarkermod6-2.so
|
||||||
|
+ $(make-target-directory)
|
||||||
|
+ cp $< $@
|
||||||
|
+$(objpfx)glibc-hwcaps/z14/libmarkermod6.so: $(objpfx)libmarkermod6-3.so
|
||||||
|
+ $(make-target-directory)
|
||||||
|
+ cp $< $@
|
||||||
|
+$(objpfx)glibc-hwcaps/z15/libmarkermod6.so: $(objpfx)libmarkermod6-4.so
|
||||||
|
+ $(make-target-directory)
|
||||||
|
+ cp $< $@
|
||||||
|
+$(objpfx)glibc-hwcaps/z16/libmarkermod6.so: $(objpfx)libmarkermod6-5.so
|
||||||
|
+ $(make-target-directory)
|
||||||
|
+ cp $< $@
|
||||||
|
+$(objpfx)glibc-hwcaps/z17/libmarkermod6.so: $(objpfx)libmarkermod6-6.so
|
||||||
|
+ $(make-target-directory)
|
||||||
|
+ cp $< $@
|
||||||
|
|
||||||
|
|
||||||
|
ifeq (no,$(build-hardcoded-path-in-tests))
|
||||||
|
diff --git a/sysdeps/s390/s390-64/dl-hwcap-check.h b/sysdeps/s390/s390-64/dl-hwcap-check.h
|
||||||
|
index 52c609571b32f4ab..d52444419b9a54c1 100644
|
||||||
|
--- a/sysdeps/s390/s390-64/dl-hwcap-check.h
|
||||||
|
+++ b/sysdeps/s390/s390-64/dl-hwcap-check.h
|
||||||
|
@@ -25,8 +25,23 @@
|
||||||
|
static inline void
|
||||||
|
dl_hwcap_check (void)
|
||||||
|
{
|
||||||
|
-#if defined __ARCH__
|
||||||
|
-# if GCCMACRO__ARCH__ >= 14
|
||||||
|
+ /* Note: The s390x kernel won't introduce new HWCAP-Bits if there is
|
||||||
|
+ no special handling needed in kernel itself. Thus we have have
|
||||||
|
+ to check the facility-list retrieved with the stfle instruction.
|
||||||
|
+ We already have a common storage of this list in cpu-features.c.
|
||||||
|
+ This dl-hwcap-check.h file is included in
|
||||||
|
+ sysdeps/unix/sysv/linux/dl-sysdep.c, where also dl-machine.h and
|
||||||
|
+ cpu-features.c is included. Therefore we don't have a special
|
||||||
|
+ include here. */
|
||||||
|
+
|
||||||
|
+#if defined GCCMACRO__ARCH__
|
||||||
|
+# if GCCMACRO__ARCH__ >= 15
|
||||||
|
+ init_cpu_features_no_tunables (&GLRO(dl_s390_cpu_features));
|
||||||
|
+ if (!(S390_IS_ARCH15 (GLRO(dl_s390_cpu_features).stfle_orig)))
|
||||||
|
+ _dl_fatal_printf ("\
|
||||||
|
+Fatal glibc error: CPU lacks VXRS_EXT3/VXRS_PDE3/MIE4/Concurrent-functions \
|
||||||
|
+support (z17 or later required)\n");
|
||||||
|
+# elif GCCMACRO__ARCH__ >= 14
|
||||||
|
if (!(GLRO(dl_hwcap) & HWCAP_S390_VXRS_PDE2))
|
||||||
|
_dl_fatal_printf ("\
|
||||||
|
Fatal glibc error: CPU lacks VXRS_PDE2 support (z16 or later required)\n");
|
||||||
|
@@ -39,7 +54,7 @@ Fatal glibc error: CPU lacks VXRS_EXT2 support (z15 or later required)\n");
|
||||||
|
_dl_fatal_printf ("\
|
||||||
|
Fatal glibc error: CPU lacks VXE support (z14 or later required)\n");
|
||||||
|
# endif
|
||||||
|
-#endif /* __ARCH__ */
|
||||||
|
+#endif /* GCCMACRO__ARCH__ */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _DL_HWCAP_CHECK_H */
|
||||||
|
diff --git a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c
|
||||||
|
index 187d732d560c4a62..0e4aa067c0b87439 100644
|
||||||
|
--- a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c
|
||||||
|
+++ b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c
|
||||||
|
@@ -18,9 +18,10 @@
|
||||||
|
|
||||||
|
#include <dl-hwcaps.h>
|
||||||
|
#include <ldsodefs.h>
|
||||||
|
+#include <cpu-features.h>
|
||||||
|
|
||||||
|
-const char _dl_hwcaps_subdirs[] = "z16:z15:z14:z13";
|
||||||
|
-enum { subdirs_count = 4 }; /* Number of components in _dl_hwcaps_subdirs. */
|
||||||
|
+const char _dl_hwcaps_subdirs[] = "z17:z16:z15:z14:z13";
|
||||||
|
+enum { subdirs_count = 5 }; /* Number of components in _dl_hwcaps_subdirs. */
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
_dl_hwcaps_subdirs_active (void)
|
||||||
|
@@ -57,5 +58,12 @@ _dl_hwcaps_subdirs_active (void)
|
||||||
|
return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
|
||||||
|
++active;
|
||||||
|
|
||||||
|
+ /* z17.
|
||||||
|
+ Note: The kernel has not introduced new HWCAP bits as the new facilities do
|
||||||
|
+ not require kernel interaction. Thus we check the features via stfle. */
|
||||||
|
+ if (!(S390_IS_ARCH15 (GLRO(dl_s390_cpu_features).stfle_orig)))
|
||||||
|
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
|
||||||
|
+ ++active;
|
||||||
|
+
|
||||||
|
return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
|
||||||
|
}
|
||||||
|
diff --git a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c
|
||||||
|
index f3b8ef3dec80d2d1..211aaf3052a1e12c 100644
|
||||||
|
--- a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c
|
||||||
|
+++ b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c
|
||||||
|
@@ -26,35 +26,53 @@ extern int marker2 (void);
|
||||||
|
extern int marker3 (void);
|
||||||
|
extern int marker4 (void);
|
||||||
|
extern int marker5 (void);
|
||||||
|
+extern int marker6 (void);
|
||||||
|
|
||||||
|
/* Return the arch level, 10 for the baseline libmarkermod*.so's. */
|
||||||
|
static int
|
||||||
|
compute_level (void)
|
||||||
|
{
|
||||||
|
const char *platform = (const char *) getauxval (AT_PLATFORM);
|
||||||
|
+ const unsigned long int hwcap = getauxval (AT_HWCAP);
|
||||||
|
+ const int latest_level = 15;
|
||||||
|
|
||||||
|
/* The arch* versions refer to the edition of the Principles of
|
||||||
|
Operation, and they are off by two when compared with the recent
|
||||||
|
product names. (The code below should not be considered an
|
||||||
|
accurate mapping to Principles of Operation editions for earlier
|
||||||
|
AT_PLATFORM strings). */
|
||||||
|
- if (strcmp (platform, "z900") == 0)
|
||||||
|
- return 10;
|
||||||
|
- if (strcmp (platform, "z990") == 0)
|
||||||
|
- return 10;
|
||||||
|
- if (strcmp (platform, "z9-109") == 0)
|
||||||
|
- return 10;
|
||||||
|
- if (strcmp (platform, "z10") == 0)
|
||||||
|
- return 10;
|
||||||
|
- if (strcmp (platform, "z196") == 0)
|
||||||
|
- return 10;
|
||||||
|
- if (strcmp (platform, "zEC12") == 0)
|
||||||
|
- return 10;
|
||||||
|
+ if ((strcmp (platform, "z900") == 0)
|
||||||
|
+ || (strcmp (platform, "z990") == 0)
|
||||||
|
+ || (strcmp (platform, "z9-109") == 0)
|
||||||
|
+ || (strcmp (platform, "z10") == 0)
|
||||||
|
+ || (strcmp (platform, "z196") == 0)
|
||||||
|
+ || (strcmp (platform, "zEC12") == 0))
|
||||||
|
+ {
|
||||||
|
+ if ((hwcap & HWCAP_S390_VX) == 0)
|
||||||
|
+ {
|
||||||
|
+ /* As vector-support was introduced with the newer z13
|
||||||
|
+ architecture, we are really on one of the tested older
|
||||||
|
+ architectures. */
|
||||||
|
+ return 10;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ /* According to AT_PLATFORM we are on an older architecture
|
||||||
|
+ without vector-support, but according to HWCAPs vector
|
||||||
|
+ registers are supported. This means we are running on a
|
||||||
|
+ new architecture which is not yet known by the kernel.
|
||||||
|
+ Thus the default AT_PLATFORM string is used, which is the
|
||||||
|
+ oldest supported one. For this test, assume we are on
|
||||||
|
+ the latest known architecture. See
|
||||||
|
+ <kernel>/arch/s390/kernel/processor.c:setup_elf_platform().
|
||||||
|
+ */
|
||||||
|
+ return latest_level;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
|
||||||
|
/* If we are running on z13 or newer and the kernel was booted with novx,
|
||||||
|
then AT_PLATFORM is z13 or newer, but _dl_hwcaps_subdirs_active will
|
||||||
|
return zero and the _dl_hwcaps_subdirs are not searched. */
|
||||||
|
- const unsigned long int hwcap = getauxval (AT_HWCAP);
|
||||||
|
if ((hwcap & HWCAP_S390_VX) == 0)
|
||||||
|
return 10;
|
||||||
|
|
||||||
|
@@ -66,9 +84,12 @@ compute_level (void)
|
||||||
|
return 13;
|
||||||
|
if (strcmp (platform, "z16") == 0)
|
||||||
|
return 14;
|
||||||
|
+ if (strcmp (platform, "z17") == 0)
|
||||||
|
+ return latest_level;
|
||||||
|
+
|
||||||
|
printf ("warning: unrecognized AT_PLATFORM value: %s\n", platform);
|
||||||
|
- /* Assume that the new platform supports z16. */
|
||||||
|
- return 14;
|
||||||
|
+ /* Assume that the new platform supports the latest known architecture. */
|
||||||
|
+ return latest_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
@@ -80,6 +101,7 @@ do_test (void)
|
||||||
|
TEST_COMPARE (marker3 (), MIN (level - 9, 3));
|
||||||
|
TEST_COMPARE (marker4 (), MIN (level - 9, 4));
|
||||||
|
TEST_COMPARE (marker5 (), MIN (level - 9, 5));
|
||||||
|
+ TEST_COMPARE (marker6 (), MIN (level - 9, 6));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/sysdeps/unix/sysv/linux/s390/sysconf.c b/sysdeps/unix/sysv/linux/s390/sysconf.c
|
||||||
|
index 14821b5f248cd991..fc04a7ddedea0d7e 100644
|
||||||
|
--- a/sysdeps/unix/sysv/linux/s390/sysconf.c
|
||||||
|
+++ b/sysdeps/unix/sysv/linux/s390/sysconf.c
|
||||||
|
@@ -65,7 +65,7 @@ get_cache_info (int level, int attr, int type)
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (!S390_IS_Z10 (features->stfle_bits))
|
||||||
|
+ if (!S390_IS_Z10 (features->stfle_orig))
|
||||||
|
{
|
||||||
|
/* We are at least on a z9 machine.
|
||||||
|
Return 256byte for LINESIZE for L1 d/i-cache,
|
||||||
42
SOURCES/glibc-RHEL-50086-2.patch
Normal file
42
SOURCES/glibc-RHEL-50086-2.patch
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
Downstream only.
|
||||||
|
|
||||||
|
From: Stefan Liebler <stli@linux.ibm.com>
|
||||||
|
Date: Tue, 6 May 2025 14:49:22 +0200
|
||||||
|
Subject: [PATCH 2/2] S390: Add z17 to legacy hwcap/platform mechanism
|
||||||
|
|
||||||
|
As glibc 2.34 is still generating ld.so.cache entries for libraries
|
||||||
|
in /usr/lib64/z16/libtest.so, do the same for z17 to have the same behavior.
|
||||||
|
|
||||||
|
See upstream glibc commits:
|
||||||
|
commit b78ff5a25dc8ba9d8c6df10bb0a533254bdd193f
|
||||||
|
'elf: Remove legacy hwcaps support from ldconfig'
|
||||||
|
https://sourceware.org/git/?p=glibc.git;a=commit;h=b78ff5a25dc8ba9d8c6df10bb0a533254bdd193f
|
||||||
|
|
||||||
|
commit c5aa5fd40adc81c4f0b18e01f329aeaf86518c7b
|
||||||
|
'elf: Remove loading legacy hwcaps/platform entries in dynamic loader'
|
||||||
|
https://sourceware.org/git/?p=glibc.git;a=commit;h=c5aa5fd40adc81c4f0b18e01f329aeaf86518c7b
|
||||||
|
|
||||||
|
diff --git a/sysdeps/s390/dl-procinfo-s390.c b/sysdeps/s390/dl-procinfo-s390.c
|
||||||
|
index 559f3827936cd017..7842f7742a829e16 100644
|
||||||
|
--- a/sysdeps/s390/dl-procinfo-s390.c
|
||||||
|
+++ b/sysdeps/s390/dl-procinfo-s390.c
|
||||||
|
@@ -28,5 +28,5 @@ const char _dl_s390_cap_flags[_DL_HWCAP_COUNT][9] =
|
||||||
|
const char _dl_s390_platforms[_DL_PLATFORMS_COUNT][7] =
|
||||||
|
{
|
||||||
|
"g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15",
|
||||||
|
- "z16"
|
||||||
|
+ "z16", "z17"
|
||||||
|
};
|
||||||
|
diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h
|
||||||
|
index eb782fc3014cd012..3d78cacc98d79f7f 100644
|
||||||
|
--- a/sysdeps/s390/dl-procinfo.h
|
||||||
|
+++ b/sysdeps/s390/dl-procinfo.h
|
||||||
|
@@ -24,7 +24,7 @@
|
||||||
|
#define _DL_HWCAP_COUNT 23
|
||||||
|
extern const char _dl_s390_cap_flags[_DL_HWCAP_COUNT][9] attribute_hidden;
|
||||||
|
|
||||||
|
-#define _DL_PLATFORMS_COUNT 11
|
||||||
|
+#define _DL_PLATFORMS_COUNT 12
|
||||||
|
extern const char _dl_s390_platforms[_DL_PLATFORMS_COUNT][7] attribute_hidden;
|
||||||
|
|
||||||
|
/* The kernel provides up to 32 capability bits with elf_hwcap. */
|
||||||
67
SOURCES/glibc-RHEL-50546-1.patch
Normal file
67
SOURCES/glibc-RHEL-50546-1.patch
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
commit 3b21166c4d34ee032093bcf599ffac42ad8a4371
|
||||||
|
Author: Arjun Shankar <arjun@redhat.com>
|
||||||
|
Date: Wed Jun 4 13:08:53 2025 +0200
|
||||||
|
|
||||||
|
manual: Expand Descriptor-Relative Access section
|
||||||
|
|
||||||
|
Improve the clarity of the paragraphs describing common flags and add a
|
||||||
|
list of common error conditions for descriptor-relative functions.
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/manual/filesys.texi b/manual/filesys.texi
|
||||||
|
index 450d175e614d8834..28d38f23fc58c51f 100644
|
||||||
|
--- a/manual/filesys.texi
|
||||||
|
+++ b/manual/filesys.texi
|
||||||
|
@@ -310,12 +310,17 @@ This is a GNU extension.
|
||||||
|
The flags argument in @code{@dots{}at} functions can be a combination of
|
||||||
|
the following flags, defined in @file{fcntl.h}. Not all such functions
|
||||||
|
support all flags, and some (such as @code{openat}) do not accept a
|
||||||
|
-flags argument at all.
|
||||||
|
-
|
||||||
|
-In the flag descriptions below, the @dfn{effective final path component}
|
||||||
|
-refers to the final component (basename) of the full path constructed
|
||||||
|
-from the descriptor and file name arguments, using file name lookup, as
|
||||||
|
-described above.
|
||||||
|
+flags argument at all. Although the flags specific to each function have
|
||||||
|
+distinct values from each other, some flags (relevant to different
|
||||||
|
+functions) might share the same value and therefore are not guaranteed to
|
||||||
|
+have unique values.
|
||||||
|
+
|
||||||
|
+A non-exhaustive list of common flags and their descriptions follows. Flags
|
||||||
|
+specific to a function are described alongside the function itself. In
|
||||||
|
+these flag descriptions, the @dfn{effective final path component} refers to
|
||||||
|
+the final component (basename) of the full path constructed from the
|
||||||
|
+descriptor and file name arguments, using file name lookup, as described
|
||||||
|
+above.
|
||||||
|
|
||||||
|
@vtable @code
|
||||||
|
@item AT_EMPTY_PATH
|
||||||
|
@@ -353,6 +358,28 @@ a non-final component of the file name are still followed.
|
||||||
|
argument to the @code{getauxval} function (with @code{AT_@dots{}}
|
||||||
|
constants defined in @file{elf.h}). @xref{Auxiliary Vector}.
|
||||||
|
|
||||||
|
+@cindex common errors in descriptor-relative functions
|
||||||
|
+@cindex common errors in @code{@dots{}at} functions
|
||||||
|
+
|
||||||
|
+The @code{@dots{}at} functions have some common error conditions due to the
|
||||||
|
+nature of descriptor-relative access. A list of common errors and their
|
||||||
|
+descriptions follows. Errors specific to a function are described alongside
|
||||||
|
+the function itself.
|
||||||
|
+
|
||||||
|
+@table @code
|
||||||
|
+@item EBADF
|
||||||
|
+The file name argument is a relative path but the descriptor argument
|
||||||
|
+is neither @code{AT_FDCWD} nor a valid file descriptor.
|
||||||
|
+
|
||||||
|
+@item EINVAL
|
||||||
|
+If the function accepts a @var{flags} argument, the flag combination passed
|
||||||
|
+is not valid for the function.
|
||||||
|
+
|
||||||
|
+@item ENOTDIR
|
||||||
|
+The file name argument is a relative file name but the descriptor
|
||||||
|
+argument is associated with a file that is not a directory.
|
||||||
|
+@end table
|
||||||
|
+
|
||||||
|
@node Accessing Directories
|
||||||
|
@section Accessing Directories
|
||||||
|
@cindex accessing directories
|
||||||
50
SOURCES/glibc-RHEL-50546-2.patch
Normal file
50
SOURCES/glibc-RHEL-50546-2.patch
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
commit 941157dbcdf1c410960bde991206bfb6d9bb292f
|
||||||
|
Author: Arjun Shankar <arjun@redhat.com>
|
||||||
|
Date: Wed Jun 4 13:08:54 2025 +0200
|
||||||
|
|
||||||
|
manual: Document faccessat
|
||||||
|
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/manual/filesys.texi b/manual/filesys.texi
|
||||||
|
index 28d38f23fc58c51f..17c15b54037e719d 100644
|
||||||
|
--- a/manual/filesys.texi
|
||||||
|
+++ b/manual/filesys.texi
|
||||||
|
@@ -3069,6 +3069,29 @@ Flag meaning test for execute/search permission.
|
||||||
|
Flag meaning test for existence of the file.
|
||||||
|
@end deftypevr
|
||||||
|
|
||||||
|
+@deftypefun int faccessat (int @var{filedes}, const char *@var{filename}, int @var{how}, int @var{flags})
|
||||||
|
+@standards{POSIX.1-2008, unistd.h}
|
||||||
|
+@comment Unaudited and therefore marked AC-Unsafe and AS-Unsafe by default
|
||||||
|
+@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
|
||||||
|
+This function is a descriptor-relative version of the @code{access}
|
||||||
|
+function above. @xref{Descriptor-Relative Access}. The @var{flags}
|
||||||
|
+argument can contain a combination of the flags @code{AT_EACCESS} described
|
||||||
|
+below, @code{AT_EMPTY_PATH}, and @code{AT_SYMLINK_NOFOLLOW}.
|
||||||
|
+
|
||||||
|
+@vtable @code
|
||||||
|
+@item AT_EACCESS
|
||||||
|
+This flag when passed to the @code{faccessat} function causes it to perform
|
||||||
|
+access checks using effective user and group IDs instead of real IDs, which
|
||||||
|
+is the default and matches the @code{access} function.
|
||||||
|
+@end vtable
|
||||||
|
+
|
||||||
|
+Compared to @code{access}, some additional error conditions can occur.
|
||||||
|
+@xref{Descriptor-Relative Access}.
|
||||||
|
+
|
||||||
|
+This function may not work correctly on older kernels missing the
|
||||||
|
+@code{faccessat2} system call.
|
||||||
|
+@end deftypefun
|
||||||
|
+
|
||||||
|
@node File Times
|
||||||
|
@subsection File Times
|
||||||
|
|
||||||
|
@@ -3849,7 +3872,6 @@ creation always works like @code{open} with @code{O_EXCL}.
|
||||||
|
The @code{mkdtemp} function comes from OpenBSD.
|
||||||
|
|
||||||
|
@c FIXME these are undocumented:
|
||||||
|
-@c faccessat
|
||||||
|
@c fchmodat
|
||||||
|
@c fchownat
|
||||||
|
@c futimesat
|
||||||
38
SOURCES/glibc-RHEL-50546-3.patch
Normal file
38
SOURCES/glibc-RHEL-50546-3.patch
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
commit 49766eb1a5b93d093bd0fada55ca7a42dfdb10d6
|
||||||
|
Author: Arjun Shankar <arjun@redhat.com>
|
||||||
|
Date: Wed Jun 4 13:08:55 2025 +0200
|
||||||
|
|
||||||
|
manual: Document mkdirat
|
||||||
|
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/manual/filesys.texi b/manual/filesys.texi
|
||||||
|
index 17c15b54037e719d..d8f362f3beda9b28 100644
|
||||||
|
--- a/manual/filesys.texi
|
||||||
|
+++ b/manual/filesys.texi
|
||||||
|
@@ -1964,6 +1964,17 @@ To use this function, your program should include the header file
|
||||||
|
@pindex sys/stat.h
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
+@deftypefun int mkdirat (int @var{filedes}, const char *@var{filename}, mode_t @var{mode})
|
||||||
|
+@standards{POSIX.1-2008, sys/stat.h}
|
||||||
|
+@comment Unaudited and therefore marked AC-Unsafe and AS-Unsafe by default
|
||||||
|
+@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
|
||||||
|
+This function is a descriptor-relative version of the @code{mkdir}
|
||||||
|
+function above. @xref{Descriptor-Relative Access}.
|
||||||
|
+
|
||||||
|
+Compared to @code{mkdir}, some additional error conditions can occur.
|
||||||
|
+@xref{Descriptor-Relative Access}.
|
||||||
|
+@end deftypefun
|
||||||
|
+
|
||||||
|
@node File Attributes
|
||||||
|
@section File Attributes
|
||||||
|
|
||||||
|
@@ -3877,7 +3888,6 @@ The @code{mkdtemp} function comes from OpenBSD.
|
||||||
|
@c futimesat
|
||||||
|
@c fstatat (there's a commented-out safety assessment for this one)
|
||||||
|
@c statx
|
||||||
|
-@c mkdirat
|
||||||
|
@c mkfifoat
|
||||||
|
@c name_to_handle_at
|
||||||
|
@c openat
|
||||||
38
SOURCES/glibc-RHEL-50546-4.patch
Normal file
38
SOURCES/glibc-RHEL-50546-4.patch
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
commit 60f86c9cd062882cbeb04b2944c3dfb7457ee5c5
|
||||||
|
Author: Arjun Shankar <arjun@redhat.com>
|
||||||
|
Date: Wed Jun 4 13:08:56 2025 +0200
|
||||||
|
|
||||||
|
manual: Document renameat
|
||||||
|
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/manual/filesys.texi b/manual/filesys.texi
|
||||||
|
index d8f362f3beda9b28..8a173c562fa71f83 100644
|
||||||
|
--- a/manual/filesys.texi
|
||||||
|
+++ b/manual/filesys.texi
|
||||||
|
@@ -1910,6 +1910,17 @@ file systems.
|
||||||
|
@end table
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
+@deftypefun int renameat (int @var{oldfiledes}, const char *@var{oldname}, int @var{newfiledes}, const char *@var{newname})
|
||||||
|
+@standards{POSIX.1-2008, stdio.h}
|
||||||
|
+@comment Unaudited and therefore marked AC-Unsafe and AS-Unsafe by default
|
||||||
|
+@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
|
||||||
|
+This function is a descriptor-relative version of the @code{rename}
|
||||||
|
+function above. @xref{Descriptor-Relative Access}.
|
||||||
|
+
|
||||||
|
+Compared to @code{rename}, some additional error conditions can occur.
|
||||||
|
+@xref{Descriptor-Relative Access}.
|
||||||
|
+@end deftypefun
|
||||||
|
+
|
||||||
|
@node Creating Directories
|
||||||
|
@section Creating Directories
|
||||||
|
@cindex creating a directory
|
||||||
|
@@ -3893,7 +3904,6 @@ The @code{mkdtemp} function comes from OpenBSD.
|
||||||
|
@c openat
|
||||||
|
@c open_by_handle_at
|
||||||
|
@c readlinkat
|
||||||
|
-@c renameat
|
||||||
|
@c renameat2
|
||||||
|
@c scandirat
|
||||||
|
@c symlinkat
|
||||||
51
SOURCES/glibc-RHEL-50546-5.patch
Normal file
51
SOURCES/glibc-RHEL-50546-5.patch
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
commit 75b725717ff23d0ae38fc7f4a0361cb1bdffbe2e
|
||||||
|
Author: Arjun Shankar <arjun@redhat.com>
|
||||||
|
Date: Wed Jun 4 13:08:57 2025 +0200
|
||||||
|
|
||||||
|
manual: Document unlinkat
|
||||||
|
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/manual/filesys.texi b/manual/filesys.texi
|
||||||
|
index 8a173c562fa71f83..396d68c32925c501 100644
|
||||||
|
--- a/manual/filesys.texi
|
||||||
|
+++ b/manual/filesys.texi
|
||||||
|
@@ -1779,6 +1779,31 @@ file system and can't be modified.
|
||||||
|
@end table
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
+@deftypefun int unlinkat (int @var{filedes}, const char *@var{filename}, int @var{flags})
|
||||||
|
+@standards{POSIX.1-2008, unistd.h}
|
||||||
|
+@comment Unaudited and therefore marked AC-Unsafe and AS-Unsafe by default
|
||||||
|
+@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
|
||||||
|
+This function is a descriptor-relative version of the @code{unlink}
|
||||||
|
+function above. @xref{Descriptor-Relative Access}. The @var{flags}
|
||||||
|
+argument may either be @code{0} or contain the flag @code{AT_REMOVEDIR}:
|
||||||
|
+
|
||||||
|
+@table @code
|
||||||
|
+@item AT_REMOVEDIR
|
||||||
|
+This flag causes @code{unlinkat} to perform an @code{rmdir} operation on
|
||||||
|
+@code{filename} instead of performing the equivalent of @code{unlink}.
|
||||||
|
+@end table
|
||||||
|
+
|
||||||
|
+Compared to @code{unlink}, some additional error conditions can occur due to
|
||||||
|
+descriptor-relative access. @xref{Descriptor-Relative Access}. In
|
||||||
|
+addition to this, the following other errors can also occur:
|
||||||
|
+
|
||||||
|
+@table @code
|
||||||
|
+@item EISDIR
|
||||||
|
+The effective final path derived from @var{filename} and @var{filedes} is a
|
||||||
|
+directory but @code{AT_REMOVEDIR} was not passed in @code{flags}.
|
||||||
|
+@end table
|
||||||
|
+@end deftypefun
|
||||||
|
+
|
||||||
|
@deftypefun int rmdir (const char *@var{filename})
|
||||||
|
@standards{POSIX.1, unistd.h}
|
||||||
|
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
|
||||||
|
@@ -3907,6 +3932,5 @@ The @code{mkdtemp} function comes from OpenBSD.
|
||||||
|
@c renameat2
|
||||||
|
@c scandirat
|
||||||
|
@c symlinkat
|
||||||
|
-@c unlinkat
|
||||||
|
@c utimensat
|
||||||
|
@c mknodat
|
||||||
97
SOURCES/glibc-RHEL-50546-6.patch
Normal file
97
SOURCES/glibc-RHEL-50546-6.patch
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
commit 25f1d945766a3a757d9b54eb48fe7c3c48c0f791
|
||||||
|
Author: Arjun Shankar <arjun@redhat.com>
|
||||||
|
Date: Wed Jun 4 13:08:58 2025 +0200
|
||||||
|
|
||||||
|
manual: Document futimens and utimensat
|
||||||
|
|
||||||
|
Document futimens and utimensat. Also document the EINVAL error
|
||||||
|
condition for futimes. It is inherited by futimens and utimensat as
|
||||||
|
well.
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/manual/filesys.texi b/manual/filesys.texi
|
||||||
|
index 396d68c32925c501..f21f21804251e480 100644
|
||||||
|
--- a/manual/filesys.texi
|
||||||
|
+++ b/manual/filesys.texi
|
||||||
|
@@ -3307,6 +3307,10 @@ permission for the file, or be a privileged user.
|
||||||
|
@item EBADF
|
||||||
|
The @var{filedes} argument is not a valid file descriptor.
|
||||||
|
|
||||||
|
+@item EINVAL
|
||||||
|
+At least one of the fields in the @code{tvp} array passed has an invalid
|
||||||
|
+value.
|
||||||
|
+
|
||||||
|
@item EPERM
|
||||||
|
If the @var{times} argument is not a null pointer, you must either be
|
||||||
|
the owner of the file or be a privileged user.
|
||||||
|
@@ -3316,6 +3320,64 @@ The file lives on a read-only file system.
|
||||||
|
@end table
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
+@deftypefun int futimens (int @var{filedes}, const struct timespec @var{tsp}@t{[2]})
|
||||||
|
+@standards{POSIX.1-2008, sys/stat.h}
|
||||||
|
+@comment Unaudited and therefore marked AC-Unsafe and AS-Unsafe by default
|
||||||
|
+@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
|
||||||
|
+This function is like @code{futimes}, except that it sets the file access
|
||||||
|
+and modification timestamps with nanosecond precision. The argument
|
||||||
|
+@code{tsp} is used similarly to @code{futimes}' @code{tvp}, but has a
|
||||||
|
+@code{const struct timespec} type that can express calendar time with
|
||||||
|
+nanosecond precision. @xref{Time Types}.
|
||||||
|
+@end deftypefun
|
||||||
|
+
|
||||||
|
+@deftypefun int utimensat (int @var{filedes}, const char *@var{filename}, const struct timespec @var{tsp}@t{[2]}, int @var{flags})
|
||||||
|
+@standards{POSIX.1-2008, sys/stat.h}
|
||||||
|
+@comment Unaudited and therefore marked AC-Unsafe and AS-Unsafe by default
|
||||||
|
+@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
|
||||||
|
+This function is a descriptor-relative version of the @code{futimens}
|
||||||
|
+function above. @xref{Descriptor-Relative Access}. The @var{flags}
|
||||||
|
+argument can contain a combination of the flags @code{AT_EMPTY_PATH}, and
|
||||||
|
+@code{AT_SYMLINK_NOFOLLOW}. The call:
|
||||||
|
+
|
||||||
|
+@smallexample
|
||||||
|
+futimens (@var{filedes}, @var{tsp})
|
||||||
|
+@end smallexample
|
||||||
|
+
|
||||||
|
+is equivalent to:
|
||||||
|
+
|
||||||
|
+@smallexample
|
||||||
|
+utimensat (@var{filedes}, @code{NULL}, @var{tsp}, 0)
|
||||||
|
+@end smallexample
|
||||||
|
+
|
||||||
|
+Compared to @code{futimens}, some additional error conditions can occur due
|
||||||
|
+to descriptor-relative access. @xref{Descriptor-Relative Access}. In
|
||||||
|
+addition to this, the following other errors can also occur:
|
||||||
|
+
|
||||||
|
+@table @code
|
||||||
|
+@item EINVAL
|
||||||
|
+The @var{filename} argument is NULL, @var{filedes} is not @code{AT_FDCWD},
|
||||||
|
+and @var{flags} is not @code{0}.
|
||||||
|
+
|
||||||
|
+@item ELOOP
|
||||||
|
+There are too many levels of indirection. This can be the result of
|
||||||
|
+circular symbolic links to directories.
|
||||||
|
+
|
||||||
|
+@item ENAMETOOLONG
|
||||||
|
+The resulting path is too long. This error only occurs on systems which
|
||||||
|
+have a limit on the file name length.
|
||||||
|
+
|
||||||
|
+@item ENOENT
|
||||||
|
+The @var{filename} argument is an empty string and @var{flags} does not
|
||||||
|
+contain @code{AT_EMPTY_PATH}, or @var{filename} does not refer to an
|
||||||
|
+existing file.
|
||||||
|
+
|
||||||
|
+@item ESRCH
|
||||||
|
+Search permission was denied for one of the prefix components of the the
|
||||||
|
+@var{filename} argument.
|
||||||
|
+@end table
|
||||||
|
+@end deftypefun
|
||||||
|
+
|
||||||
|
@node File Size
|
||||||
|
@subsection File Size
|
||||||
|
|
||||||
|
@@ -3932,5 +3994,4 @@ The @code{mkdtemp} function comes from OpenBSD.
|
||||||
|
@c renameat2
|
||||||
|
@c scandirat
|
||||||
|
@c symlinkat
|
||||||
|
-@c utimensat
|
||||||
|
@c mknodat
|
||||||
148
SOURCES/glibc-RHEL-53909-1.patch
Normal file
148
SOURCES/glibc-RHEL-53909-1.patch
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
commit 2eee835eca960c9d4119279804214b7a1ed5d156
|
||||||
|
Author: DJ Delorie <dj@redhat.com>
|
||||||
|
Date: Thu Aug 8 22:44:56 2024 -0400
|
||||||
|
|
||||||
|
inet: test if_nametoindex and if_indextoname
|
||||||
|
|
||||||
|
Tests for if_nameindex, if_name2index, and if_index2name
|
||||||
|
|
||||||
|
Tests that valid results are consistent.
|
||||||
|
|
||||||
|
Tests that invalid parameters fail correctly.
|
||||||
|
|
||||||
|
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
diff --git a/inet/Makefile b/inet/Makefile
|
||||||
|
index ef6b94ed0b519d6d..dbdcea9e71fdd765 100644
|
||||||
|
--- a/inet/Makefile
|
||||||
|
+++ b/inet/Makefile
|
||||||
|
@@ -136,6 +136,7 @@ tests := \
|
||||||
|
tst-getni1 \
|
||||||
|
tst-getni2 \
|
||||||
|
tst-if_index-long \
|
||||||
|
+ tst-if_nameindex \
|
||||||
|
tst-inet6_rth \
|
||||||
|
tst-network \
|
||||||
|
tst-ntoa \
|
||||||
|
diff --git a/inet/tst-if_nameindex.c b/inet/tst-if_nameindex.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000..b025cdb3a7c6b68c
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/inet/tst-if_nameindex.c
|
||||||
|
@@ -0,0 +1,116 @@
|
||||||
|
+/* Tests for if_nameindex et al.
|
||||||
|
+ 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
|
||||||
|
+ <https://www.gnu.org/licenses/>. */
|
||||||
|
+
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <errno.h>
|
||||||
|
+#include <net/if.h>
|
||||||
|
+#include <netdb.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <support/check.h>
|
||||||
|
+#include <support/descriptors.h>
|
||||||
|
+#include <support/support.h>
|
||||||
|
+
|
||||||
|
+static char *buffer;
|
||||||
|
+
|
||||||
|
+static const char *test_names[] = {
|
||||||
|
+ "testing",
|
||||||
|
+ "invalid",
|
||||||
|
+ "dont-match",
|
||||||
|
+ "",
|
||||||
|
+ "\001\001\001\177",
|
||||||
|
+ NULL
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+checki (int i)
|
||||||
|
+{
|
||||||
|
+ char *ifname;
|
||||||
|
+
|
||||||
|
+ /* Test that a known-invalid index returns NULL. */
|
||||||
|
+ /* BUFFER should not be accessed. */
|
||||||
|
+
|
||||||
|
+ printf ("Testing if_indextoname (%d) == NULL\n", i);
|
||||||
|
+ ifname = if_indextoname (i, NULL);
|
||||||
|
+ TEST_VERIFY (ifname == NULL);
|
||||||
|
+ TEST_VERIFY (errno == ENXIO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+do_test (void)
|
||||||
|
+{
|
||||||
|
+ struct if_nameindex *if_ni, *ifp;
|
||||||
|
+ int min_idx, max_idx, buflen = 0;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ if_ni = if_nameindex ();
|
||||||
|
+ TEST_VERIFY (if_ni != NULL);
|
||||||
|
+
|
||||||
|
+ min_idx = max_idx = if_ni->if_index;
|
||||||
|
+
|
||||||
|
+ for (ifp = if_ni; !(ifp->if_index == 0 && ifp->if_name == NULL); ifp++)
|
||||||
|
+ {
|
||||||
|
+ printf ("%u: %s\n", ifp->if_index, ifp->if_name);
|
||||||
|
+ if (ifp->if_index < min_idx)
|
||||||
|
+ min_idx = ifp->if_index;
|
||||||
|
+ if (ifp->if_index > max_idx)
|
||||||
|
+ max_idx = ifp->if_index;
|
||||||
|
+ if (strlen (ifp->if_name) + 1 > buflen)
|
||||||
|
+ buflen = strlen (ifp->if_name) + 1;
|
||||||
|
+ }
|
||||||
|
+ buffer = (char *) xmalloc (buflen);
|
||||||
|
+
|
||||||
|
+ /* Check normal operation. */
|
||||||
|
+ for (ifp = if_ni; !(ifp->if_index == 0 && ifp->if_name == NULL); ifp++)
|
||||||
|
+ {
|
||||||
|
+ unsigned int idx = if_nametoindex (ifp->if_name);
|
||||||
|
+ TEST_VERIFY (idx == ifp->if_index);
|
||||||
|
+
|
||||||
|
+ char *fn = if_indextoname (ifp->if_index, buffer);
|
||||||
|
+ TEST_VERIFY (strcmp (fn, ifp->if_name) == 0);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (i=-2; i<min_idx; i++)
|
||||||
|
+ checki (i);
|
||||||
|
+ for (i=max_idx+1; i<max_idx+3; i++)
|
||||||
|
+ checki (i);
|
||||||
|
+
|
||||||
|
+ /* Check that a known-invalid name returns 0. */
|
||||||
|
+
|
||||||
|
+ for (i=0; test_names[i] != NULL; i++)
|
||||||
|
+ {
|
||||||
|
+ /* Make sure our "invalid" name is really invalid. */
|
||||||
|
+ for (ifp = if_ni; !(ifp->if_index == 0 && ifp->if_name == NULL); ifp++)
|
||||||
|
+ if (strcmp (test_names[i], ifp->if_name) == 0)
|
||||||
|
+ goto not_this_one;
|
||||||
|
+
|
||||||
|
+ printf ("Testing if_nametoindex (%s) == 0\n", test_names[i]);
|
||||||
|
+
|
||||||
|
+ unsigned int idx = if_nametoindex (test_names[i]);
|
||||||
|
+ TEST_VERIFY (idx == 0);
|
||||||
|
+ TEST_VERIFY (errno == ENODEV);
|
||||||
|
+
|
||||||
|
+ not_this_one:
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ if_freenameindex (if_ni);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#include <support/test-driver.c>
|
||||||
20
SOURCES/glibc-RHEL-53909-2.patch
Normal file
20
SOURCES/glibc-RHEL-53909-2.patch
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
commit 79f44e1a47e87907fb8e97bbd098e01c4adc26a5
|
||||||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||||||
|
Date: Mon Aug 26 16:45:31 2024 +0200
|
||||||
|
|
||||||
|
inet: Avoid label at end of compound statement in tst-if_nameindex
|
||||||
|
|
||||||
|
This fails to compile with GCC 8.
|
||||||
|
|
||||||
|
diff --git a/inet/tst-if_nameindex.c b/inet/tst-if_nameindex.c
|
||||||
|
index b025cdb3a7c6b68c..5b905601245bef34 100644
|
||||||
|
--- a/inet/tst-if_nameindex.c
|
||||||
|
+++ b/inet/tst-if_nameindex.c
|
||||||
|
@@ -105,6 +105,7 @@ do_test (void)
|
||||||
|
TEST_VERIFY (errno == ENODEV);
|
||||||
|
|
||||||
|
not_this_one:
|
||||||
|
+ ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user