glibc/glibc-rh2248502-1.patch
Florian Weimer 0413a67417 Auto-sync with upstream branch master
Upstream commit: 5dd3bda59c2d9da138f0d98808d087cdb95cdc17:

- Revert back to old qsort/qsort_r implementation (#2248502)
- Adjust test build competition check to match new DejaGnu-style message.

- sysdeps: sem_open: Clear O_CREAT when semaphore file is expected to exist [BZ #30789]
- Add SEGV_CPERR from Linux 6.6 to bits/siginfo-consts.h
- linux: Sync Linux 6.6 elf.h
- linux: Add HWCAP2_HBC from Linux 6.6 to AArch64 bits/hwcap.h
- linux: Add FSCONFIG_CMD_CREATE_EXCL from Linux 6.6 to sys/mount.h
- linux: Add MMAP_ABOVE4G from Linux 6.6 to sys/mman.h
- Update kernel version to 6.6 in header constant tests
- Update syscall lists for Linux 6.6
- Format test results closer to what DejaGnu does
- AArch64: Cleanup ifuncs
- Use correct subdir when building tst-rfc3484* for mach and arm
- stdlib: Add more qsort{_r} coverage
- stdlib: qsort: Move some macros to inline function
- stdlib: Move insertion sort out qsort
- stdlib: Optimization qsort{_r} swap implementation
- string: Add internal memswap implementation
- crypt: Remove manul entry for --enable-crypt
- Use Linux 6.6 in build-many-glibcs.py
- crypt: Remove libcrypt support
- sparc: Remove optimize md5, sha256, and sha512
- build-many-glibcs: Fix traililing whitespace
- AArch64: Add support for MOPS memcpy/memmove/memset
- Move getnameinfo from 'inet' to 'nss'
- Move getaddrinfo from 'posix' into 'nss'
- Move 'services' routines from 'inet' into 'nss'
- Move 'rpc' routines from 'inet' into 'nss'
- Move 'protocols' routines from 'inet' into 'nss'
- Move 'networks' routines from 'inet' into 'nss'
- Move 'netgroup' routines from 'inet' into 'nss'
- Move 'hosts' routines from 'inet' into 'nss'
- Move 'ethers' routines from 'inet' into 'nss'
- Move 'aliases' routines from 'inet' into 'nss'
- Remove 'shadow' and merge into 'nss'
- Remove 'pwd' and merge into 'nss'
- Remove 'gshadow' and merge into 'nss'
- Remove 'grp' and merge into 'nss' and 'posix'
- malloc: Fix tst-tcfree3 build csky-linux-gnuabiv2 with fortify source
- test-container: disable ld.so system cache on DSO detection
- aarch64: Add vector implementations of exp10 routines
- aarch64: Add vector implementations of log10 routines
- aarch64: Add vector implementations of log2 routines
- aarch64: Add vector implementations of exp2 routines
- aarch64: Add vector implementations of tan routines
- elf: ldconfig should skip temporary files created by package managers
- tst-spawn-cgroup.c: Fix argument order of UNSUPPORTED message.
- Add NT_PPC_DEXCR and NT_PPC_HASHKEYR from Linux 6.5 to elf.h
- s390: Fix undefined behaviour in feenableexcept, fedisableexcept [BZ #30960]
- elf: Do not print the cache entry if --inhibit-cache is used
2023-11-07 16:22:46 +01:00

448 lines
12 KiB
Diff

Revert "stdlib: Remove use of mergesort on qsort (BZ 21719)"
This reverts commit 03bf8357e8291857a435afcc3048e0b697b6cc04.
diff --git a/include/stdlib.h b/include/stdlib.h
index 580da9be15adf0c1..0ed8271d9bd76896 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -149,6 +149,8 @@ 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 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..720e0ca952a665bd 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
@@ -275,6 +275,7 @@ 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 a550858478f7fc83..5691bf2f2b2bb861 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} in this library might not be an
+in-place sort and might thereby use an extra amount of memory to store
+the array.
@end deftypefun
@node Search/Sort Example
diff --git a/stdlib/Makefile b/stdlib/Makefile
index 6af606136e557910..b99bb34ae8f23730 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -96,6 +96,7 @@ routines := \
mbtowc \
mrand48 \
mrand48_r \
+ msort \
nrand48 \
nrand48_r \
old_atexit \
@@ -380,6 +381,7 @@ 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
new file mode 100644
index 0000000000000000..bbaa5e9f82a75b78
--- /dev/null
+++ b/stdlib/msort.c
@@ -0,0 +1,309 @@
+/* An alternative to qsort, with an identical interface.
+ This file is part of the GNU C Library.
+ Copyright (C) 1992-2023 Free Software Foundation, Inc.
+
+ 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
+ && ((uintptr_t) b) % __alignof__ (uint32_t) == 0)
+ {
+ if (s == sizeof (uint32_t))
+ p.var = 0;
+ else if (s == sizeof (uint64_t)
+ && ((uintptr_t) b) % __alignof__ (uint64_t) == 0)
+ p.var = 1;
+ else if ((s & (sizeof (unsigned long) - 1)) == 0
+ && ((uintptr_t) b)
+ % __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 fd32a165e7313c3a..d5f205affc4371cb 100644
--- a/stdlib/qsort.c
+++ b/stdlib/qsort.c
@@ -19,6 +19,7 @@
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>
@@ -264,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
-__qsort_r (void *const pbase, size_t total_elems, size_t size,
- __compar_d_fn_t cmp, void *arg)
+_quicksort (void *const pbase, size_t total_elems, size_t size,
+ __compar_d_fn_t cmp, void *arg)
{
char *base_ptr = (char *) pbase;
@@ -397,12 +398,3 @@ __qsort_r (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)