Compare commits

...
Author SHA1 Message Date
Sunil K Pandey f28f188021 nptl: Optimize trylock for high cache contention workloads (BZ #33704)
Check lock availability before acquisition to reduce cache line
bouncing.  Significantly improves trylock throughput on multi-core
systems under heavy contention.

Tested on x86_64.

Fixes BZ #33704.

Co-authored-by: Alex M Wells <alex.m.wells@intel.com>
Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>
(cherry picked from commit 63716823db)
2025-12-18 11:05:58 -08:00
Alex Butler 2417ddb645 aarch64: MTE compatible strncmp
Add support for MTE to strncmp. Regression tested with xcheck and benchmarked
with glibc's benchtests on the Cortex-A53, Cortex-A72, and Neoverse N1.

The existing implementation assumes that any access to the pages in which the
string resides is safe. This assumption is not true when MTE is enabled. This
patch updates the algorithm to ensure that accesses remain within the bounds
of an MTE tag (16-byte chunks) and improves overall performance.

Co-authored-by: Branislav Rankov <branislav.rankov@arm.com>
Co-authored-by: Wilco Dijkstra <wilco.dijkstra@arm.com>
(cherry picked from commit 03e1378f94)
2024-11-04 16:31:20 +00:00
Adhemerval Zanella 3c15600e79 elf: Fix elf/tst-pldd with --enable-hardcoded-path-in-tests (BZ#24506)
The elf/tst-pldd (added by 1a4c27355e to fix BZ#18035) test does
not expect the hardcoded paths that are output by pldd when the test
is built with --enable-hardcoded-path-in-tests.  Instead of showing
the ABI installed library names for loader and libc (such as
ld-linux-x86-64.so.2 and libc.so.6 for x86_64), pldd shows the default
built ld.so and libc.so.

It makes the tests fail with an invalid expected loader/libc name.

This patch fixes the elf-pldd test by adding the canonical ld.so and
libc.so names in the expected list of possible outputs when parsing
the result output from pldd.  The test now handles both default
build and --enable-hardcoded-path-in-tests option.

Checked on x86_64-linux-gnu (built with and without
--enable-hardcoded-path-in-tests) and i686-linux-gnu.

	* elf/tst-pldd.c (in_str_list): New function.
	(do_test): Add default names for ld and libc as one option.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit b2af6fb2ed)
2024-05-10 07:50:59 -07:00
H.J. Lu 6fc6b074ea Force DT_RPATH for --enable-hardcoded-path-in-tests
On Fedora 40/x86-64, linker enables --enable-new-dtags by default which
generates DT_RUNPATH instead of DT_RPATH.  Unlike DT_RPATH, DT_RUNPATH
only applies to DT_NEEDED entries in the executable and doesn't applies
to DT_NEEDED entries in shared libraries which are loaded via DT_NEEDED
entries in the executable.  Some glibc tests have libstdc++.so.6 in
DT_NEEDED, which has libm.so.6 in DT_NEEDED.  When DT_RUNPATH is generated,
/lib64/libm.so.6 is loaded for such tests.  If the newly built glibc is
older than glibc 2.36, these tests fail with

assert/tst-assert-c++: /export/build/gnu/tools-build/glibc-gitlab-release/build-x86_64-linux/libc.so.6: version `GLIBC_2.36' not found (required by /lib64/libm.so.6)
assert/tst-assert-c++: /export/build/gnu/tools-build/glibc-gitlab-release/build-x86_64-linux/libc.so.6: version `GLIBC_ABI_DT_RELR' not found (required by /lib64/libm.so.6)

Pass -Wl,--disable-new-dtags to linker when building glibc tests with
--enable-hardcoded-path-in-tests.  This fixes BZ #31719.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 2dcaf70643)
2024-05-10 06:16:48 -07:00
H.J. Lu 3d443b8d6a Don't make errlist.o[s].d depend on errlist-compat.h
stdio-common/errlist.o.d and stdio-common/errlist.os.d aren't generated
alongside with stdio-common/errlist-compat.h.  Don't make them depend on
stdio-common/errlist-compat.h to avoid infinite loop with make-4.4.  This
fixes BZ #31330.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sunil K Pandey <skpgkp2@gmail.com>
2024-05-09 20:12:05 -07:00
Sergei Trofimovich b1241520a0 Makerules: fix MAKEFLAGS assignment for upcoming make-4.4 [BZ# 29564]
make-4.4 will add long flags to MAKEFLAGS variable:

    * WARNING: Backward-incompatibility!
      Previously only simple (one-letter) options were added to the MAKEFLAGS
      variable that was visible while parsing makefiles.  Now, all options
      are available in MAKEFLAGS.

This causes locale builds to fail when long options are used:

    $ make --shuffle
    ...
    make  -C localedata install-locales
    make: invalid shuffle mode: '1662724426r'

The change fixes it by passing eash option via whitespace and dashes.
That way option is appended to both single-word form and whitespace
separated form.

While at it fixed --silent mode detection in $(MAKEFLAGS) by filtering
out --long-options. Otherwise options like --shuffle flag enable silent
mode unintentionally. $(silent-make) variable consolidates the checks.

Resolves: BZ# 29564

CC: Paul Smith <psmith@gnu.org>
CC: Siddhesh Poyarekar <siddhesh@gotplt.org>
Signed-off-by: Sergei Trofimovich <slyich@gmail.com>
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit 2d7ed98add)
2024-05-09 20:12:03 -07:00
Florian Weimer ba7a5e3e0f elf: Disable some subtests of ifuncmain1, ifuncmain5 for !PIE
(cherry picked from commit 9cc9d61ee1)
2024-05-09 19:06:57 -07:00
Aurelien Jarno b6e9f21071 testsuite: stdlib/isomac.c: add missing include
When running the testsuite, building stdlib/isomac.c outputs the
following warning:

  gcc -O   -D_GNU_SOURCE -DIS_IN_build -include /home/aurel32/glibc-build/config.h isomac.c -o /home/aurel32/glibc-build/stdlib/isomac
  isomac.c: In function ‘get_null_defines’:
  isomac.c:260:3: warning: implicit declaration of function ‘close’; did you mean ‘pclose’? [-Wimplicit-function-declaration]
     close (fd);
     ^~~~~
     pclose

Fix that by adding the <unistd.h> include.

Changelog:
	* stdlib/isomac.c: Include <unistd.h>.
(cherry picked from commit 11f382ee78)
2024-05-09 19:05:44 -07:00
Florian Weimer 76d9e44c59 resolv/tst-idna_name_classify: Isolate from system libraries
Loading NSS modules from static binaries uses installed system
libraries if LD_LIBRARY_PATH is not set.

(cherry picked from commit 8dddf0bd5a)
2024-05-09 15:32:52 -07:00
Wilco Dijkstra 2a7a9d3ac8 aarch64: Use memcpy_simd as the default memcpy
Since __memcpy_simd is the fastest memcpy on almost all cores, replace
the generic memcpy with it.

(cherry picked from commit 531717afbc)
2024-04-09 19:48:23 +01:00
Sunil K Pandey d04b63770f x86_64: Optimize ffsll function code size.
Ffsll function randomly regress by ~20%, depending on how code gets
aligned in memory.  Ffsll function code size is 17 bytes.  Since default
function alignment is 16 bytes, it can load on 16, 32, 48 or 64 bytes
aligned memory.  When ffsll function load at 16, 32 or 64 bytes aligned
memory, entire code fits in single 64 bytes cache line.  When ffsll
function load at 48 bytes aligned memory, it splits in two cache line,
hence random regression.

Ffsll function size reduction from 17 bytes to 12 bytes ensures that it
will always fit in single 64 bytes cache line.

This patch fixes ffsll function random performance regression.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 9d94997b5f)
2024-02-08 10:07:26 -08:00
Noah Goldstein bb7c57219d x86: Fix incorrect scope of setting shared_per_thread [BZ# 30745]
The:

```
    if (shared_per_thread > 0 && threads > 0)
      shared_per_thread /= threads;
```

Code was accidentally moved to inside the else scope.  This doesn't
match how it was previously (before af992e7abd).

This patch fixes that by putting the division after the `else` block.

(cherry picked from commit 084fb31bc2)
2023-09-11 22:48:28 -05:00
Noah Goldstein 83ce856e77 x86: Use 3/4*sizeof(per-thread-L3) as low bound for NT threshold.
On some machines we end up with incomplete cache information. This can
make the new calculation of `sizeof(total-L3)/custom-divisor` end up
lower than intended (and lower than the prior value). So reintroduce
the old bound as a lower bound to avoid potentially regressing code
where we don't have complete information to make the decision.
Reviewed-by: DJ Delorie <dj@redhat.com>

(cherry picked from commit 8b9a0af8ca)
2023-09-11 22:48:28 -05:00
Noah Goldstein f578da1020 x86: Fix slight bug in shared_per_thread cache size calculation.
After:
```
    commit af992e7abd
    Author: Noah Goldstein <goldstein.w.n@gmail.com>
    Date:   Wed Jun 7 13:18:01 2023 -0500

        x86: Increase `non_temporal_threshold` to roughly `sizeof_L3 / 4`
```

Split `shared` (cumulative cache size) from `shared_per_thread` (cache
size per socket), the `shared_per_thread` *can* be slightly off from
the previous calculation.

Previously we added `core` even if `threads_l2` was invalid, and only
used `threads_l2` to divide `core` if it was present. The changed
version only included `core` if `threads_l2` was valid.

This change restores the old behavior if `threads_l2` is invalid by
adding the entire value of `core`.
Reviewed-by: DJ Delorie <dj@redhat.com>

(cherry picked from commit 47f7472178)
2023-09-11 22:48:28 -05:00
Noah Goldstein d4386d345e x86: Increase non_temporal_threshold to roughly sizeof_L3 / 4
Current `non_temporal_threshold` set to roughly '3/4 * sizeof_L3 /
ncores_per_socket'. This patch updates that value to roughly
'sizeof_L3 / 4`

The original value (specifically dividing the `ncores_per_socket`) was
done to limit the amount of other threads' data a `memcpy`/`memset`
could evict.

Dividing by 'ncores_per_socket', however leads to exceedingly low
non-temporal thresholds and leads to using non-temporal stores in
cases where REP MOVSB is multiple times faster.

Furthermore, non-temporal stores are written directly to main memory
so using it at a size much smaller than L3 can place soon to be
accessed data much further away than it otherwise could be. As well,
modern machines are able to detect streaming patterns (especially if
REP MOVSB is used) and provide LRU hints to the memory subsystem. This
in affect caps the total amount of eviction at 1/cache_associativity,
far below meaningfully thrashing the entire cache.

As best I can tell, the benchmarks that lead this small threshold
where done comparing non-temporal stores versus standard cacheable
stores. A better comparison (linked below) is to be REP MOVSB which,
on the measure systems, is nearly 2x faster than non-temporal stores
at the low-end of the previous threshold, and within 10% for over
100MB copies (well past even the current threshold). In cases with a
low number of threads competing for bandwidth, REP MOVSB is ~2x faster
up to `sizeof_L3`.

The divisor of `4` is a somewhat arbitrary value. From benchmarks it
seems Skylake and Icelake both prefer a divisor of `2`, but older CPUs
such as Broadwell prefer something closer to `8`. This patch is meant
to be followed up by another one to make the divisor cpu-specific, but
in the meantime (and for easier backporting), this patch settles on
`4` as a middle-ground.

Benchmarks comparing non-temporal stores, REP MOVSB, and cacheable
stores where done using:
https://github.com/goldsteinn/memcpy-nt-benchmarks

Sheets results (also available in pdf on the github):
https://docs.google.com/spreadsheets/d/e/2PACX-1vS183r0rW_jRX6tG_E90m9qVuFiMbRIJvi5VAE8yYOvEOIEEc3aSNuEsrFbuXw5c3nGboxMmrupZD7K/pubhtml
Reviewed-by: DJ Delorie <dj@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>

(cherry picked from commit af992e7abd)
2023-09-11 22:48:28 -05:00
Florian Weimer 66b1fe1d4f debug: Mark libSegFault.so as NODELETE
The signal handler installed in the ELF constructor cannot easily
be removed again (because the program may have changed handlers
in the meantime).  Mark the object as NODELETE so that the registered
handler function is never unloaded.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 23ee92deea)
2023-07-21 16:41:11 +02:00
Noah Goldstein 5ac4f45c1b x86: Fix wcsnlen-avx2 page cross length comparison [BZ #29591]
Previous implementation was adjusting length (rsi) to match
bytes (eax), but since there is no bound to length this can cause
overflow.

Fix is to just convert the byte-count (eax) to length by dividing by
sizeof (wchar_t) before the comparison.

Full check passes on x86-64 and build succeeds w/ and w/o multiarch.

(cherry picked from commit b0969fa53a)
2022-11-24 18:05:33 -08:00
Sunil K Pandey 114e3349de x86-64: Require BMI2 for avx2 functions [BZ #29611]
This patch fixes BZ #29611
2022-09-28 19:04:13 -07:00
H.J. Lu 986e7b911f x86-64: Require BMI2 for strchr-avx2.S [BZ #29611]
Since strchr-avx2.S updated by

commit 1f745ecc21
Author: noah <goldstein.w.n@gmail.com>
Date:   Wed Feb 3 00:38:59 2021 -0500

    x86-64: Refactor and improve performance of strchr-avx2.S

uses sarx:

c4 e2 72 f7 c0       	sarx   %ecx,%eax,%eax

for strchr-avx2 family functions, require BMI2 in ifunc-impl-list.c and
ifunc-avx2.h.

This fixes BZ #29611.

(cherry picked from commit 83c5b36822)
2022-09-28 19:04:00 -07:00
Andreas Schwab 6da40102c7 Add test for bug 29530
This tests for a bug that was introduced in commit edc1686af0 ("vfprintf:
Reuse work_buffer in group_number") and fixed as a side effect of commit
6caddd34bd ("Remove most vfprintf width/precision-dependent allocations
(bug 14231, bug 26211).").

(cherry picked from commit ca6466e8be)
2022-08-30 11:07:43 +02:00
Arjun Shankar f22d1cb932 support: Add xsetlocale function
(cherry picked from commit cce35a50c1)
2022-08-30 11:07:43 +02:00
Joseph Myers b2b761bc47 Fix memmove call in vfprintf-internal.c:group_number
A recent GCC mainline change introduces errors of the form:

vfprintf-internal.c: In function 'group_number':
vfprintf-internal.c:2093:15: error: 'memmove' specified bound between 9223372036854775808 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Werror=stringop-overflow=]
 2093 |               memmove (w, s, (front_ptr -s) * sizeof (CHAR_T));
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This is a genuine bug in the glibc code: s > front_ptr is always true
at this point in the code, and the intent is clearly for the
subtraction to be the other way round.  The other arguments to the
memmove call here also appear to be wrong; w and s point just *after*
the destination and source for copying the rest of the number, so the
size needs to be subtracted to get appropriate pointers for the
copying.  Adjust the memmove call to conform to the apparent intent of
the code, so fixing the -Wstringop-overflow error.

Now, if the original code were ever executed, a buffer overrun would
result.  However, I believe this code (introduced in commit
edc1686af0, "vfprintf: Reuse work_buffer
in group_number", so in glibc 2.26) is unreachable in prior glibc
releases (so there is no need for a bug in Bugzilla, no need to
consider any backports unless someone wants to build older glibc
releases with GCC 12 and no possibility of this buffer overrun
resulting in a security issue).

work_buffer is 1000 bytes / 250 wide characters.  This case is only
reachable if an initial part of the number, plus a grouped copy of the
rest of the number, fail to fit in that space; that is, if the grouped
number fails to fit in the space.  In the wide character case,
grouping is always one wide character, so even with a locale (of which
there aren't any in glibc) grouping every digit, a number would need
to occupy at least 125 wide characters to overflow, and a 64-bit
integer occupies at most 23 characters in octal including a leading 0.
In the narrow character case, the multibyte encoding of the grouping
separator would need to be at least 42 bytes to overflow, again
supposing grouping every digit, but MB_LEN_MAX is 16.  So even if we
admit the case of artificially constructed locales not shipped with
glibc, given that such a locale would need to use one of the character
sets supported by glibc, this code cannot be reached at present.  (And
POSIX only actually specifies the ' flag for grouping for decimal
output, though glibc acts on it for other bases as well.)

With binary output (if you consider use of grouping there to be
valid), you'd need a 15-byte multibyte character for overflow; I don't
know if any supported character set has such a character (if, again,
we admit constructed locales using grouping every digit and a grouping
separator chosen to have a multibyte encoding as long as possible, as
well as accepting use of grouping with binary), but given that we have
this code at all (clearly it's not *correct*, or in accordance with
the principle of avoiding arbitrary limits, to skip grouping on
running out of internal space like that), I don't think it should need
any further changes for binary printf support to go in.

On the other hand, support for large sizes of _BitInt in printf (see
the N2858 proposal) *would* require something to be done about such
arbitrary limits (presumably using dynamic allocation in printf again,
for sufficiently large _BitInt arguments only - currently only
floating-point uses dynamic allocation, and, as previously discussed,
that could actually be replaced by bounded allocation given smarter
code).

Tested with build-many-glibcs.py for aarch64-linux-gnu (GCC mainline).
Also tested natively for x86_64.

(cherry picked from commit db6c4935fa)
2022-08-30 11:07:43 +02:00
Joseph Myers 5b5dd5a43d Remove most vfprintf width/precision-dependent allocations (bug 14231, bug 26211).
The vfprintf implementation (used for all printf-family functions)
contains complicated logic to allocate internal buffers of a size
depending on the width and precision used for a format, using either
malloc or alloca depending on that size, and with consequent checks
for size overflow and allocation failure.

As noted in bug 26211, the version of that logic used when '$' plus
argument number formats are in use is missing the overflow checks,
which can result in segfaults (quite possibly exploitable, I didn't
try to work that out) when the width or precision is in the range
0x7fffffe0 through 0x7fffffff (maybe smaller values as well in the
wprintf case on 32-bit systems, when the multiplication by sizeof
(CHAR_T) can overflow).

All that complicated logic in fact appears to be useless.  As far as I
can tell, there has been no need (outside the floating-point printf
code, which does its own allocations) for allocations depending on
width or precision since commit
3e95f6602b ("Remove limitation on size
of precision for integers", Sun Sep 12 21:23:32 1999 +0000).  Thus,
this patch removes that logic completely, thereby fixing both problems
with excessive allocations for large width and precision for
non-floating-point formats, and the problem with missing overflow
checks with such allocations.  Note that this does have the
consequence that width and precision up to INT_MAX are now allowed
where previously INT_MAX / sizeof (CHAR_T) - EXTSIZ or more would have
been rejected, so could potentially expose any other overflows where
the value would previously have been rejected by those removed checks.

I believe this completely fixes bugs 14231 and 26211.

Excessive allocations are still possible in the floating-point case
(bug 21127), as are other integer or buffer overflows (see bug 26201).
This does not address the cases where a precision larger than INT_MAX
(embedded in the format string) would be meaningful without printf's
return value overflowing (when it's used with a string format, or %g
without the '#' flag, so the actual output will be much smaller), as
mentioned in bug 17829 comment 8; using size_t internally for
precision to handle that case would be complicated by struct
printf_info being a public ABI.  Nor does it address the matter of an
INT_MIN width being negated (bug 17829 comment 7; the same logic
appears a second time in the file as well, in the form of multiplying
by -1).  There may be other sources of memory allocations with malloc
in printf functions as well (bug 24988, bug 16060).  From inspection,
I think there are also integer overflows in two copies of "if ((width
-= len) < 0)" logic (where width is int, len is size_t and a very long
string could result in spurious padding being output on a 32-bit
system before printf overflows the count of output characters).

Tested for x86-64 and x86.

(cherry picked from commit 6caddd34bd)
2022-08-30 11:07:36 +02:00
Adhemerval Zanella b307c13ef3 stdio: Add tests for printf multibyte convertion leak [BZ#25691]
Checked on x86_64-linux-gnu and i686-linux-gnu.

(cherry picked from commit 910a835dc9)
2022-08-30 11:03:58 +02:00
Florian Weimer e68db8bf5a stdio: Remove memory leak from multibyte convertion [BZ#25691]
This is an updated version of a previous patch [1] with the
following changes:

  - Use compiler overflow builtins on done_add_func function.
  - Define the scratch +utstring_converted_wide_string using
    CHAR_T.
  - Added a testcase and mention the bug report.

Both default and wide printf functions might leak memory when
manipulate multibyte characters conversion depending of the size
of the input (whether __libc_use_alloca trigger or not the fallback
heap allocation).

This patch fixes it by removing the extra memory allocation on
string formatting with conversion parts.

The testcase uses input argument size that trigger memory leaks
on unpatched code (using a scratch buffer the threashold to use
heap allocation is lower).

Checked on x86_64-linux-gnu and i686-linux-gnu.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

[1] https://sourceware.org/pipermail/libc-alpha/2017-June/082098.html

(cherry picked from commit 3cc4a8367c)
2022-08-30 11:03:56 +02:00
H.J. Lu efe736ebe7 NEWS: Add a bug fix entry for BZ #28896 2022-02-18 19:14:26 -08:00
Noah Goldstein 8c21bd940e x86: Fix TEST_NAME to make it a string in tst-strncmp-rtm.c
Previously TEST_NAME was passing a function pointer. This didn't fail
because of the -Wno-error flag (to allow for overflow sizes passed
to strncmp/wcsncmp)

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit b98d0bbf74)
2022-02-18 19:14:01 -08:00
Noah Goldstein 9e69d744b3 x86: Test wcscmp RTM in the wcsncmp overflow case [BZ #28896]
In the overflow fallback strncmp-avx2-rtm and wcsncmp-avx2-rtm would
call strcmp-avx2 and wcscmp-avx2 respectively. This would have
not checks around vzeroupper and would trigger spurious
aborts. This commit fixes that.

test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass on
AVX2 machines with and without RTM.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>

(cherry picked from commit 7835d611af)
2022-02-18 19:13:56 -08:00
Noah GoldsteinandH.J. Lu 428e34eab5 x86: Fallback {str|wcs}cmp RTM in the ncmp overflow case [BZ #28896]
In the overflow fallback strncmp-avx2-rtm and wcsncmp-avx2-rtm would
call strcmp-avx2 and wcscmp-avx2 respectively. This would have
not checks around vzeroupper and would trigger spurious
aborts. This commit fixes that.

test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass on
AVX2 machines with and without RTM.

Co-authored-by: H.J. Lu <hjl.tools@gmail.com>

(cherry picked from commit c627209832)
2022-02-18 19:13:50 -08:00
H.J. Lu a486152569 string: Add a testcase for wcsncmp with SIZE_MAX [BZ #28755]
Verify that wcsncmp (L("abc"), L("abd"), SIZE_MAX) == 0.  The new test
fails without

commit ddf0992cf5
Author: Noah Goldstein <goldstein.w.n@gmail.com>
Date:   Sun Jan 9 16:02:21 2022 -0600

    x86: Fix __wcsncmp_avx2 in strcmp-avx2.S [BZ# 28755]

and

commit 7e08db3359
Author: Noah Goldstein <goldstein.w.n@gmail.com>
Date:   Sun Jan 9 16:02:28 2022 -0600

    x86: Fix __wcsncmp_evex in strcmp-evex.S [BZ# 28755]

This is for BZ #28755.

Reviewed-by: Sunil K Pandey <skpgkp2@gmail.com>

(cherry picked from commit aa5a720056)
2022-02-17 11:43:34 -08:00
H.J. Lu 28689d6255 x86-64: Test strlen and wcslen with 0 in the RSI register [BZ #28064]
commit 6f573a27b6
Author: Noah Goldstein <goldstein.w.n@gmail.com>
Date:   Wed Jun 23 01:19:34 2021 -0400

    x86-64: Add wcslen optimize for sse4.1

added wcsnlen-sse4.1 to the wcslen ifunc implementation list.  Since the
random value in the the RSI register is larger than the wide-character
string length in the existing wcslen test, it didn't trigger the wcslen
test failure.  Add a test to force 0 into the RSI register before calling
wcslen.

(cherry picked from commit a6e7c3745d)
2022-02-01 12:51:16 -08:00
Noah Goldstein 352cb39fa0 x86: Remove wcsnlen-sse4_1 from wcslen ifunc-impl-list [BZ #28064]
The following commit

commit 6f573a27b6
Author: Noah Goldstein <goldstein.w.n@gmail.com>
Date:   Wed Jun 23 01:19:34 2021 -0400

    x86-64: Add wcslen optimize for sse4.1

Added wcsnlen-sse4.1 to the wcslen ifunc implementation list and did
not add wcslen-sse4.1 to wcslen ifunc implementation list. This commit
fixes that by removing wcsnlen-sse4.1 from the wcslen ifunc
implementation list and adding wcslen-sse4.1 to the ifunc
implementation list.

Testing:
test-wcslen.c, test-rsi-wcslen.c, and test-rsi-strlen.c are passing as
well as all other tests in wcsmbs and string.

Signed-off-by: Noah Goldstein <goldstein.w.n@gmail.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 0679442def)
2022-02-01 12:51:09 -08:00
H.J. Lu 5d94c86a47 x86: Black list more Intel CPUs for TSX [BZ #27398]
Disable TSX and enable RTM_ALWAYS_ABORT for Intel CPUs listed in:

https://www.intel.com/content/www/us/en/support/articles/000059422/processors.html

This fixes BZ #27398.

Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
(cherry picked from commit 1e000d3d33)
2022-02-01 07:38:16 -08:00
H.J. Lu 7aac95739a x86: Check RTM_ALWAYS_ABORT for RTM [BZ #28033]
From

https://www.intel.com/content/www/us/en/support/articles/000059422/processors.html

* Intel TSX will be disabled by default.
* The processor will force abort all Restricted Transactional Memory (RTM)
  transactions by default.
* A new CPUID bit CPUID.07H.0H.EDX[11](RTM_ALWAYS_ABORT) will be enumerated,
  which is set to indicate to updated software that the loaded microcode is
  forcing RTM abort.
* On processors that enumerate support for RTM, the CPUID enumeration bits
  for Intel TSX (CPUID.07H.0H.EBX[11] and CPUID.07H.0H.EBX[4]) continue to
  be set by default after microcode update.
* Workloads that were benefited from Intel TSX might experience a change
  in performance.
* System software may use a new bit in Model-Specific Register (MSR) 0x10F
  TSX_FORCE_ABORT[TSX_CPUID_CLEAR] functionality to clear the Hardware Lock
  Elision (HLE) and RTM bits to indicate to software that Intel TSX is
  disabled.

1. Add RTM_ALWAYS_ABORT to CPUID features.
2. Set RTM usable only if RTM_ALWAYS_ABORT isn't set.  This skips the
string/tst-memchr-rtm etc. testcases on the affected processors, which
always fail after a microcde update.
3. Check RTM feature, instead of usability, against /proc/cpuinfo.

This fixes BZ #28033.

(cherry picked from commit ea8e465a6b)
2022-02-01 07:38:09 -08:00
H.J. Lu a0ed5893fc NEWS: Add a bug fix entry for BZ #27974 2022-01-27 16:27:20 -08:00
Noah Goldstein ac1d6f25d6 String: Add overflow tests for strnlen, memchr, and strncat [BZ #27974]
This commit adds tests for a bug in the wide char variant of the
functions where the implementation may assume that maxlen for wcsnlen
or n for wmemchr/strncat will not overflow when multiplied by
sizeof(wchar_t).

These tests show the following implementations failing on x86_64:

wcsnlen-sse4_1
wcsnlen-avx2

wmemchr-sse2
wmemchr-avx2

strncat would fail as well if it where on a system that prefered
either of the wcsnlen implementations that failed as it relies on
wcsnlen.

Signed-off-by: Noah Goldstein <goldstein.w.n@gmail.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit da5a6fba0f)
2022-01-27 16:26:26 -08:00
Noah Goldstein f9fe740ec4 x86: Optimize strlen-evex.S
No bug. This commit optimizes strlen-evex.S. The
optimizations are mostly small things but they add up to roughly
10-30% performance improvement for strlen. The results for strnlen are
bit more ambiguous. test-strlen, test-strnlen, test-wcslen, and
test-wcsnlen are all passing.

Signed-off-by: Noah Goldstein <goldstein.w.n@gmail.com>
(cherry picked from commit 4ba6558684)
2022-01-27 16:26:21 -08:00
Noah Goldstein dd92fa3029 x86: Fix overflow bug in wcsnlen-sse4_1 and wcsnlen-avx2 [BZ #27974]
This commit fixes the bug mentioned in the previous commit.

The previous implementations of wmemchr in these files relied
on maxlen * sizeof(wchar_t) which was not guranteed by the standard.

The new overflow tests added in the previous commit now
pass (As well as all the other tests).

Signed-off-by: Noah Goldstein <goldstein.w.n@gmail.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit a775a7a3eb)
2022-01-27 16:26:15 -08:00
Noah Goldstein 2599967449 x86-64: Add wcslen optimize for sse4.1
No bug. This comment adds the ifunc / build infrastructure
necessary for wcslen to prefer the sse4.1 implementation
in strlen-vec.S. test-wcslen.c is passing.

Signed-off-by: Noah Goldstein <goldstein.w.n@gmail.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 6f573a27b6)
2022-01-27 16:26:10 -08:00
H.J. Lu ccf4e0edde x86-64: Move strlen.S to multiarch/strlen-vec.S
Since strlen.S contains SSE2 version of strlen/strnlen and SSE4.1
version of wcslen/wcsnlen, move strlen.S to multiarch/strlen-vec.S
and include multiarch/strlen-vec.S from SSE2 and SSE4.1 variants.
This also removes the unused symbols, __GI___strlen_sse2 and
__GI___wcsnlen_sse4_1.

(cherry picked from commit a0db678071)
2022-01-27 16:26:04 -08:00
Alice Xu 3cee1ddad2 x86-64: Fix an unknown vector operation in memchr-evex.S
An unknown vector operation occurred in commit 2a76821c30. Fixed it
by using "ymm{k1}{z}" but not "ymm {k1} {z}".

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 6ea916adfa)
2022-01-27 16:25:58 -08:00
Noah Goldstein cba2fbe17f x86: Optimize memchr-evex.S
No bug. This commit optimizes memchr-evex.S. The optimizations include
replacing some branches with cmovcc, avoiding some branches entirely
in the less_4x_vec case, making the page cross logic less strict,
saving some ALU in the alignment process, and most importantly
increasing ILP in the 4x loop. test-memchr, test-rawmemchr, and
test-wmemchr are all passing.

Signed-off-by: Noah Goldstein <goldstein.w.n@gmail.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 2a76821c30)
2022-01-27 16:25:53 -08:00
Noah Goldstein 0a3b2efccc x86: Optimize strlen-avx2.S
No bug. This commit optimizes strlen-avx2.S. The optimizations are
mostly small things but they add up to roughly 10-30% performance
improvement for strlen. The results for strnlen are bit more
ambiguous. test-strlen, test-strnlen, test-wcslen, and test-wcsnlen
are all passing.

Signed-off-by: Noah Goldstein <goldstein.w.n@gmail.com>
(cherry picked from commit aaa23c3507)
2022-01-27 16:25:48 -08:00
Noah Goldstein c51e9501c2 x86: Fix overflow bug with wmemchr-sse2 and wmemchr-avx2 [BZ #27974]
This commit fixes the bug mentioned in the previous commit.

The previous implementations of wmemchr in these files relied
on n * sizeof(wchar_t) which was not guranteed by the standard.

The new overflow tests added in the previous commit now
pass (As well as all the other tests).

Signed-off-by: Noah Goldstein <goldstein.w.n@gmail.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 645a158978)
2022-01-27 16:25:42 -08:00
Noah Goldstein 5c38877df5 x86: Optimize memchr-avx2.S
No bug. This commit optimizes memchr-avx2.S. The optimizations include
replacing some branches with cmovcc, avoiding some branches entirely
in the less_4x_vec case, making the page cross logic less strict,
asaving a few instructions the in loop return loop. test-memchr,
test-rawmemchr, and test-wmemchr are all passing.

Signed-off-by: Noah Goldstein <goldstein.w.n@gmail.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit acfd088a19)
2022-01-27 16:25:37 -08:00
H.J. Lu 8fa2afcec3 test-strnlen.c: Check that strnlen won't go beyond the maximum length
Place strings ending at page boundary without the null byte.  If an
implementation goes beyond EXP_LEN, it will trigger the segfault.

(cherry picked from commit cb882b21b6)
2022-01-27 16:25:31 -08:00
H.J. Lu 0717959eb3 test-strnlen.c: Initialize wchar_t string with wmemset [BZ #27655]
Use wmemset to initialize wchar_t string.

(cherry picked from commit 86859b7e58)
2022-01-27 16:25:26 -08:00
H.J. Lu 3fc179e2b2 x86-64: Require BMI2 for __strlen_evex and __strnlen_evex
Since __strlen_evex and __strnlen_evex added by

commit 1fd8c163a8
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri Mar 5 06:24:52 2021 -0800

    x86-64: Add ifunc-avx2.h functions with 256-bit EVEX

use sarx:

c4 e2 6a f7 c0       	sarx   %edx,%eax,%eax

require BMI2 for __strlen_evex and __strnlen_evex in ifunc-impl-list.c.
ifunc-avx2.h already requires BMI2 for EVEX implementation.

(cherry picked from commit 55bf411b45)
2022-01-27 16:25:20 -08:00
H.J. Lu c3535cb6cd NEWS: Add a bug fix entry for BZ #27457 2022-01-27 12:25:41 -08:00
Sunil K Pandey aff5eec9ce x86-64: Fix ifdef indentation in strlen-evex.S
Fix some indentations of ifdef in file strlen-evex.S which are off by 1
and confusing to read.

(cherry picked from commit 595c22ecd8)
2022-01-27 12:07:11 -08:00
H.J. Lu 7056607e6a x86-64: Use ZMM16-ZMM31 in AVX512 memmove family functions
Update ifunc-memmove.h to select the function optimized with AVX512
instructions using ZMM16-ZMM31 registers to avoid RTM abort with usable
AVX512VL since VZEROUPPER isn't needed at function exit.

(cherry picked from commit e4fda46310)
2022-01-27 12:07:11 -08:00
H.J. Lu a54fae8df4 x86-64: Use ZMM16-ZMM31 in AVX512 memset family functions
Update ifunc-memset.h/ifunc-wmemset.h to select the function optimized
with AVX512 instructions using ZMM16-ZMM31 registers to avoid RTM abort
with usable AVX512VL and AVX512BW since VZEROUPPER isn't needed at
function exit.

(cherry picked from commit 4e2d8f3527)
2022-01-27 12:07:11 -08:00
H.J. Lu 674137c9b0 x86: Add string/memory function tests in RTM region
At function exit, AVX optimized string/memory functions have VZEROUPPER
which triggers RTM abort.   When such functions are called inside a
transactionally executing RTM region, RTM abort causes severe performance
degradation.  Add tests to verify that string/memory functions won't
cause RTM abort in RTM region.

(cherry picked from commit 4bd660be40)
2022-01-27 12:07:11 -08:00
H.J. Lu 5be8a84721 x86-64: Add AVX optimized string/memory functions for RTM
Since VZEROUPPER triggers RTM abort while VZEROALL won't, select AVX
optimized string/memory functions with

	xtest
	jz	1f
	vzeroall
	ret
1:
	vzeroupper
	ret

at function exit on processors with usable RTM, but without 256-bit EVEX
instructions to avoid VZEROUPPER inside a transactionally executing RTM
region.

(cherry picked from commit 7ebba91361)
2022-01-27 12:07:11 -08:00
H.J. Lu 757d90ff37 x86-64: Add memcmp family functions with 256-bit EVEX
Update ifunc-memcmp.h to select the function optimized with 256-bit EVEX
instructions using YMM16-YMM31 registers to avoid RTM abort with usable
AVX512VL, AVX512BW and MOVBE since VZEROUPPER isn't needed at function
exit.

(cherry picked from commit 91264fe357)
2022-01-27 12:07:11 -08:00
H.J. Lu 9650d04fb6 x86-64: Add memset family functions with 256-bit EVEX
Update ifunc-memset.h/ifunc-wmemset.h to select the function optimized
with 256-bit EVEX instructions using YMM16-YMM31 registers to avoid RTM
abort with usable AVX512VL and AVX512BW since VZEROUPPER isn't needed at
function exit.

(cherry picked from commit 1b968b6b9b)
2022-01-27 12:07:11 -08:00
H.J. Lu 2f4a98ab17 x86-64: Add memmove family functions with 256-bit EVEX
Update ifunc-memmove.h to select the function optimized with 256-bit EVEX
instructions using YMM16-YMM31 registers to avoid RTM abort with usable
AVX512VL since VZEROUPPER isn't needed at function exit.

(cherry picked from commit 63ad43566f)
2022-01-27 12:07:11 -08:00
H.J. Lu c90c70b8f9 x86-64: Add strcpy family functions with 256-bit EVEX
Update ifunc-strcpy.h to select the function optimized with 256-bit EVEX
instructions using YMM16-YMM31 registers to avoid RTM abort with usable
AVX512VL and AVX512BW since VZEROUPPER isn't needed at function exit.

(cherry picked from commit 525bc2a32c)
2022-01-27 12:07:11 -08:00
H.J. Lu c671b231cf x86-64: Add ifunc-avx2.h functions with 256-bit EVEX
Update ifunc-avx2.h, strchr.c, strcmp.c, strncmp.c and wcsnlen.c to
select the function optimized with 256-bit EVEX instructions using
YMM16-YMM31 registers to avoid RTM abort with usable AVX512VL, AVX512BW
and BMI2 since VZEROUPPER isn't needed at function exit.

For strcmp/strncmp, prefer AVX2 strcmp/strncmp if Prefer_AVX2_STRCMP
is set.

(cherry picked from commit 1fd8c163a8)
2022-01-27 12:07:11 -08:00
H.J. Lu be07b3e059 x86: Set Prefer_No_VZEROUPPER and add Prefer_AVX2_STRCMP
1. Set Prefer_No_VZEROUPPER if RTM is usable to avoid RTM abort triggered
by VZEROUPPER inside a transactionally executing RTM region.
2. Since to compare 2 32-byte strings, 256-bit EVEX strcmp requires 2
loads, 3 VPCMPs and 2 KORDs while AVX2 strcmp requires 1 load, 2 VPCMPEQs,
1 VPMINU and 1 VPMOVMSKB, AVX2 strcmp is faster than EVEX strcmp.  Add
Prefer_AVX2_STRCMP to prefer AVX2 strcmp family functions.

(cherry picked from commit 1da50d4bda)
2022-01-27 12:07:11 -08:00
H.J. Lu 2f3fb944b3 NEWS: Add a bug fix entry for BZ #28755 2022-01-27 07:28:12 -08:00
Noah Goldstein be6fb78a1f x86: Fix __wcsncmp_avx2 in strcmp-avx2.S [BZ# 28755]
Fixes [BZ# 28755] for wcsncmp by redirecting length >= 2^56 to
__wcscmp_avx2. For x86_64 this covers the entire address range so any
length larger could not possibly be used to bound `s1` or `s2`.

test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass.

Signed-off-by: Noah Goldstein <goldstein.w.n@gmail.com>
(cherry picked from commit ddf0992cf5)
2022-01-27 07:28:12 -08:00
H.J. Lu 646ec4ebe5 NEWS: Add a bug fix entry for BZ #24794 2022-01-27 07:28:12 -08:00
Tulio Magno Quites Machado Filho edceb7f520 test-container: Install with $(all-subdirs) [BZ #24794]
Whenever a sub-make is created, it inherits the variable subdirs from its
parent.  This is also true when make check is called with a restricted
list of subdirs.  In this scenario, make install is executed "partially"
and testroot.pristine ends up with an incomplete installation.

	[BZ #24794]
	* Makefile (testroot.pristine/install.stamp): Pass
	subdirs='$(all-subdirs)' to make install.

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 35e038c1d2)
2022-01-27 07:28:12 -08:00
Siddhesh Poyarekar 2c9083f93d Fix SXID_ERASE behavior in setuid programs (BZ #27471)
When parse_tunables tries to erase a tunable marked as SXID_ERASE for
setuid programs, it ends up setting the envvar string iterator
incorrectly, because of which it may parse the next tunable
incorrectly.  Given that currently the implementation allows malformed
and unrecognized tunables pass through, it may even allow SXID_ERASE
tunables to go through.

This change revamps the SXID_ERASE implementation so that:

- Only valid tunables are written back to the tunestr string, because
  of which children of SXID programs will only inherit a clean list of
  identified tunables that are not SXID_ERASE.

- Unrecognized tunables get scrubbed off from the environment and
  subsequently from the child environment.

- This has the side-effect that a tunable that is not identified by
  the setxid binary, will not be passed on to a non-setxid child even
  if the child could have identified that tunable.  This may break
  applications that expect this behaviour but expecting such tunables
  to cross the SXID boundary is wrong.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>

(cherry picked from commit 2ed18c5b53)
2021-04-14 11:08:02 +05:30
Siddhesh Poyarekar dcfcb1b208 Enhance setuid-tunables test
Instead of passing GLIBC_TUNABLES via the environment, pass the
environment variable from parent to child.  This allows us to test
multiple variables to ensure better coverage.

The test list currently only includes the case that's already being
tested.  More tests will be added later.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>

(cherry picked from commit 061fe3f8ad)
2021-04-14 11:07:47 +05:30
Siddhesh Poyarekar 1927d02d19 tst-env-setuid: Use support_capture_subprogram_self_sgid
Use the support_capture_subprogram_self_sgid to spawn an sgid child.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>

(cherry picked from commit ca33528106)
2021-04-14 11:07:47 +05:30
Siddhesh Poyarekar 2c23a4d7e0 support: Add capability to fork an sgid child
Add a new function support_capture_subprogram_self_sgid that spawns an
sgid child of the running program with its own image and returns the
exit code of the child process.  This functionality is used by at
least three tests in the testsuite at the moment, so it makes sense to
consolidate.

There is also a new function support_subprogram_wait which should
provide simple system() like functionality that does not set up file
actions.  This is useful in cases where only the return code of the
spawned subprocess is interesting.

This patch also ports tst-secure-getenv to this new function.  A
subsequent patch will port other tests.  This also brings an important
change to tst-secure-getenv behaviour.  Now instead of succeeding, the
test fails as UNSUPPORTED if it is unable to spawn a setgid child,
which is how it should have been in the first place.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>

(cherry picked from commit 716a3bdc41)
2021-04-14 11:07:45 +05:30
Siddhesh Poyarekar 23d0e97fe5 support: Typo and formatting fixes
- Add a newline to the end of error messages in transfer().
- Fixed the name of support_subprocess_init().

(cherry picked from commit 95c68080a3)
2021-04-14 11:06:05 +05:30
Siddhesh Poyarekar ad25ea0c47 support: Pass environ to child process
Pass environ to posix_spawn so that the child process can inherit
environment of the test.

(cherry picked from commit e958490f8c)
2021-04-14 11:06:05 +05:30
DJ Delorie e9c0d7d7ff nscd: Fix double free in netgroupcache [BZ #27462]
In commit 745664bd79 a use-after-free
was fixed, but this led to an occasional double-free.  This patch
tracks the "live" allocation better.

Tested manually by a third party.

Related: RHBZ 1927877

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit dca565886b)
2021-03-08 15:42:15 +05:30
Florian Weimer a9acd88a5d gconv: Fix assertion failure in ISO-2022-JP-3 module (bug 27256)
The conversion loop to the internal encoding does not follow
the interface contract that __GCONV_FULL_OUTPUT is only returned
after the internal wchar_t buffer has been filled completely.  This
is enforced by the first of the two asserts in iconv/skeleton.c:

	      /* We must run out of output buffer space in this
		 rerun.  */
	      assert (outbuf == outerr);
	      assert (nstatus == __GCONV_FULL_OUTPUT);

This commit solves this issue by queuing a second wide character
which cannot be written immediately in the state variable, like
other converters already do (e.g., BIG5-HKSCS or TSCII).

Reported-by: Tavis Ormandy <taviso@gmail.com>
(cherry picked from commit 7d88c6142c)
2021-01-27 15:22:18 +01:00
H.J. Lu 1864775abc x86: Check IFUNC definition in unrelocated executable [BZ #20019]
Calling an IFUNC function defined in unrelocated executable also leads to
segfault.  Issue a fatal error message when calling IFUNC function defined
in the unrelocated executable from a shared library.

On x86, ifuncmain6pie failed with:

[hjl@gnu-cfl-2 build-i686-linux]$ ./elf/ifuncmain6pie --direct
./elf/ifuncmain6pie: IFUNC symbol 'foo' referenced in '/export/build/gnu/tools-build/glibc-32bit/build-i686-linux/elf/ifuncmod6.so' is defined in the executable and creates an unsatisfiable circular dependency.
[hjl@gnu-cfl-2 build-i686-linux]$ readelf -rW elf/ifuncmod6.so | grep foo
00003ff4  00000706 R_386_GLOB_DAT         0000400c   foo_ptr
00003ff8  00000406 R_386_GLOB_DAT         00000000   foo
0000400c  00000401 R_386_32               00000000   foo
[hjl@gnu-cfl-2 build-i686-linux]$

Remove non-JUMP_SLOT relocations against foo in ifuncmod6.so, which
trigger the circular IFUNC dependency, and build ifuncmain6pie with
-Wl,-z,lazy.

(cherry picked from commits 6ea5b57afa
 and 7137d682eb)
2021-01-13 14:30:42 -08:00
H.J. Lu 420ade1f64 x86: Set header.feature_1 in TCB for always-on CET [BZ #27177]
Update dl_cet_check() to set header.feature_1 in TCB when both IBT and
SHSTK are always on.

(cherry picked from commit 2ef23b5205)
2021-01-13 09:24:35 -08:00
H.J. Lu 8493ba72b1 x86-64: Avoid rep movsb with short distance [BZ #27130]
When copying with "rep movsb", if the distance between source and
destination is N*4GB + [1..63] with N >= 0, performance may be very
slow.  This patch updates memmove-vec-unaligned-erms.S for AVX and
AVX512 versions with the distance in RCX:

	cmpl	$63, %ecx
	// Don't use "rep movsb" if ECX <= 63
	jbe	L(Don't use rep movsb")
	Use "rep movsb"

Benchtests data with bench-memcpy, bench-memcpy-large, bench-memcpy-random
and bench-memcpy-walk on Skylake, Ice Lake and Tiger Lake show that its
performance impact is within noise range as "rep movsb" is only used for
data size >= 4KB.

(cherry picked from commit 3ec5d83d2a)
2021-01-12 07:01:34 -08:00
Szabolcs Nagy a3c78954ee aarch64: Fix DT_AARCH64_VARIANT_PCS handling [BZ #26798]
The variant PCS support was ineffective because in the common case
linkmap->l_mach.plt == 0 but then the symbol table flags were ignored
and normal lazy binding was used instead of resolving the relocs early.
(This was a misunderstanding about how GOT[1] is setup by the linker.)

In practice this mainly affects SVE calls when the vector length is
more than 128 bits, then the top bits of the argument registers get
clobbered during lazy binding.

Fixes bug 26798.

(cherry picked from commit 558251bd87)
2020-11-04 12:26:02 +00:00
Wilco Dijkstra 28ff0f650c AArch64: Use __memcpy_simd on Neoverse N2/V1
Add CPU detection of Neoverse N2 and Neoverse V1, and select __memcpy_simd as
the memcpy/memmove ifunc.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit e11ed9d2b4)
2020-10-14 14:31:24 +01:00
Wilco Dijkstra be3eaffd5a [AArch64] Improve integer memcpy
Further optimize integer memcpy.  Small cases now include copies up
to 32 bytes.  64-128 byte copies are split into two cases to improve
performance of 64-96 byte copies.  Comments have been rewritten.

(cherry picked from commit 7000651327)
2020-10-12 18:29:42 +01:00
Krzysztof Koch c969e84e0c aarch64: Increase small and medium cases for __memcpy_generic
Increase the upper bound on medium cases from 96 to 128 bytes.
Now, up to 128 bytes are copied unrolled.

Increase the upper bound on small cases from 16 to 32 bytes so that
copies of 17-32 bytes are not impacted by the larger medium case.

Benchmarking:
The attached figures show relative timing difference with respect
to 'memcpy_generic', which is the existing implementation.
'memcpy_med_128' denotes the the version of memcpy_generic with
only the medium case enlarged. The 'memcpy_med_128_small_32' numbers
are for the version of memcpy_generic submitted in this patch, which
has both medium and small cases enlarged. The figures were generated
using the script from:
https://www.sourceware.org/ml/libc-alpha/2019-10/msg00563.html

Depending on the platform, the performance improvement in the
bench-memcpy-random.c benchmark ranges from 6% to 20% between
the original and final version of memcpy.S

Tested against GLIBC testsuite and randomized tests.

(cherry picked from commit b9f145df85)
2020-10-12 18:29:42 +01:00
Wilco Dijkstra 53d501d6e9 AArch64: Rename IS_ARES to IS_NEOVERSE_N1
Rename IS_ARES to IS_NEOVERSE_N1 since that is a bit clearer.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 0f6278a879)
2020-10-12 18:29:38 +01:00
Wilco Dijkstra 64458aabeb AArch64: Improve backwards memmove performance
On some microarchitectures performance of the backwards memmove improves if
the stores use STR with decreasing addresses.  So change the memmove loop
in memcpy_advsimd.S to use 2x STR rather than STP.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit bd394d131c)
2020-10-12 18:28:42 +01:00
Wilco Dijkstra 58c6a7ae53 AArch64: Add optimized Q-register memcpy
Add a new memcpy using 128-bit Q registers - this is faster on modern
cores and reduces codesize.  Similar to the generic memcpy, small cases
include copies up to 32 bytes.  64-128 byte copies are split into two
cases to improve performance of 64-96 byte copies.  Large copies align
the source rather than the destination.

bench-memcpy-random is ~9% faster than memcpy_falkor on Neoverse N1,
so make this memcpy the default on N1 (on Centriq it is 15% faster than
memcpy_falkor).

Passes GLIBC regression tests.

Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
(cherry picked from commit 4a733bf375)
2020-10-12 18:28:34 +01:00
Wilco Dijkstra 2fb2098c24 AArch64: Align ENTRY to a cacheline
Given almost all uses of ENTRY are for string/memory functions,
align ENTRY to a cacheline to simplify things.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 34f0d01d5e)
2020-10-12 16:56:18 +01:00
H.J. Lu 83aaa17144 NEWS: Mention BZ 25933 fix 2020-07-04 09:59:10 -07:00
Sunil K Pandey 0a4d3eac67 Fix avx2 strncmp offset compare condition check [BZ #25933]
strcmp-avx2.S: In avx2 strncmp function, strings are compared in
chunks of 4 vector size(i.e. 32x4=128 byte for avx2). After first 4
vector size comparison, code must check whether it already passed
the given offset. This patch implement avx2 offset check condition
for strncmp function, if both string compare same for first 4 vector
size.

(cherry picked from commit 75870237ff)
2020-07-04 09:53:28 -07:00
Florian Weimer b0d3f7858c nss_compat: internal_end*ent may clobber errno, hiding ERANGE [BZ #25976]
During cleanup, before returning from get*_r functions, the end*ent
calls must not change errno.  Otherwise, an ERANGE error from the
underlying implementation can be hidden, causing unexpected lookup
failures.  This commit introduces an internal_end*ent_noerror
function which saves and restore errno, and marks the original
internal_end*ent function as warn_unused_result, so that it is used
only in contexts were errors from it can be handled explicitly.

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 790b8dda44)
2020-05-19 16:33:04 +02:00
Andreas Schwab a318448f7a Fix array overflow in backtrace on PowerPC (bug 25423)
When unwinding through a signal frame the backtrace function on PowerPC
didn't check array bounds when storing the frame address.  Fixes commit
d400dcac5e ("PowerPC: fix backtrace to handle signal trampolines").

(cherry picked from commit d937694059)
2020-03-18 13:41:55 -04:00
Andreas Schwab 9aaebaf805 Fix use-after-free in glob when expanding ~user (bug 25414)
The value of `end_name' points into the value of `dirname', thus don't
deallocate the latter before the last use of the former.

(cherry picked from commit ddc650e9b3)
2020-03-17 21:51:11 -04:00
Florian Weimer 8e5d591b10 math/test-sinl-pseudo: Use stack protector only if available
This fixes commit 9333498794 ("Avoid ldbl-96 stack
corruption from range reduction of pseudo-zero (bug 25487).").

(cherry picked from commit c10acd4026)
2020-03-15 17:33:57 -04:00
Joseph Myers 0474cd5de6 Avoid ldbl-96 stack corruption from range reduction of pseudo-zero (bug 25487).
Bug 25487 reports stack corruption in ldbl-96 sinl on a pseudo-zero
argument (an representation where all the significand bits, including
the explicit high bit, are zero, but the exponent is not zero, which
is not a valid representation for the long double type).

Although this is not a valid long double representation, existing
practice in this area (see bug 4586, originally marked invalid but
subsequently fixed) is that we still seek to avoid invalid memory
accesses as a result, in case of programs that treat arbitrary binary
data as long double representations, although the invalid
representations of the ldbl-96 format do not need to be consistently
handled the same as any particular valid representation.

This patch makes the range reduction detect pseudo-zero and unnormal
representations that would otherwise go to __kernel_rem_pio2, and
returns a NaN for them instead of continuing with the range reduction
process.  (Pseudo-zero and unnormal representations whose unbiased
exponent is less than -1 have already been safely returned from the
function before this point without going through the rest of range
reduction.)  Pseudo-zero representations would previously result in
the value passed to __kernel_rem_pio2 being all-zero, which is
definitely unsafe; unnormal representations would previously result in
a value passed whose high bit is zero, which might well be unsafe
since that is not a form of input expected by __kernel_rem_pio2.

Tested for x86_64.

(cherry picked from commit 9333498794)
2020-03-15 17:33:26 -04:00
Florian Weimer e0a0770bb4 riscv: Do not use __has_include__
The user-visible preprocessor construct is called __has_include.

(cherry picked from commit 28dd393922)
2020-01-21 13:42:47 +01:00
Florian Weimer ea6f2c3174 misc/test-errno-linux: Handle EINVAL from quotactl
In commit 3dd4d40b420846dd35869ccc8f8627feef2cff32 ("xfs: Sanity check
flags of Q_XQUOTARM call"), Linux 5.4 added checking for the flags
argument, causing the test to fail due to too restrictive test
expectations.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 1f7525d924)
2019-12-05 17:30:40 +01:00
Kamlesh Kumar 42786ee476 <string.h>: Define __CORRECT_ISO_CPP_STRING_H_PROTO for Clang [BZ #25232]
Without the asm redirects, strchr et al. are not const-correct.

libc++ has a wrapper header that works with and without
__CORRECT_ISO_CPP_STRING_H_PROTO (using a Clang extension).  But when
Clang is used with libstdc++ or just C headers, the overloaded functions
with the correct types are not declared.

This change does not impact current GCC (with libstdc++ or libc++).

(cherry picked from commit 953ceff17a)
2019-12-05 16:55:19 +01:00
Florian Weimer 0b4c3e1e0b x86: Assume --enable-cet if GCC defaults to CET [BZ #25225]
This links in CET support if GCC defaults to CET.  Otherwise, __CET__
is defined, yet CET functionality is not compiled and linked into the
dynamic loader, resulting in a linker failure due to undefined
references to _dl_cet_check and _dl_open_check.

(cherry picked from commit 9fb8139079)
2019-12-03 21:08:49 +01:00
Florian Weimer 44a61d4589 libio: Disable vtable validation for pre-2.1 interposed handles [BZ #25203]
Commit c402355dfa ("libio: Disable
vtable validation in case of interposition [BZ #23313]") only covered
the interposable glibc 2.1 handles, in libio/stdfiles.c.  The
parallel code in libio/oldstdfiles.c needs similar detection logic.

Fixes (again) commit db3476aff1
("libio: Implement vtable verification [BZ #20191]").

Change-Id: Ief6f9f17e91d1f7263421c56a7dc018f4f595c21
(cherry picked from commit cb61630ed7)
2019-11-28 14:17:27 +01:00
Florian Weimer 5422ac2d08 Update NEWS for CVE-2019-19126 2019-11-22 13:45:03 +01:00
Marcin Kościelnicki 2626b15e88 rtld: Check __libc_enable_secure before honoring LD_PREFER_MAP_32BIT_EXEC (CVE-2019-19126) [BZ #25204]
The problem was introduced in glibc 2.23, in commit
b9eb92ab05
("Add Prefer_MAP_32BIT_EXEC to map executable pages with MAP_32BIT").

(cherry picked from commit d5dfad4326)
Change-Id: Ib782573b4623ee3edfa9f98ad62f69b9d8edcb27
2019-11-22 13:11:36 +01:00
Florian Weimer 845278f2c6 Linux: Use in-tree copy of SO_ constants for !__USE_MISC [BZ #24532]
The kernel changes for a 64-bit time_t on 32-bit architectures
resulted in <asm/socket.h> indirectly including <linux/posix_types.h>.
The latter is not namespace-clean for the POSIX version of
<sys/socket.h>.

This issue has persisted across several Linux releases, so this commit
creates our own copy of the SO_* definitions for !__USE_MISC mode.

The new test socket/tst-socket-consts ensures that the copy is
consistent with the kernel definitions (which vary across
architectures).  The test is tricky to get right because CPPFLAGS
includes include/libc-symbols.h, which in turn defines _GNU_SOURCE
unconditionally.

Tested with build-many-glibcs.py.  I verified that a discrepancy in
the definitions actually results in a failure of the
socket/tst-socket-consts test.

(cherry picked from commit 7854ebf8ed)
2019-11-18 18:16:03 +01:00
DJ Delorie a683450f26 Base max_fast on alignment, not width, of bins (Bug 24903)
set_max_fast sets the "impossibly small" value based on,
eventually, MALLOC_ALIGNMENT.  The comparisons for the smallest
chunk used is, eventually, MIN_CHUNK_SIZE.  Note that i386
is the only platform where these are the same, so a smallest
chunk *would* be put in a no-fastbins fastbin.

This change calculates the "impossibly small" value
based on MIN_CHUNK_SIZE instead, so that we can know it will
always be impossibly small.

(cherry picked from commit ff12e0fb91)
2019-11-18 16:10:51 +01:00
Florian Weimer 1b96d1d90b malloc: Various cleanups for malloc/tst-mxfast
(cherry picked from commit f9769a2397)
2019-11-18 16:10:11 +01:00
DJ Delorie 4618f1ffba Add glibc.malloc.mxfast tunable
* elf/dl-tunables.list: Add glibc.malloc.mxfast.
* manual/tunables.texi: Document it.
* malloc/malloc.c (do_set_mxfast): New.
(__libc_mallopt): Call it.
* malloc/arena.c: Add mxfast tunable.
* malloc/tst-mxfast.c: New.
* malloc/Makefile: Add it.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit c48d92b430)
2019-11-18 16:08:44 +01:00
Niklas Hambüchen c6e4c3198b malloc: Fix missing accounting of top chunk in malloc_info [BZ #24026]
Fixes `<total type="rest" size="..."> incorrectly showing as 0 most
of the time.

The rest value being wrong is significant because to compute the
actual amount of memory handed out via malloc, the user must subtract
it from <system type="current" size="...">. That result being wrong
makes investigating memory fragmentation issues like
<https://bugzilla.redhat.com/show_bug.cgi?id=843478> close to
impossible.

(cherry picked from commit b6d2c4475d)
2019-11-18 16:04:03 +01:00
Florian Weimer a0a551d259 malloc: Remove unwanted leading whitespace in malloc_info [BZ #24867]
It was introduced in commit 6c8dbf00f5
("Reformat malloc to gnu style.").

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit b0f6679bcd)
2019-11-18 16:02:10 +01:00
Wilco Dijkstra 0ad788face Small tcache improvements
Change the tcache->counts[] entries to uint16_t - this removes
the limit set by char and allows a larger tcache.  Remove a few
redundant asserts.

bench-malloc-thread with 4 threads is ~15% faster on Cortex-A72.

Reviewed-by: DJ Delorie <dj@redhat.com>

	* malloc/malloc.c (MAX_TCACHE_COUNT): Increase to UINT16_MAX.
	(tcache_put): Remove redundant assert.
	(tcache_get): Remove redundant asserts.
	(__libc_malloc): Check tcache count is not zero.
	* manual/tunables.texi (glibc.malloc.tcache_count): Update maximum.

(cherry picked from commit 1f50f2ad85)
2019-11-18 15:55:12 +01:00
Joseph Myers 9a3ff995bd Fix assertion in malloc.c:tcache_get.
One of the warnings that appears with -Wextra is "ordered comparison
of pointer with integer zero" in malloc.c:tcache_get, for the
assertion:

  assert (tcache->entries[tc_idx] > 0);

Indeed, a "> 0" comparison does not make sense for
tcache->entries[tc_idx], which is a pointer.  My guess is that
tcache->counts[tc_idx] is what's intended here, and this patch changes
the assertion accordingly.

Tested for x86_64.

	* malloc/malloc.c (tcache_get): Compare tcache->counts[tc_idx]
	with 0, not tcache->entries[tc_idx].

(cherry picked from commit 77dc0d8643)
2019-11-18 15:45:39 +01:00
Stefan Liebler 8646009efd Fix alignment of TLS variables for tls variant TLS_TCB_AT_TP [BZ #23403]
The alignment of TLS variables is wrong if accessed from within a thread
for architectures with tls variant TLS_TCB_AT_TP.
For the main thread the static tls data is properly aligned.
For other threads the alignment depends on the alignment of the thread
pointer as the static tls data is located relative to this pointer.

This patch adds this alignment for TLS_TCB_AT_TP variants in the same way
as it is already done for TLS_DTV_AT_TP. The thread pointer is also already
properly aligned if the user provides its own stack for the new thread.

This patch extends the testcase nptl/tst-tls1.c in order to check the
alignment of the tls variables and it adds a pthread_create invocation
with a user provided stack.
The test itself is migrated from test-skeleton.c to test-driver.c
and the missing support functions xpthread_attr_setstack and xposix_memalign
are added.

ChangeLog:

	[BZ #23403]
	* nptl/allocatestack.c (allocate_stack): Align pointer pd for
	TLS_TCB_AT_TP tls variant.
	* nptl/tst-tls1.c: Migrate to support/test-driver.c.
	Add alignment checks.
	* support/Makefile (libsupport-routines): Add xposix_memalign and
	xpthread_setstack.
	* support/support.h: Add xposix_memalign.
	* support/xthread.h: Add xpthread_attr_setstack.
	* support/xposix_memalign.c: New File.
	* support/xpthread_attr_setstack.c: Likewise.

(cherry picked from commit bc79db3fd4)
2019-11-05 14:36:16 -05:00
Dragan Mladjenovic a7646651f8 mips: Force RWX stack for hard-float builds that can run on pre-4.8 kernels
Linux/Mips kernels prior to 4.8 could potentially crash the user
process when doing FPU emulation while running on non-executable
user stack.

Currently, gcc doesn't emit .note.GNU-stack for mips, but that will
change in the future. To ensure that glibc can be used with such
future gcc, without silently resulting in binaries that might crash
in runtime, this patch forces RWX stack for all built objects if
configured to run against minimum kernel version less than 4.8.

	* sysdeps/unix/sysv/linux/mips/Makefile
	(test-xfail-check-execstack):
	Move under mips-has-gnustack != yes.
	(CFLAGS-.o*, ASFLAGS-.o*): New rules.
	Apply -Wa,-execstack if mips-force-execstack == yes.
	* sysdeps/unix/sysv/linux/mips/configure: Regenerated.
	* sysdeps/unix/sysv/linux/mips/configure.ac
	(mips-force-execstack): New var.
	Set to yes for hard-float builds with minimum_kernel < 4.8.0
	or minimum_kernel not set at all.
	(mips-has-gnustack): New var.
	Use value of libc_cv_as_noexecstack
	if mips-force-execstack != yes, otherwise set to no.

(cherry picked from commit 33bc9efd91)
2019-11-05 14:49:11 -03:00
Florian Weimer 52a6381659 elf: Refuse to dlopen PIE objects [BZ #24323]
Another executable has already been mapped, so the dynamic linker
cannot perform relocations correctly for the second executable.

(cherry picked from commit 2c75b545de)
2019-10-31 19:29:35 -04:00
DJ Delorie f1f24cdeba nss_db: fix endent wrt NULL mappings [BZ #24695] [BZ #24696]
nss_db allows for getpwent et al to be called without a set*ent,
but it only works once.  After the last get*ent a set*ent is
required to restart, because the end*ent did not properly reset
the module.  Resetting it to NULL allows for a proper restart.

If the database doesn't exist, however, end*ent erroniously called
munmap which set errno.

The test case runs "makedb" inside the testroot, so needs selinux
DSOs installed.

(cherry picked from commit 99135114ba)
2019-10-31 18:12:21 -04:00
Adhemerval Zanella c1803823c6 support: Export bindir path on support_path
Checked on x86_64-linux-gnu.

	* support/Makefile (CFLAGS-support_paths.c): Add -DBINDIR_PATH.
	* support/support.h (support_bindir_prefix): New variable.
	* support/support_paths.c [BINDIR_PATH] (support_bindir_prefix):

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit c7ac9caaae)
2019-10-31 18:10:53 -04:00
H.J. Lu 5e1548a6d9 Call _dl_open_check after relocation [BZ #24259]
This is a workaround for [BZ #20839] which doesn't remove the NODELETE
object when _dl_open_check throws an exception.  Move it after relocation
in dl_open_worker to avoid leaving the NODELETE object mapped without
relocation.

	[BZ #24259]
	* elf/dl-open.c (dl_open_worker): Call _dl_open_check after
	relocation.
	* sysdeps/x86/Makefile (tests): Add tst-cet-legacy-5a,
	tst-cet-legacy-5b, tst-cet-legacy-6a and tst-cet-legacy-6b.
	(modules-names): Add tst-cet-legacy-mod-5a, tst-cet-legacy-mod-5b,
	tst-cet-legacy-mod-5c, tst-cet-legacy-mod-6a, tst-cet-legacy-mod-6b
	and tst-cet-legacy-mod-6c.
	(CFLAGS-tst-cet-legacy-5a.c): New.
	(CFLAGS-tst-cet-legacy-5b.c): Likewise.
	(CFLAGS-tst-cet-legacy-mod-5a.c): Likewise.
	(CFLAGS-tst-cet-legacy-mod-5b.c): Likewise.
	(CFLAGS-tst-cet-legacy-mod-5c.c): Likewise.
	(CFLAGS-tst-cet-legacy-6a.c): Likewise.
	(CFLAGS-tst-cet-legacy-6b.c): Likewise.
	(CFLAGS-tst-cet-legacy-mod-6a.c): Likewise.
	(CFLAGS-tst-cet-legacy-mod-6b.c): Likewise.
	(CFLAGS-tst-cet-legacy-mod-6c.c): Likewise.
	($(objpfx)tst-cet-legacy-5a): Likewise.
	($(objpfx)tst-cet-legacy-5a.out): Likewise.
	($(objpfx)tst-cet-legacy-mod-5a.so): Likewise.
	($(objpfx)tst-cet-legacy-mod-5b.so): Likewise.
	($(objpfx)tst-cet-legacy-5b): Likewise.
	($(objpfx)tst-cet-legacy-5b.out): Likewise.
	(tst-cet-legacy-5b-ENV): Likewise.
	($(objpfx)tst-cet-legacy-6a): Likewise.
	($(objpfx)tst-cet-legacy-6a.out): Likewise.
	($(objpfx)tst-cet-legacy-mod-6a.so): Likewise.
	($(objpfx)tst-cet-legacy-mod-6b.so): Likewise.
	($(objpfx)tst-cet-legacy-6b): Likewise.
	($(objpfx)tst-cet-legacy-6b.out): Likewise.
	(tst-cet-legacy-6b-ENV): Likewise.
	* sysdeps/x86/tst-cet-legacy-5.c: New file.
	* sysdeps/x86/tst-cet-legacy-5a.c: Likewise.
	* sysdeps/x86/tst-cet-legacy-5b.c: Likewise.
	* sysdeps/x86/tst-cet-legacy-6.c: Likewise.
	* sysdeps/x86/tst-cet-legacy-6a.c: Likewise.
	* sysdeps/x86/tst-cet-legacy-6b.c: Likewise.
	* sysdeps/x86/tst-cet-legacy-mod-5.c: Likewise.
	* sysdeps/x86/tst-cet-legacy-mod-5a.c: Likewise.
	* sysdeps/x86/tst-cet-legacy-mod-5b.c: Likewise.
	* sysdeps/x86/tst-cet-legacy-mod-5c.c: Likewise.
	* sysdeps/x86/tst-cet-legacy-mod-6.c: Likewise.
	* sysdeps/x86/tst-cet-legacy-mod-6a.c: Likewise.
	* sysdeps/x86/tst-cet-legacy-mod-6b.c: Likewise.
	* sysdeps/x86/tst-cet-legacy-mod-6c.c: Likewise.

(cherry picked from commit d0093c5cef)
2019-10-31 16:53:28 -04:00
Joseph Myers afbf970cae Fix RISC-V vfork build with Linux 5.3 kernel headers.
Building glibc for RISC-V with Linux 5.3 kernel headers fails because
<linux/sched.h>, included in vfork.S for CLONE_* constants, contains a
structure definition not safe for inclusion in assembly code.

All other architectures already avoid use of that header in vfork.S,
either defining the CLONE_* constants locally or embedding the
required values directly in the relevant instruction, where they
implement vfork using the clone syscall (see the implementations for
aarch64, ia64, mips and nios2).  This patch makes the RISC-V version
define the constants locally like the other architectures.

Tested build for all three RISC-V configurations in
build-many-glibcs.py with Linux 5.3 headers.

	* sysdeps/unix/sysv/linux/riscv/vfork.S: Do not include
	<linux/sched.h>.
	(CLONE_VM): New macro.
	(CLONE_VFORK): Likewise.

(cherry picked from commit 8cacbcf4a9)
2019-09-20 21:30:04 +02:00
Aurelien Jarno a132a2c305 alpha: force old OSF1 syscalls for getegid, geteuid and getppid [BZ #24986]
On alpha, Linux kernel 5.1 added the standard getegid, geteuid and
getppid syscalls (commit ecf7e0a4ad15287). Up to now alpha was using
the corresponding OSF1 syscalls through:
 - sysdeps/unix/alpha/getegid.S
 - sysdeps/unix/alpha/geteuid.S
 - sysdeps/unix/alpha/getppid.S

When building against kernel headers >= 5.1, the glibc now use the new
syscalls through sysdeps/unix/sysv/linux/syscalls.list. When it is then
used with an older kernel, the corresponding 3 functions fail.

A quick fix is to move the OSF1 wrappers under the
sysdeps/unix/sysv/linux/alpha directory so they override the standard
linux ones. A better fix would be to try the new syscalls and fallback
to the old OSF1 in case the new ones fail. This can be implemented in
a later commit.

Changelog:
	[BZ #24986]
        * sysdeps/unix/alpha/getegid.S: Move to ...
	* sysdeps/unix/sysv/linux/alpha/getegid.S: ... here.
        * sysdeps/unix/alpha/geteuid.S: Move to ...
	* sysdeps/unix/sysv/linux/alpha/geteuid.S: ... here.
        * sysdeps/unix/alpha/getppid.S: Move to ...
	* sysdeps/unix/sysv/linux/alpha/getppid.S: ... here
2019-09-14 20:12:11 +02:00
Wilco Dijkstra 91372f0001 Improve performance of memmem
This patch significantly improves performance of memmem using a novel
modified Horspool algorithm.  Needles up to size 256 use a bad-character
table indexed by hashed pairs of characters to quickly skip past mismatches.
Long needles use a self-adapting filtering step to avoid comparing the whole
needle repeatedly.

By limiting the needle length to 256, the shift table only requires 8 bits
per entry, lowering preprocessing overhead and minimizing cache effects.
This limit also implies worst-case performance is linear.

Small needles up to size 2 use a dedicated linear search.  Very long needles
use the Two-Way algorithm (to avoid increasing stack size or slowing down
the common case, inlining is disabled).

The performance gain is 6.6 times on English text on AArch64 using random
needles with average size 8.

Tested against GLIBC testsuite and randomized tests.

Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>

	* string/memmem.c (__memmem): Rewrite to improve performance.

(cherry picked from commit 680942b016)
2019-09-13 14:51:35 +01:00
Wilco Dijkstra 1ad15e008c Improve performance of strstr
This patch significantly improves performance of strstr using a novel
modified Horspool algorithm.  Needles up to size 256 use a bad-character
table indexed by hashed pairs of characters to quickly skip past mismatches.
Long needles use a self-adapting filtering step to avoid comparing the whole
needle repeatedly.

By limiting the needle length to 256, the shift table only requires 8 bits
per entry, lowering preprocessing overhead and minimizing cache effects.
This limit also implies worst-case performance is linear.

Small needles up to size 3 use a dedicated linear search.  Very long needles
use the Two-Way algorithm.

The performance gain using the improved bench-strstr on Cortex-A72 is 5.8
times basic_strstr and 3.7 times twoway_strstr.

Tested against GLIBC testsuite, randomized tests and the GNULIB strstr test
(https://git.savannah.gnu.org/cgit/gnulib.git/tree/tests/test-strstr.c).

Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>

	* string/str-two-way.h (two_way_short_needle): Add inline to avoid
	warning.
	(two_way_long_needle): Block inlining.
	* string/strstr.c (strstr2): Add new function.
	(strstr3): Likewise.
	(STRSTR): Completely rewrite strstr to improve performance.

(cherry picked from commit 5e0a7ecb66)
2019-09-13 14:51:28 +01:00
Aurelien Jarno ef98313dd3 Update Alpha libm-test-ulps
Changelog:

	* sysdeps/alpha/fpu/libm-test-ulps: Regenerated using GCC 9.2.

(cherry picked from commit b5367a08ae)
2019-09-03 21:43:22 +02:00
Adhemerval Zanella 6d8eaf4a25 hppa: Update libm-tests-ulps
The make regen-ulps was done on a PA8900 with 8.3.0.

	* sysdeps/hppa/fpu/libm-test-ulps: Update.

(cherry picked from commit 3175dcc1e6)
2019-08-18 11:38:26 +02:00
Richard Henderson 23ef51a50a alpha: Do not redefine __NR_shmat or __NR_osf_shmat
Fixes build using v5.1-rc1 headers.

The kernel has cleaned up how these are defined.  Previous behavior
was to define __NR_osf_shmat as 209 and not define __NR_shmat.
Current behavior is to define __NR_shmat as 209 and then define
__NR_osf_shmat as __NR_shmat.

	* sysdeps/unix/sysv/linux/alpha/kernel-features.h (__NR_shmat):
	Do not redefine.
	* sysdeps/unix/sysv/linux/alpha/sysdep.h (__NR_osf_shmat):
	Do not redefine.

(cherry picked from commit d5ecee822e)
2019-08-15 19:52:22 +02:00
Adhemerval Zanella 2d3fefd7ce posix: Fix large mmap64 offset for mips64n32 (BZ#24699)
The fix for BZ#21270 (commit 158d5fa0e1) added a mask to avoid offset larger
than 1^44 to be used along __NR_mmap2.  However mips64n32 users __NR_mmap,
as mips64n64, but still defines off_t as old non-LFS type (other ILP32, such
x32, defines off_t being equal to off64_t).  This leads to use the same
mask meant only for __NR_mmap2 call for __NR_mmap, thus limiting the maximum
offset it can use with mmap64.

This patch fixes by setting the high mask only for __NR_mmap2 usage. The
posix/tst-mmap-offset.c already tests it and also fails for mips64n32. The
patch also change the test to check for an arch-specific header that defines
the maximum supported offset.

Checked on x86_64-linux-gnu, i686-linux-gnu, and I also tests tst-mmap-offset
on qemu simulated mips64 with kernel 3.2.0 kernel for both mips-linux-gnu and
mips64-n32-linux-gnu.

	[BZ #24699]
	* posix/tst-mmap-offset.c: Mention BZ #24699.
	(do_test_bz21270): Rename to do_test_large_offset and use
	mmap64_maximum_offset to check for maximum expected offset value.
	* sysdeps/generic/mmap_info.h: New file.
	* sysdeps/unix/sysv/linux/mips/mmap_info.h: Likewise.
	* sysdeps/unix/sysv/linux/mmap64.c (MMAP_OFF_HIGH_MASK): Define iff
	__NR_mmap2 is used.

(cherry picked from commit a008c76b56)
2019-07-15 09:26:39 -03:00
Szabolcs Nagy 4163c382f0 aarch64: handle STO_AARCH64_VARIANT_PCS
Backport of commit 82bc69c012
and commit 30ba037546
without using DT_AARCH64_VARIANT_PCS for optimizing the symbol table check.
This is needed so the internal abi between ld.so and libc.so is unchanged.

Avoid lazy binding of symbols that may follow a variant PCS with different
register usage convention from the base PCS.

Currently the lazy binding entry code does not preserve all the registers
required for AdvSIMD and SVE vector calls.  Saving and restoring all
registers unconditionally may break existing binaries, even if they never
use vector calls, because of the larger stack requirement for lazy
resolution, which can be significant on an SVE system.

The solution is to mark all symbols in the symbol table that may follow
a variant PCS so the dynamic linker can handle them specially.  In this
patch such symbols are always resolved at load time, not lazily.

So currently LD_AUDIT for variant PCS symbols are not supported, for that
the _dl_runtime_profile entry needs to be changed e.g. to unconditionally
save/restore all registers (but pass down arg and retval registers to
pltentry/exit callbacks according to the base PCS).

This patch also removes a __builtin_expect from the modified code because
the branch prediction hint did not seem useful.

	* sysdeps/aarch64/dl-machine.h (elf_machine_lazy_rel): Check
	STO_AARCH64_VARIANT_PCS and bind such symbols at load time.
2019-07-12 10:14:12 +01:00
Szabolcs Nagy 53f48f845c aarch64: add STO_AARCH64_VARIANT_PCS and DT_AARCH64_VARIANT_PCS
STO_AARCH64_VARIANT_PCS is a non-visibility st_other flag for marking
symbols that reference functions that may follow a variant PCS with
different register usage convention from the base PCS.

DT_AARCH64_VARIANT_PCS is a dynamic tag that marks ELF modules that
have R_*_JUMP_SLOT relocations for symbols marked with
STO_AARCH64_VARIANT_PCS (i.e. have variant PCS calls via a PLT).

	* elf/elf.h (STO_AARCH64_VARIANT_PCS): Define.
	(DT_AARCH64_VARIANT_PCS): Define.
2019-07-09 11:53:59 +01:00
Florian Weimer a00dc2a18f NEWS: Add deprecated section heading 2019-07-09 10:34:07 +02:00
Florian Weimer da347f4aa3 io: Remove copy_file_range emulation [BZ #24744]
The kernel is evolving this interface (e.g., removal of the
restriction on cross-device copies), and keeping up with that
is difficult.  Applications which need the function should
run kernels which support the system call instead of relying on
the imperfect glibc emulation.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 5a659ccc0e)
2019-07-09 10:01:21 +02:00
Dmitry V. Levin 34fb5f61d3 libio: do not attempt to free wide buffers of legacy streams [BZ #24228]
Commit a601b74d31 aka glibc-2.23~693
("In preparation for fixing BZ#16734, fix failure in misc/tst-error1-mem
when _G_HAVE_MMAP is turned off.") introduced a regression:
_IO_unbuffer_all now invokes _IO_wsetb to free wide buffers of all
files, including legacy standard files which are small statically
allocated objects that do not have wide buffers and the _mode member,
causing memory corruption.

Another memory corruption in _IO_unbuffer_all happens when -1
is assigned to the _mode member of legacy standard files that
do not have it.

[BZ #24228]
* libio/genops.c (_IO_unbuffer_all)
[SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)]: Do not attempt to free wide
buffers and access _IO_FILE_complete members of legacy libio streams.
* libio/tst-bz24228.c: New file.
* libio/tst-bz24228.map: Likewise.
* libio/Makefile [build-shared] (tests): Add tst-bz24228.
[build-shared] (generated): Add tst-bz24228.mtrace and
tst-bz24228.check.
[run-built-tests && build-shared] (tests-special): Add
$(objpfx)tst-bz24228-mem.out.
(LDFLAGS-tst-bz24228, tst-bz24228-ENV): New variables.
($(objpfx)tst-bz24228-mem.out): New rule.

(cherry picked from commit 21cc130b78)
2019-06-20 17:32:07 +00:00
Zack Weinberg 2ec0b166bf Use a proper C tokenizer to implement the obsolete typedefs test.
The test for obsolete typedefs in installed headers was implemented
using grep, and could therefore get false positives on e.g. “ulong”
in a comment.  It was also scanning all of the headers included by
our headers, and therefore testing headers we don’t control, e.g.
Linux kernel headers.

This patch splits the obsolete-typedef test from
scripts/check-installed-headers.sh to a separate program,
scripts/check-obsolete-constructs.py.  Being implemented in Python,
it is feasible to make it tokenize C accurately enough to avoid false
positives on the contents of comments and strings.  It also only
examines $(headers) in each subdirectory--all the headers we install,
but not any external dependencies of those headers.  Headers whose
installed name starts with finclude/ are ignored, on the assumption
that they contain Fortran.

It is also feasible to make the new test understand the difference
between _defining_ the obsolete typedefs and _using_ the obsolete
typedefs, which means posix/{bits,sys}/types.h no longer need to be
exempted.  This uncovered an actual bug in bits/types.h: __quad_t and
__u_quad_t were being used to define __S64_TYPE, __U64_TYPE,
__SQUAD_TYPE and __UQUAD_TYPE.  These are changed to __int64_t and
__uint64_t respectively.  This is a safe change, despite the comments
in bits/types.h claiming a difference between __quad_t and __int64_t,
because those comments are incorrect.  In all current ABIs, both
__quad_t and __int64_t are ‘long’ when ‘long’ is a 64-bit type, and
‘long long’ when ‘long’ is a 32-bit type, and similarly for __u_quad_t
and __uint64_t.  (Changing the types to be what the comments say they
are would be an ABI break, as it affects C++ name mangling.)  This
patch includes a minimal change to make the comments not completely
wrong.

sys/types.h was defining the legacy BSD u_intN_t typedefs using a
construct that was not necessarily consistent with how the C99 uintN_t
typedefs are defined, and is also too complicated for the new script to
understand (it lexes C relatively accurately, but it does not attempt
to expand preprocessor macros, nor does it do any actual parsing).
This patch cuts all of that out and uses bits/types.h's __uintN_t typedefs
to define u_intN_t instead.  This is verified to not change the ABI on
any supported architecture, via the c++-types test, which means u_intN_t
and uintN_t were, in fact, consistent on all supported architectures.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

	* scripts/check-obsolete-constructs.py: New test script.
	* scripts/check-installed-headers.sh: Remove tests for
	obsolete typedefs, superseded by check-obsolete-constructs.py.
	* Rules: Run scripts/check-obsolete-constructs.py over $(headers)
	as a special test.  Update commentary.
	* posix/bits/types.h (__SQUAD_TYPE, __S64_TYPE): Define as __int64_t.
	(__UQUAD_TYPE, __U64_TYPE): Define as __uint64_t.
	Update commentary.
	* posix/sys/types.h (__u_intN_t): Remove.
	(u_int8_t): Typedef using __uint8_t.
	(u_int16_t): Typedef using __uint16_t.
	(u_int32_t): Typedef using __uint32_t.
	(u_int64_t): Typedef using __uint64_t.

(cherry picked from commit 711a322a23)
2019-06-05 14:15:01 +02:00
Florian Weimer bd0a325b6a malloc: Fix warnings in tests with GCC 9
This is a partial backport of test changes in commit
9bf8e29ca1 ("malloc: make malloc fail
with requests larger than PTRDIFF_MAX (BZ#23741)"), without the
actual functionality changes.
2019-06-05 14:02:05 +02:00
Wilco Dijkstra 95d66fecaa Fix tcache count maximum (BZ #24531)
The tcache counts[] array is a char, which has a very small range and thus
may overflow.  When setting tcache_count tunable, there is no overflow check.
However the tunable must not be larger than the maximum value of the tcache
counts[] array, otherwise it can overflow when filling the tcache.

	[BZ #24531]
	* malloc/malloc.c (MAX_TCACHE_COUNT): New define.
	(do_set_tcache_count): Only update if count is small enough.
	* manual/tunables.texi (glibc.malloc.tcache_count): Document max value.

(cherry picked from commit 5ad533e8e6)
2019-05-22 14:17:01 +01:00
Mark Wielaard 980cb43f15 Update NEWS for BZ#24476 Guard __dlerror_main_freeres. 2019-05-16 15:25:40 +02:00
Mark Wielaard e3f828b8bd dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once) [BZ#24476]
dlerror.c (__dlerror_main_freeres) will try to free resources which only
have been initialized when init () has been called. That function is
called when resources are needed using __libc_once (once, init) where
once is a __libc_once_define (static, once) in the dlerror.c file.
Trying to free those resources if init () hasn't been called will
produce errors under valgrind memcheck. So guard the freeing of those
resources using __libc_once_get (once) and make sure we have a valid
key. Also add a similar guard to __dlerror ().

	* dlfcn/dlerror.c (__dlerror_main_freeres): Guard using
	__libc_once_get (once) and static_bug == NULL.
	(__dlerror): Check we have a valid key, set result to static_buf
	otherwise.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 11b451c886)
2019-05-16 14:54:23 +02:00
Andreas Schwab c6177be4b9 Fix crash in _IO_wfile_sync (bug 20568)
When computing the length of the converted part of the stdio buffer, use
the number of consumed wide characters, not the (negative) distance to the
end of the wide buffer.

(cherry picked from commit 32ff397533)
2019-05-15 17:09:05 +02:00
Adam Maris 52b7cd6e9a malloc: Check for large bin list corruption when inserting unsorted chunk
Fixes bug 24216. This patch adds security checks for bk and bk_nextsize pointers
of chunks in large bin when inserting chunk from unsorted bin. It was possible
to write the pointer to victim (newly inserted chunk) to arbitrary memory
locations if bk or bk_nextsize pointers of the next large bin chunk
got corrupted.

(cherry picked from commit 5b06f538c5)
2019-05-02 13:50:00 +02:00
Adhemerval Zanella eaea1dfbe9 elf: Fix pldd (BZ#18035)
Since 9182aa6799 (Fix vDSO l_name for GDB's, BZ#387) the initial link_map
for executable itself and loader will have both l_name and l_libname->name
holding the same value due:

 elf/dl-object.c

 95   new->l_name = *realname ? realname : (char *) newname->name + libname_len - 1;

Since newname->name points to new->l_libname->name.

This leads to pldd to an infinite call at:

 elf/pldd-xx.c

203     again:
204       while (1)
205         {
206           ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset);

228           /* Try the l_libname element.  */
229           struct E(libname_list) ln;
230           if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln))
231             {
232               name_offset = ln.name;
233               goto again;
234             }

Since the value at ln.name (l_libname->name) will be the same as previously
read. The straightforward fix is just avoid the check and read the new list
entry.

I checked also against binaries issues with old loaders with fix for BZ#387,
and pldd could dump the shared objects.

Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu, and
powerpc64le-linux-gnu.

	[BZ #18035]
	* elf/Makefile (tests-container): Add tst-pldd.
	* elf/pldd-xx.c: Use _Static_assert in of pldd_assert.
	(E(find_maps)): Avoid use alloca, use default read file operations
	instead of explicit LFS names, and fix infinite	loop.
	* elf/pldd.c: Explicit set _FILE_OFFSET_BITS, cleanup headers.
	(get_process_info): Use _Static_assert instead of assert, use default
	directory operations instead of explicit LFS names, and free some
	leadek pointers.
	* elf/tst-pldd.c: New file.

(cherry picked from commit 1a4c27355e)
2019-04-26 14:31:22 +02:00
Adhemerval Zanella f62d21a1f0 support: Add support_capture_subprogram
Its API is similar to support_capture_subprocess, but rather creates a
new process based on the input path and arguments.  Under the hoods it
uses posix_spawn to create the new process.

It also allows the use of other support_capture_* functions to check
for expected results and free the resources.

Checked on x86_64-linux-gnu.

	* support/Makefile (libsupport-routines): Add support_subprocess,
	xposix_spawn, xposix_spawn_file_actions_addclose, and
	xposix_spawn_file_actions_adddup2.
	(tst-support_capture_subprocess-ARGS): New rule.
	* support/capture_subprocess.h (support_capture_subprogram): New
	prototype.
	* support/support_capture_subprocess.c (support_capture_subprocess):
	Refactor to use support_subprocess and support_capture_poll.
	(support_capture_subprogram): New function.
	* support/tst-support_capture_subprocess.c (write_mode_to_str,
	str_to_write_mode, test_common, parse_int, handle_restart,
	do_subprocess, do_subprogram, do_multiple_tests): New functions.
	(do_test): Add support_capture_subprogram tests.
	* support/subprocess.h: New file.
	* support/support_subprocess.c: Likewise.
	* support/xposix_spawn.c: Likewise.
	* support/xposix_spawn_file_actions_addclose.c: Likewise.
	* support/xposix_spawn_file_actions_adddup2.c: Likewise.
	* support/xspawn.h: Likewise.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 0e16969129)
2019-04-26 14:31:22 +02:00
Florian Weimer 0744a268bc Revert "memusagestat: use local glibc when linking [BZ #18465]"
This reverts commit 42dfc13abf.

The position of the -Wl,-rpath-link= options on the linker command
line is not correct, so the new way of linking memusagestat does not
always work.
2019-04-25 14:58:13 +02:00
Mike Frysinger 42dfc13abf memusagestat: use local glibc when linking [BZ #18465]
The memusagestat is the only binary that has its own link line which
causes it to be linked against the existing installed C library.  It
has been this way since it was originally committed in 1999, but I
don't see any reason as to why.  Since we want all the programs we
build locally to be against the new copy of glibc, change the build
to be like all other programs.

(cherry picked from commit f9b645b4b0)
2019-04-24 19:07:46 +02:00
Carlos O'Donell dcd2b97dd1 malloc: Set and reset all hooks for tracing (Bug 16573)
If an error occurs during the tracing operation, particularly during a
call to lock_and_info() which calls _dl_addr, we may end up calling back
into the malloc-subsystem and relock the loader lock and deadlock. For
all intents and purposes the call to _dl_addr can call any of the malloc
family API functions and so we should disable all tracing before calling
such loader functions.  This is similar to the strategy that the new
malloc tracer takes when calling the real malloc, namely that all
tracing ceases at the boundary to the real function and any faults at
that point are the purvue of the library (though the new tracer does
this on a per-thread basis in an MT-safe fashion). Since the new tracer
and the hook deprecation are not yet complete we must fix these issues
where we can.

Tested on x86_64 with no regressions.

Co-authored-by: Kwok Cheung Yeung <kcy@codesourcery.com>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit e621246ec6)
2019-04-15 20:49:32 +02:00
TAMUKI Shoichi 0941350c20 ja_JP locale: Add entry for the new Japanese era [BZ #22964]
The Japanese era name will be changed on May 1, 2019.  The Japanese
government made a preliminary announcement on April 1, 2019.

The glibc ja_JP locale must be updated to include the new era name for
strftime's alternative year format support.

This is a minimal cherry pick of just the required locale changes.

(cherry picked from commit 466afec308)
2019-04-03 19:42:20 +02:00
TAMUKI Shoichi e28ad442e7 ja_JP: Change the offset for Taisho gan-nen from 2 to 1 [BZ #24162]
The offset in era-string format for Taisho gan-nen (1912) is currently
defined as 2, but it should be 1.  So fix it.  "Gan-nen" means the 1st
(origin) year, Taisho started on July 30, 1912.

Reported-by: Morimitsu, Junji <junji.morimitsu@hpe.com>
Reviewed-by: Rafal Luzynski <digitalfreak@lingonborough.com>

ChangeLog:

	[BZ #24162]
	* localedata/locales/ja_JP (LC_TIME): Change the offset for Taisho
	gan-nen from 2 to 1.  Problem reported by Morimitsu, Junji.

(cherry picked from commit 31effacee2)
2019-03-22 10:59:06 +09:00
Stefan Liebler 6eb48fe80c S390: Mark vx and vxe as important hwcap.
This patch adds vx and vxe as important hwcaps
which allows one to provide shared libraries
tuned for platforms with non-vx/-vxe, vx or vxe.

ChangeLog:

	* sysdeps/s390/dl-procinfo.h (HWCAP_IMPORTANT):
	Add HWCAP_S390_VX and HWCAP_S390_VXE.

(cherry picked from commit 61f5e9470f)

Conflicts:
	ChangeLog
2019-03-21 09:27:37 +01:00
Aurelien Jarno 10dd17da71 Record CVE-2019-9169 in NEWS and ChangeLog [BZ #24114]
(cherry picked from commit b626c5aa5d)
2019-03-16 23:27:47 +01:00
Paul Eggert 4d0b1b0f61 regex: fix read overrun [BZ #24114]
Problem found by AddressSanitizer, reported by Hongxu Chen in:
https://debbugs.gnu.org/34140
* posix/regexec.c (proceed_next_node):
Do not read past end of input buffer.

(cherry picked from commit 583dd860d5)
2019-03-16 23:26:14 +01:00
Stefan Liebler bc6f839fb4 Fix output of LD_SHOW_AUXV=1.
Starting with commit 1616d034b6
the output was corrupted on some platforms as _dl_procinfo
was called for every auxv entry and on some architectures like s390
all entries were represented as "AT_HWCAP".

This patch is removing the condition and let _dl_procinfo decide if
an entry is printed in a platform specific or generic way.
This patch also adjusts all _dl_procinfo implementations which assumed
that they are only called for AT_HWCAP or AT_HWCAP2. They are now just
returning a non-zero-value for entries which are not handled platform
specifc.

ChangeLog:

	* elf/dl-sysdep.c (_dl_show_auxv): Remove condition and always
	call _dl_procinfo.
	* sysdeps/unix/sysv/linux/s390/dl-procinfo.h (_dl_procinfo):
	Ignore types other than AT_HWCAP.
	* sysdeps/sparc/dl-procinfo.h (_dl_procinfo): Likewise.
	* sysdeps/unix/sysv/linux/i386/dl-procinfo.h (_dl_procinfo):
	Likewise.
	* sysdeps/powerpc/dl-procinfo.h (_dl_procinfo): Adjust comment
	in the case of falling back to generic output mechanism.
	* sysdeps/unix/sysv/linux/arm/dl-procinfo.h (_dl_procinfo):
	Likewise.

(cherry picked from commit 7c6513082b)

Conflicts:
	ChangeLog
2019-03-13 10:51:23 +01:00
Florian Weimer 067fc32968 nptl: Fix invalid Systemtap probe in pthread_join [BZ #24211]
After commit f1ac745583 ("arm: Use "nr"
constraint for Systemtap probes [BZ #24164]"), we load pd->result into
a register in the probe below:

      /* Free the TCB.  */
      __free_tcb (pd);
    }
  else
    pd->joinid = NULL;

  LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd->result);

However, at this point, the thread descriptor has been freed.  If the
thread stack does not fit into the thread stack cache, the memory will
have been unmapped, and the program will crash in the probe.

(cherry picked from commit bc10e22c90)
2019-02-15 21:27:01 +01:00
Florian Weimer c096b008d2 nptl: Avoid fork handler lock for async-signal-safe fork [BZ #24161]
Commit 27761a1042 ("Refactor atfork
handlers") introduced a lock, atfork_lock, around fork handler list
accesses.  It turns out that this lock occasionally results in
self-deadlocks in malloc/tst-mallocfork2:

(gdb) bt
#0  __lll_lock_wait_private ()
    at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:63
#1  0x00007f160c6f927a in __run_fork_handlers (who=(unknown: 209394016),
    who@entry=atfork_run_prepare) at register-atfork.c:116
#2  0x00007f160c6b7897 in __libc_fork () at ../sysdeps/nptl/fork.c:58
#3  0x00000000004027d6 in sigusr1_handler (signo=<optimized out>)
    at tst-mallocfork2.c:80
#4  sigusr1_handler (signo=<optimized out>) at tst-mallocfork2.c:64
#5  <signal handler called>
#6  0x00007f160c6f92e4 in __run_fork_handlers (who=who@entry=atfork_run_parent)
    at register-atfork.c:136
#7  0x00007f160c6b79a2 in __libc_fork () at ../sysdeps/nptl/fork.c:152
#8  0x0000000000402567 in do_test () at tst-mallocfork2.c:156
#9  0x0000000000402dd2 in support_test_main (argc=1, argv=0x7ffc81ef1ab0,
    config=config@entry=0x7ffc81ef1970) at support_test_main.c:350
#10 0x0000000000402362 in main (argc=<optimized out>, argv=<optimized out>)
    at ../support/test-driver.c:168

If no locking happens in the single-threaded case (where fork is
expected to be async-signal-safe), this deadlock is avoided.
(pthread_atfork is not required to be async-signal-safe, so a fork
call from a signal handler interrupting pthread_atfork is not
a problem.)

(cherry picked from commit 669ff911e2)
2019-02-08 12:54:41 +01:00
Stefan Liebler 44113a8ba2 Add compiler barriers around modifications of the robust mutex list for pthread_mutex_trylock. [BZ #24180]
While debugging a kernel warning, Thomas Gleixner, Sebastian Sewior and
Heiko Carstens found a bug in pthread_mutex_trylock due to misordered
instructions:
140:   a5 1b 00 01             oill    %r1,1
144:   e5 48 a0 f0 00 00       mvghi   240(%r10),0   <--- THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
14a:   e3 10 a0 e0 00 24       stg     %r1,224(%r10) <--- last THREAD_SETMEM of ENQUEUE_MUTEX_PI

vs (with compiler barriers):
140:   a5 1b 00 01             oill    %r1,1
144:   e3 10 a0 e0 00 24       stg     %r1,224(%r10)
14a:   e5 48 a0 f0 00 00       mvghi   240(%r10),0

Please have a look at the discussion:
"Re: WARN_ON_ONCE(!new_owner) within wake_futex_pi() triggerede"
(https://lore.kernel.org/lkml/20190202112006.GB3381@osiris/)

This patch is introducing the same compiler barriers and comments
for pthread_mutex_trylock as introduced for pthread_mutex_lock and
pthread_mutex_timedlock by commit 8f9450a0b7
"Add compiler barriers around modifications of the robust mutex list."

ChangeLog:

	[BZ #24180]
	* nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock):
	Add compiler barriers and comments.

(cherry picked from commit 823624bdc4)
2019-02-07 15:33:23 +01:00
Florian Weimer 2de15ac957 arm: Use "nr" constraint for Systemtap probes [BZ #24164]
With the default "nor" constraint, current GCC will use the "o"
constraint for constants, after emitting the constant to memory.  That
results in unparseable Systemtap probe notes such as "-4@.L1052".
Removing the "o" alternative and using "nr" instead avoids this.

(cherry picked from commit f1ac745583)
2019-02-05 13:49:03 +01:00
H.J. Lu 726a78867b x86-64 memcmp: Use unsigned Jcc instructions on size [BZ #24155]
Since the size argument is unsigned. we should use unsigned Jcc
instructions, instead of signed, to check size.

Tested on x86-64 and x32, with and without --disable-multi-arch.

	[BZ #24155]
	CVE-2019-7309
	* NEWS: Updated for CVE-2019-7309.
	* sysdeps/x86_64/memcmp.S: Use RDX_LP for size.  Clear the
	upper 32 bits of RDX register for x32.  Use unsigned Jcc
	instructions, instead of signed.
	* sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp-2.
	* sysdeps/x86_64/x32/tst-size_t-memcmp-2.c: New test.

(cherry picked from commit 3f635fb433)
2019-02-04 12:27:04 -08:00
Carlos O'Donell 86013ef5ce nptl: Fix pthread_rwlock_try*lock stalls (Bug 23844)
For a full analysis of both the pthread_rwlock_tryrdlock() stall
and the pthread_rwlock_trywrlock() stall see:
https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14

In the pthread_rwlock_trydlock() function we fail to inspect for
PTHREAD_RWLOCK_FUTEX_USED in __wrphase_futex and wake the waiting
readers.

In the pthread_rwlock_trywrlock() function we write 1 to
__wrphase_futex and loose the setting of the PTHREAD_RWLOCK_FUTEX_USED
bit, again failing to wake waiting readers during unlock.

The fix in the case of pthread_rwlock_trydlock() is to check for
PTHREAD_RWLOCK_FUTEX_USED and wake the readers.

The fix in the case of pthread_rwlock_trywrlock() is to only write
1 to __wrphase_futex if we installed the write phase, since all other
readers would be spinning waiting for this step.

We add two new tests, one exercises the stall for
pthread_rwlock_trywrlock() which is easy to exercise, and one exercises
the stall for pthread_rwlock_trydlock() which is harder to exercise.

The pthread_rwlock_trywrlock() test fails consistently without the fix,
and passes after. The pthread_rwlock_tryrdlock() test fails roughly
5-10% of the time without the fix, and passes all the time after.

Signed-off-by: Carlos O'Donell <carlos@redhat.com>
Signed-off-by: Torvald Riegel <triegel@redhat.com>
Signed-off-by: Rik Prohaska <prohaska7@gmail.com>
Co-authored-by: Torvald Riegel <triegel@redhat.com>
Co-authored-by: Rik Prohaska <prohaska7@gmail.com>
(cherry picked from commit 5fc9ed4c40)
2019-01-31 21:37:53 -05:00
310 changed files with 14072 additions and 3647 deletions
+497
View File
@@ -1,3 +1,500 @@
2019-02-03 Aurelien Jarno <aurelien@aurel32.net>
* stdlib/isomac.c: Include <unistd.h>.
2019-06-06 Florian Weimer <fweimer@redhat.com>
* sysdeps/unix/sysv/linux/riscv/flush-icache.c: Do not use
internal GCC preprocessor identifier __has_include__.
2019-07-24 Florian Weimer <fweimer@redhat.com>
[BZ #24532]
Linux: Use in-tree copy of SO_ constants for !__USE_MISC.
* sysdeps/unix/sysv/linux/Makefile [$(subdir) == socket]
(sysdep_headers): Add bits/socket-constants.h.
(tests-special): Add tst-socket-consts.out.
(tst-socket-consts.out): New target.
* sysdeps/unix/sysv/linux/bits/socket.h: Remove macro tracking
around <asm/unistd.h>.
[__USE_MISC]: Include <bits/types/time_t.h> before <asm/socket.h>.
[!__USE_MISC]: Include <sys/socket-constants.h> instead of
<asm/socket.h>.
* sysdeps/unix/sysv/linux/bits/tst-socket-consts.py: New file.
* sysdeps/unix/sysv/linux/bits/socket-constants.h: Likewise.
* sysdeps/unix/sysv/linux/alpha/bits/socket-constants.h: Likewise.
* sysdeps/unix/sysv/linux/hppa/bits/socket-constants.h: Likewise.
* sysdeps/unix/sysv/linux/mips/bits/socket-constants.h: Likewise.
* sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h:
Likewise.
* sysdeps/unix/sysv/linux/sparc/bits/socket-constants.h: Likewise.
2019-08-15 Florian Weimer <fweimer@redhat.com>
* malloc/Makefile (tests): Only add tst-mxfast for
$(have-tunables).
* malloc/tst-mxfast.c: Fix copyright year.
(do_test): Fix GNU style issues. Use TEST_COMPARE instead of
assert for checks.
2019-08-09 DJ Delorie <dj@redhat.com>
* elf/dl-tunables.list: Add glibc.malloc.mxfast.
* manual/tunables.texi: Document it.
* malloc/malloc.c (do_set_mxfast): New.
(__libc_mallopt): Call it.
* malloc/arena.c: Add mxfast tunable.
* malloc/tst-mxfast.c: New.
* malloc/Makefile: Add it.
2019-08-08 Niklas Hambüchen <mail@nh2.me>
Carlos O'Donell <carlos@redhat.com>
[BZ #24026]
* malloc/malloc.c (__malloc_info): Account for top chunk.
2019-08-01 Florian Weimer <fweimer@redhat.com>
[BZ #24867]
* malloc/malloc.c (__malloc_info): Remove unwanted leading
whitespace.
2019-05-17 Wilco Dijkstra <wdijkstr@arm.com>
* malloc/malloc.c (MAX_TCACHE_COUNT): Increase to UINT16_MAX.
(tcache_put): Remove redundant assert.
(tcache_get): Remove redundant asserts.
(__libc_malloc): Check tcache count is not zero.
* manual/tunables.texi (glibc.malloc.tcache_count): Update maximum.
2019-02-04 Joseph Myers <joseph@codesourcery.com>
* malloc/malloc.c (tcache_get): Compare tcache->counts[tc_idx]
with 0, not tcache->entries[tc_idx].
2019-02-06 Stefan Liebler <stli@linux.ibm.com>
[BZ #23403]
* nptl/allocatestack.c (allocate_stack): Align pointer pd for
TLS_TCB_AT_TP tls variant.
* nptl/tst-tls1.c: Migrate to support/test-driver.c.
Add alignment checks.
* support/Makefile (libsupport-routines): Add xposix_memalign and
xpthread_setstack.
* support/support.h: Add xposix_memalign.
* support/xthread.h: Add xpthread_attr_setstack.
* support/xposix_memalign.c: New File.
* support/xpthread_attr_setstack.c: Likewise.
2019-06-18 Florian Weimer <fweimer@redhat.com>
[BZ #24323]
* include/elf.h (DT_1_SUPPORTED_MASK): Include DF_1_PIE.
* elf/dl-load.c (_dl_map_object_from_fd): Check for DF_1_PIE and
fail when called from dlopen.
* elf/Makefile [have-fpie && build-shared] (tests): Add
tst-dlopen-pie.
(tst-dlopen-pie): Link with -ldl.
(tst-dlopen-pie.out): Add run-time dependency on tst-pie1.
* elf/tst-dlopen-pie.c (do_test): New file.
2019-07-10 DJ Delorie <dj@redhat.com>
Sergei Trofimovich <slyfox@inbox.ru>
[BZ #24696]
[BZ #24695]
* nss/nss_db/db-open.c (internal_endent): Protect against NULL
mappings.
* nss/tst-nss-db-endgrent.c: New.
* nss/tst-nss-db-endgrent.root: New.
* nss/tst-nss-db-endpwent.c: New.
* nss/tst-nss-db-endpwent.root: New.
* nss/Makefile: Add new tests.
* support/links-dso-program-c.c: Add selinux dependency.
* support/links-dso-program.cc: Add selinux dependency.
* support/Makefile: Build those with -lselinux if enabled.
2019-05-14 Adhemerval Zanella <adhemerval.zanella@linaro.org>
* support/Makefile (CFLAGS-support_paths.c): Add -DBINDIR_PATH.
* support/support.h (support_bindir_prefix): New variable.
* support/support_paths.c [BINDIR_PATH] (support_bindir_prefix):
* config.make.in (bindir): New variable.
2019-07-01 H.J. Lu <hongjiu.lu@intel.com>
[BZ #24259]
* elf/dl-open.c (dl_open_worker): Call _dl_open_check after
relocation.
* sysdeps/x86/Makefile (tests): Add tst-cet-legacy-5a,
tst-cet-legacy-5b, tst-cet-legacy-6a and tst-cet-legacy-6b.
(modules-names): Add tst-cet-legacy-mod-5a, tst-cet-legacy-mod-5b,
tst-cet-legacy-mod-5c, tst-cet-legacy-mod-6a, tst-cet-legacy-mod-6b
and tst-cet-legacy-mod-6c.
(CFLAGS-tst-cet-legacy-5a.c): New.
(CFLAGS-tst-cet-legacy-5b.c): Likewise.
(CFLAGS-tst-cet-legacy-mod-5a.c): Likewise.
(CFLAGS-tst-cet-legacy-mod-5b.c): Likewise.
(CFLAGS-tst-cet-legacy-mod-5c.c): Likewise.
(CFLAGS-tst-cet-legacy-6a.c): Likewise.
(CFLAGS-tst-cet-legacy-6b.c): Likewise.
(CFLAGS-tst-cet-legacy-mod-6a.c): Likewise.
(CFLAGS-tst-cet-legacy-mod-6b.c): Likewise.
(CFLAGS-tst-cet-legacy-mod-6c.c): Likewise.
($(objpfx)tst-cet-legacy-5a): Likewise.
($(objpfx)tst-cet-legacy-5a.out): Likewise.
($(objpfx)tst-cet-legacy-mod-5a.so): Likewise.
($(objpfx)tst-cet-legacy-mod-5b.so): Likewise.
($(objpfx)tst-cet-legacy-5b): Likewise.
($(objpfx)tst-cet-legacy-5b.out): Likewise.
(tst-cet-legacy-5b-ENV): Likewise.
($(objpfx)tst-cet-legacy-6a): Likewise.
($(objpfx)tst-cet-legacy-6a.out): Likewise.
($(objpfx)tst-cet-legacy-mod-6a.so): Likewise.
($(objpfx)tst-cet-legacy-mod-6b.so): Likewise.
($(objpfx)tst-cet-legacy-6b): Likewise.
($(objpfx)tst-cet-legacy-6b.out): Likewise.
(tst-cet-legacy-6b-ENV): Likewise.
* sysdeps/x86/tst-cet-legacy-5.c: New file.
* sysdeps/x86/tst-cet-legacy-5a.c: Likewise.
* sysdeps/x86/tst-cet-legacy-5b.c: Likewise.
* sysdeps/x86/tst-cet-legacy-6.c: Likewise.
* sysdeps/x86/tst-cet-legacy-6a.c: Likewise.
* sysdeps/x86/tst-cet-legacy-6b.c: Likewise.
* sysdeps/x86/tst-cet-legacy-mod-5.c: Likewise.
* sysdeps/x86/tst-cet-legacy-mod-5a.c: Likewise.
* sysdeps/x86/tst-cet-legacy-mod-5b.c: Likewise.
* sysdeps/x86/tst-cet-legacy-mod-5c.c: Likewise.
* sysdeps/x86/tst-cet-legacy-mod-6.c: Likewise.
* sysdeps/x86/tst-cet-legacy-mod-6a.c: Likewise.
* sysdeps/x86/tst-cet-legacy-mod-6b.c: Likewise.
* sysdeps/x86/tst-cet-legacy-mod-6c.c: Likewise.
2019-09-20 Joseph Myers <joseph@codesourcery.com>
* sysdeps/unix/sysv/linux/riscv/vfork.S: Do not include
<linux/sched.h>.
(CLONE_VM): New macro.
(CLONE_VFORK): Likewise.
2019-09-14 Aurelien Jarno <aurelien@aurel32.net>
[BZ #24986]
* sysdeps/unix/alpha/getegid.S: Move to ...
* sysdeps/unix/sysv/linux/alpha/getegid.S: ... here.
* sysdeps/unix/alpha/geteuid.S: Move to ...
* sysdeps/unix/sysv/linux/alpha/geteuid.S: ... here.
* sysdeps/unix/alpha/getppid.S: Move to ...
* sysdeps/unix/sysv/linux/alpha/getppid.S: ... here
2019-09-13 Wilco Dijkstra <wdijkstr@arm.com>
* string/memmem.c (__memmem): Rewrite to improve performance.
2019-06-12 Wilco Dijkstra <wdijkstr@arm.com>
* string/str-two-way.h (two_way_short_needle): Add inline to avoid
warning.
(two_way_long_needle): Block inlining.
* string/strstr.c (strstr2): Add new function.
(strstr3): Likewise.
(STRSTR): Completely rewrite strstr to improve performance.
2019-09-03 Aurelien Jarno <aurelien@aurel32.net>
* sysdeps/alpha/fpu/libm-test-ulps: Regenerated using GCC 9.2.
2019-08-18 Adhemerval Zanella <adhemerval.zanella@linaro.org>
* sysdeps/hppa/fpu/libm-test-ulps: Update.
2019-08-15 Richard Henderson <rth@twiddle.net>
* sysdeps/unix/sysv/linux/alpha/kernel-features.h (__NR_shmat):
Do not redefine.
* sysdeps/unix/sysv/linux/alpha/sysdep.h (__NR_osf_shmat):
Do not redefine.
2019-07-15 Adhemerval Zanella <adhemerval.zanella@linaro.org>
[BZ #24699]
* posix/tst-mmap-offset.c: Mention BZ #24699.
(do_test_bz21270): Rename to do_test_large_offset and use
mmap64_maximum_offset to check for maximum expected offset value.
* sysdeps/generic/mmap_info.h: New file.
* sysdeps/unix/sysv/linux/mips/mmap_info.h: Likewise.
* sysdeps/unix/sysv/linux/mmap64.c (MMAP_OFF_HIGH_MASK): Define iff
__NR_mmap2 is used.
2019-07-12 Szabolcs Nagy <szabolcs.nagy@arm.com>
* sysdeps/aarch64/dl-machine.h (elf_machine_lazy_rel): Check
STO_AARCH64_VARIANT_PCS and bind such symbols at load time.
2019-06-13 Szabolcs Nagy <szabolcs.nagy@arm.com>
* elf/elf.h (STO_AARCH64_VARIANT_PCS): Define.
(DT_AARCH64_VARIANT_PCS): Define.
2019-06-28 Florian Weimer <fweimer@redhat.com>
[BZ #24744]
io: Remove the copy_file_range emulation.
* sysdeps/unix/sysv/linux/copy_file_range.c (copy_file_range): Do
not define and call copy_file_range_compat.
* io/Makefile (tests-static, tests-internal): Do not add
tst-copy_file_range-compat.
* io/copy_file_range-compat.c: Remove file.
* io/copy_file_range.c (copy_file_range): Define as stub.
* io/tst-copy_file_range-compat.c: Remove file.
* io/tst-copy_file_range.c (xdevfile): Remove variable.
(typical_sizes): Update comment. Remove 16K sizes.
(maximum_offset, maximum_offset_errno, maximum_offset_hard_limit):
Remove variables.
(find_maximum_offset, pipe_as_source, pipe_as_destination)
(delayed_write_failure_beginning, delayed_write_failure_end)
(cross_device_failure, enospc_failure_1, enospc_failure)
(oappend_failure): Remove functions.
(tests): Adjust test case list.
(do_test): Remove file system search code. Check for ENOSYS from
copy_file_range. Do not free xdevfile.
* manual/llio.texi (Copying File Data): Document ENOSYS error from
copy_file_range. Do not document the EXDEV error, which future
kernels may not report. Update the wording to reflect that
further errors are possible.
* sysdeps/unix/sysv/linux/alpha/kernel-features.h
[__LINUX_KERNEL_VERSION < 0x040D00] (__ASSUME_COPY_FILE_RANGE): Do
not undefine.
* sysdeps/unix/sysv/linux/arm/kernel-features.h
[__LINUX_KERNEL_VERSION < 0x040700] (__ASSUME_COPY_FILE_RANGE):
Likewise.
* sysdeps/unix/sysv/linux/kernel-features.h
[__LINUX_KERNEL_VERSION >= 0x040500] (__ASSUME_COPY_FILE_RANGE):
Remove definition.
* sysdeps/unix/sysv/linux/microblaze/kernel-features.h
[__LINUX_KERNEL_VERSION < 0x040A00] (__ASSUME_COPY_FILE_RANGE): Do
not undefine.
* sysdeps/unix/sysv/linux/sh/kernel-features.h
[__LINUX_KERNEL_VERSION < 0x040800] (__ASSUME_COPY_FILE_RANGE):
Likewise.
2019-06-20 Dmitry V. Levin <ldv@altlinux.org>
Florian Weimer <fweimer@redhat.com>
[BZ #24228]
* libio/genops.c (_IO_unbuffer_all)
[SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)]: Do not attempt to free wide
buffers and access _IO_FILE_complete members of legacy libio streams.
* libio/tst-bz24228.c: New file.
* libio/tst-bz24228.map: Likewise.
* libio/Makefile [build-shared] (tests): Add tst-bz24228.
[build-shared] (generated): Add tst-bz24228.mtrace and
tst-bz24228.check.
[run-built-tests && build-shared] (tests-special): Add
$(objpfx)tst-bz24228-mem.out.
(LDFLAGS-tst-bz24228, tst-bz24228-ENV): New variables.
($(objpfx)tst-bz24228-mem.out): New rule.
2019-03-13 Zack Weinberg <zackw@panix.com>
* scripts/check-obsolete-constructs.py: New test script.
* scripts/check-installed-headers.sh: Remove tests for
obsolete typedefs, superseded by check-obsolete-constructs.py.
* Rules: Run scripts/check-obsolete-constructs.py over $(headers)
as a special test. Update commentary.
* posix/bits/types.h (__SQUAD_TYPE, __S64_TYPE): Define as __int64_t.
(__UQUAD_TYPE, __U64_TYPE): Define as __uint64_t.
Update commentary.
* posix/sys/types.h (__u_intN_t): Remove.
(u_int8_t): Typedef using __uint8_t.
(u_int16_t): Typedef using __uint16_t.
(u_int32_t): Typedef using __uint32_t.
(u_int64_t): Typedef using __uint64_t.
2019-04-18 Adhemerval Zanella <adhemerval.zanella@linaro.org>
* malloc/tst-memalign.c (do_test): Disable
-Walloc-size-larger-than= around tests of malloc with negative
sizes.
* malloc/tst-malloc-too-large.c (do_test): Likewise.
2019-05-22 Wilco Dijkstra <wdijkstr@arm.com>
[BZ #24531]
* malloc/malloc.c (MAX_TCACHE_COUNT): New define.
(do_set_tcache_count): Only update if count is small enough.
* manual/tunables.texi (glibc.malloc.tcache_count): Document max value.
2019-05-15 Mark Wielaard <mark@klomp.org>
[BZ#24476]
* dlfcn/dlerror.c (__dlerror_main_freeres): Guard using
__libc_once_get (once) and static_buf == NULL.
(__dlerror): Check we have a valid key, set result to static_buf
otherwise.
2019-05-15 Andreas Schwab <schwab@suse.de>
[BZ #20568]
* libio/wfileops.c (_IO_wfile_sync): Correct last argument to
__codecvt_do_length.
* libio/Makefile (tests): Add tst-wfile-sync.
($(objpfx)tst-wfile-sync.out): Depend on $(gen-locales).
* libio/tst-wfile-sync.c: New file.
* libio/tst-wfile-sync.input: New file.
2019-04-23 Adhemerval Zanella <adhemerval.zanella@linaro.org>
[BZ #18035]
* elf/Makefile (tests-container): Add tst-pldd.
* elf/pldd-xx.c: Use _Static_assert in of pldd_assert.
(E(find_maps)): Avoid use alloca, use default read file operations
instead of explicit LFS names, and fix infinite loop.
* elf/pldd.c: Explicit set _FILE_OFFSET_BITS, cleanup headers.
(get_process_info): Use _Static_assert instead of assert, use default
directory operations instead of explicit LFS names, and free some
leadek pointers.
* elf/tst-pldd.c: New file.
2019-04-17 Adhemerval Zanella <adhemerval.zanella@linaro.org>
* support/Makefile (libsupport-routines): Add support_subprocess,
xposix_spawn, xposix_spawn_file_actions_addclose, and
xposix_spawn_file_actions_adddup2.
(tst-support_capture_subprocess-ARGS): New rule.
* support/capture_subprocess.h (support_capture_subprogram): New
prototype.
* support/support_capture_subprocess.c (support_capture_subprocess):
Refactor to use support_subprocess and support_capture_poll.
(support_capture_subprogram): New function.
* support/tst-support_capture_subprocess.c (write_mode_to_str,
str_to_write_mode, test_common, parse_int, handle_restart,
do_subprocess, do_subprogram, do_multiple_tests): New functions.
(do_test): Add support_capture_subprogram tests.
* support/subprocess.h: New file.
* support/support_subprocess.c: Likewise.
* support/xposix_spawn.c: Likewise.
* support/xposix_spawn_file_actions_addclose.c: Likewise.
* support/xposix_spawn_file_actions_adddup2.c: Likewise.
* support/xspawn.h: Likewise.
2019-04-09 Carlos O'Donell <carlos@redhat.com>
Kwok Cheung Yeung <kcy@codesourcery.com>
[BZ #16573]
* malloc/mtrace.c: Define prototypes for all hooks.
(set_default_hooks): New function.
(set_trace_hooks): Likewise.
(save_default_hooks): Likewise.
(tr_freehook): Use new s*_hooks functions.
(tr_mallochook): Likewise.
(tr_reallochook): Likewise.
(tr_memalignhook): Likewise.
(mtrace): Likewise.
(muntrace): Likewise.
2019-04-02 TAMUKI Shoichi <tamuki@linet.gr.jp>
[BZ #22964]
* localedata/locales/ja_JP (LC_TIME): Add entry for the new Japanese
era.
2019-03-02 TAMUKI Shoichi <tamuki@linet.gr.jp>
[BZ #24162]
* localedata/locales/ja_JP (LC_TIME): Change the offset for Taisho
gan-nen from 2 to 1. Problem reported by Morimitsu, Junji.
2019-03-21 Stefan Liebler <stli@linux.ibm.com>
* sysdeps/s390/dl-procinfo.h (HWCAP_IMPORTANT):
Add HWCAP_S390_VX and HWCAP_S390_VXE.
2019-01-31 Paul Eggert <eggert@cs.ucla.edu>
CVE-2019-9169
regex: fix read overrun [BZ #24114]
Problem found by AddressSanitizer, reported by Hongxu Chen in:
https://debbugs.gnu.org/34140
* posix/regexec.c (proceed_next_node):
Do not read past end of input buffer.
2019-03-13 Stefan Liebler <stli@linux.ibm.com>
* elf/dl-sysdep.c (_dl_show_auxv): Remove condition and always
call _dl_procinfo.
* sysdeps/unix/sysv/linux/s390/dl-procinfo.h (_dl_procinfo):
Ignore types other than AT_HWCAP.
* sysdeps/sparc/dl-procinfo.h (_dl_procinfo): Likewise.
* sysdeps/unix/sysv/linux/i386/dl-procinfo.h (_dl_procinfo):
Likewise.
* sysdeps/powerpc/dl-procinfo.h (_dl_procinfo): Adjust comment
in the case of falling back to generic output mechanism.
* sysdeps/unix/sysv/linux/arm/dl-procinfo.h (_dl_procinfo):
Likewise.
2019-02-15 Florian Weimer <fweimer@redhat.com>
[BZ #24211]
* nptl/pthread_join_common.c (__pthread_timedjoin_ex): Do not read
pd->result after the thread descriptor has been freed.
2019-02-08 Florian Weimer <fweimer@redhat.com>
[BZ #24161]
* sysdeps/nptl/fork.h (__run_fork_handlers): Add multiple_threads
argument.
* nptl/register-atfork.c (__run_fork_handlers): Only perform
locking if the new do_locking argument is true.
* sysdeps/nptl/fork.c (__libc_fork): Pass multiple_threads to
__run_fork_handlers.
2019-02-07 Stefan Liebler <stli@linux.ibm.com>
[BZ #24180]
* nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock):
Add compiler barriers and comments.
2019-02-05 Florian Weimer <fweimer@redhat.com>
[BZ #24164]
arm: Use "nr" constraint for Systemtap probes, to avoid the
compiler using memory operands for constants, due to the "o"
alternative in the default "nor" constraint.
* include/stap-probe.h [USE_STAP_PROBE]: Include
<stap-probe-machine.h>
* sysdeps/generic/stap-probe-machine.h: New file.
* sysdeps/arm/stap-probe-machine.h: Likewise.
2019-02-04 H.J. Lu <hongjiu.lu@intel.com>
[BZ #24155]
CVE-2019-7309
* NEWS: Updated for CVE-2019-7309.
* sysdeps/x86_64/memcmp.S: Use RDX_LP for size. Clear the
upper 32 bits of RDX register for x32. Use unsigned Jcc
instructions, instead of signed.
* sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp-2.
* sysdeps/x86_64/x32/tst-size_t-memcmp-2.c: New test.
2019-01-31 Carlos O'Donell <carlos@redhat.com>
Torvald Riegel <triegel@redhat.com>
Rik Prohaska <prohaska7@gmail.com>
[BZ# 23844]
* nptl/Makefile (tests): Add tst-rwlock-tryrdlock-stall, and
tst-rwlock-trywrlock-stall.
* nptl/pthread_rwlock_tryrdlock.c (__pthread_rwlock_tryrdlock):
Wake waiters if PTHREAD_RWLOCK_FUTEX_USED is set.
* nptl/pthread_rwlock_trywrlock.c (__pthread_rwlock_trywrlock):
Set __wrphase_fute to 1 only if we started the write phase.
* nptl/tst-rwlock-tryrdlock-stall.c: New file.
* nptl/tst-rwlock-trywrlock-stall.c: New file.
* support/Makefile (libsupport-routines): Add xpthread_rwlock_destroy.
* support/xpthread_rwlock_destroy.c: New file.
* support/xthread.h: Declare xpthread_rwlock_destroy.
2019-01-31 Siddhesh Poyarekar <siddhesh@sourceware.org>
* version.h (RELEASE): Set to "stable".
+23 -2
View File
@@ -42,6 +42,22 @@ else
objdir must be defined by the build-directory Makefile.
endif
# Did we request 'make -s' run? "yes" or "no".
# Starting from make-4.4 MAKEFLAGS now contains long
# options like '--shuffle'. To detect presence of 's'
# we pick first word with short options. Long options
# are guaranteed to come after whitespace. We use '-'
# prefix to always have a word before long options
# even if no short options were passed.
# Typical MAKEFLAGS values to watch for:
# "rs --shuffle=42" (silent)
# " --shuffle" (not silent)
ifeq ($(findstring s, $(firstword -$(MAKEFLAGS))),)
silent-make := no
else
silent-make := yes
endif
# Root of the sysdeps tree.
sysdep_dir := $(..)sysdeps
export sysdep_dir := $(sysdep_dir)
@@ -546,8 +562,13 @@ ifeq (yes,$(build-shared))
link-libc-rpath = -Wl,-rpath=$(rpath-link)
link-libc-rpath-link = -Wl,-rpath-link=$(rpath-link)
# Tests use -Wl,-rpath instead of -Wl,-rpath-link for
# build-hardcoded-path-in-tests. Add -Wl,--disable-new-dtags to force
# DT_RPATH instead of DT_RUNPATH which only applies to DT_NEEDED entries
# in the executable and doesn't applies to DT_NEEDED entries in shared
# libraries which are loaded via DT_NEEDED entries in the executable.
ifeq (yes,$(build-hardcoded-path-in-tests))
link-libc-tests-rpath-link = $(link-libc-rpath)
link-libc-tests-rpath-link = $(link-libc-rpath) -Wl,--disable-new-dtags
else
link-libc-tests-rpath-link = $(link-libc-rpath-link)
endif # build-hardcoded-path-in-tests
@@ -880,7 +901,7 @@ endif
# umpteen zillion filenames along with it (we use `...' instead)
# but we don't want this echoing done when the user has said
# he doesn't want to see commands echoed by using -s.
ifneq "$(findstring s,$(MAKEFLAGS))" "" # if -s
ifeq ($(silent-make),yes) # if -s
+cmdecho := echo >/dev/null
else # not -s
+cmdecho := echo
+2 -1
View File
@@ -395,7 +395,8 @@ ifeq ($(run-built-tests),yes)
$(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\
done
endif
$(MAKE) install DESTDIR=$(objpfx)testroot.pristine
$(MAKE) install DESTDIR=$(objpfx)testroot.pristine \
subdirs='$(all-subdirs)'
touch $(objpfx)testroot.pristine/install.stamp
tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special))
+2 -2
View File
@@ -805,7 +805,7 @@ endif
# Maximize efficiency by minimizing the number of rules.
.SUFFIXES: # Clear the suffix list. We don't use suffix rules.
# Don't define any builtin rules.
MAKEFLAGS := $(MAKEFLAGS)r
MAKEFLAGS := $(MAKEFLAGS) -r
# Generic rule for making directories.
%/:
@@ -822,7 +822,7 @@ MAKEFLAGS := $(MAKEFLAGS)r
.PRECIOUS: $(foreach l,$(libtypes),$(patsubst %,$(common-objpfx)$l,c))
# Use the verbose option of ar and tar when not running silently.
ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s
ifeq ($(silent-make),no) # if not -s
verbose := v
else # -s
verbose :=
+71
View File
@@ -4,6 +4,77 @@ See the end for copying conditions.
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
using `glibc' in the "product" field.
Version 2.29.1
Major new features:
* The entry for the new Japanese era has been added for ja_JP locale.
Deprecated and removed features, and other changes affecting compatibility:
* The copy_file_range function fails with ENOSYS if the kernel does not
support the system call of the same name. Previously, user space
emulation was performed, but its behavior did not match the kernel
behavior, which was deemed too confusing. Applications which use the
copy_file_range function will have to be run on kernels which implement
the copy_file_range system call. Support for most architectures was added
in version 4.5 of the mainline Linux kernel.
The following bugs are resolved with this release:
[14231] stdio-common tests memory requirements
[16573] malloc: Set and reset all hooks for tracing
[18035] Fix pldd hang
[20019] NULL pointer dereference in libc.so.6 IFUNC due to uninitialized GOT
[20568] Fix crash in _IO_wfile_sync
[24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
[24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
[24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
[24211] Use-after-free in Systemtap probe in pthread_join
[24228] old x86 applications that use legacy libio crash on exit
[24476] dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once)
[24744] io: Remove the copy_file_range emulation
[24794] Partial test suite run builds corrupt test-in-container testroot
[24986] alpha: new getegid, geteuid and getppid syscalls used
unconditionally
[25203] libio: Disable vtable validation for pre-2.1 interposed handles
[25204] Ignore LD_PREFER_MAP_32BIT_EXEC for SUID programs
[25225] ld.so fails to link on x86 if GCC defaults to -fcf-protection
[25232] No const correctness for strchr et al. for Clang++
[25691] stdio: Remove memory leak from multibyte conversion
[25933] Off by one error in __strncmp_avx2
[25976] nss_compat: internal_end*ent may clobber errno, hiding ERANGE
[26211] printf integer overflow calculating allocation size
[27130] "rep movsb" performance issue
[27177] GLIBC_TUNABLES=glibc.cpu.x86_ibt=on:glibc.cpu.x86_shstk=on doesn't work
[27457] vzeroupper use in AVX2 multiarch string functions cause HTM aborts
[27974] Overflow bug in some implementation of wcsnlen, wmemchr, and wcsncat
[28755] overflow bug in wcsncmp_avx2 and wcsncmp_evex
[28896] strncmp-avx2-rtm and wcsncmp-avx2-rtm fallback on non-rtm
variants when avoiding overflow
[29530] segfault in printf handling thousands separator
Security related changes:
CVE-2019-7309: x86-64 memcmp used signed Jcc instructions to check
size. For x86-64, memcmp on an object size larger than SSIZE_MAX
has undefined behavior. On x32, the size_t argument may be passed
in the lower 32 bits of the 64-bit RDX register with non-zero upper
32 bits. When it happened with the sign bit of RDX register set,
memcmp gave the wrong result since it treated the size argument as
zero. Reported by H.J. Lu.
CVE-2019-9169: Attempted case-insensitive regular-expression match
via proceed_next_node in posix/regexec.c leads to heap-based buffer
over-read. Reported by Hongxu Chen.
CVE-2019-19126: ld.so failed to ignore the LD_PREFER_MAP_32BIT_EXEC
environment variable during program execution after a security
transition, allowing local attackers to restrict the possible mapping
addresses for loaded libraries and thus bypass ASLR for a setuid
program. Reported by Marcin Kościelnicki.
Version 2.29
+4 -1
View File
@@ -82,7 +82,8 @@ $(common-objpfx)dummy.c:
common-generated += dummy.o dummy.c
ifneq "$(headers)" ""
# Special test of all the installed headers in this directory.
# Test that all of the headers installed by this directory can be compiled
# in isolation.
tests-special += $(objpfx)check-installed-headers-c.out
libof-check-installed-headers-c := testsuite
$(objpfx)check-installed-headers-c.out: \
@@ -93,6 +94,8 @@ $(objpfx)check-installed-headers-c.out: \
$(evaluate-test)
ifneq "$(CXX)" ""
# If a C++ compiler is available, also test that they can be compiled
# in isolation as C++.
tests-special += $(objpfx)check-installed-headers-cxx.out
libof-check-installed-headers-cxx := testsuite
$(objpfx)check-installed-headers-cxx.out: \
Vendored
+22 -1
View File
@@ -3777,11 +3777,32 @@ else
fi
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
#ifndef __CET__
#error no CET compiler support
#endif
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
libc_cv_compiler_default_cet=yes
else
libc_cv_compiler_default_cet=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
# Check whether --enable-cet was given.
if test "${enable_cet+set}" = set; then :
enableval=$enable_cet; enable_cet=$enableval
else
enable_cet=no
enable_cet=$libc_cv_compiler_default_cet
fi
+8 -1
View File
@@ -472,11 +472,18 @@ AC_ARG_ENABLE([mathvec],
[build_mathvec=$enableval],
[build_mathvec=notset])
AC_TRY_COMPILE([], [
#ifndef __CET__
# error no CET compiler support
#endif],
[libc_cv_compiler_default_cet=yes],
[libc_cv_compiler_default_cet=no])
AC_ARG_ENABLE([cet],
AC_HELP_STRING([--enable-cet],
[enable Intel Control-flow Enforcement Technology (CET), x86 only]),
[enable_cet=$enableval],
[enable_cet=no])
[enable_cet=$libc_cv_compiler_default_cet])
# We keep the original values in `$config_*' and never modify them, so we
# can write them unchanged into config.make. Everything else uses
+2
View File
@@ -168,6 +168,8 @@ extra-libs-others = $(extra-libs)
libSegFault-routines = segfault
libSegFault-inhibit-o = $(filter-out .os,$(object-suffixes))
# libSegFault.so installs a signal handler in its ELF constructor.
LDFLAGS-SegFault.so = -Wl,--enable-new-dtags,-z,nodelete
libpcprofile-routines = pcprofile
libpcprofile-inhibit-o = $(filter-out .os,$(object-suffixes))
+12
View File
@@ -89,6 +89,18 @@ handle_signal (int signum)
}
/* Symbol names are not available for static functions, so we do not
check do_test. */
/* Check that backtrace does not return more than what fits in the array
(bug 25423). */
for (int j = 0; j < NUM_FUNCTIONS; j++)
{
n = backtrace (addresses, j);
if (n > j)
{
FAIL ();
return;
}
}
}
NO_INLINE int
+21 -8
View File
@@ -72,9 +72,16 @@ __dlerror (void)
__libc_once (once, init);
/* Get error string. */
result = (struct dl_action_result *) __libc_getspecific (key);
if (result == NULL)
result = &last_result;
if (static_buf != NULL)
result = static_buf;
else
{
/* init () has been run and we don't use the static buffer.
So we have a valid key. */
result = (struct dl_action_result *) __libc_getspecific (key);
if (result == NULL)
result = &last_result;
}
/* Test whether we already returned the string. */
if (result->returned != 0)
@@ -230,13 +237,19 @@ free_key_mem (void *mem)
void
__dlerror_main_freeres (void)
{
void *mem;
/* Free the global memory if used. */
check_free (&last_result);
/* Free the TSD memory if used. */
mem = __libc_getspecific (key);
if (mem != NULL)
free_key_mem (mem);
if (__libc_once_get (once) && static_buf == NULL)
{
/* init () has been run and we don't use the static buffer.
So we have a valid key. */
void *mem;
/* Free the TSD memory if used. */
mem = __libc_getspecific (key);
if (mem != NULL)
free_key_mem (mem);
}
}
struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
+6 -3
View File
@@ -194,6 +194,7 @@ tests-internal += loadtest unload unload2 circleload1 \
tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \
tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \
tst-create_format1
tests-container += tst-pldd
ifeq ($(build-hardcoded-path-in-tests),yes)
tests += tst-dlopen-aout
tst-dlopen-aout-no-pie = yes
@@ -304,7 +305,7 @@ test-xfail-tst-protected1b = yes
endif
ifeq (yesyes,$(have-fpie)$(build-shared))
modules-names += tst-piemod1
tests += tst-pie1 tst-pie2
tests += tst-pie1 tst-pie2 tst-dlopen-pie
tests-pie += tst-pie1 tst-pie2
ifeq (yes,$(have-protected-data))
tests += vismain
@@ -1065,6 +1066,8 @@ CFLAGS-tst-pie2.c += $(pie-ccflag)
$(objpfx)tst-piemod1.so: $(libsupport)
$(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
$(objpfx)tst-dlopen-pie: $(libdl)
$(objpfx)tst-dlopen-pie.out: $(objpfx)tst-pie1
ifeq (yes,$(build-shared))
# NB: Please keep cet-built-dso in sysdeps/x86/Makefile in sync with
@@ -1276,6 +1279,8 @@ CFLAGS-ifuncmain6pie.c += $(pie-ccflag)
CFLAGS-ifuncmain7pie.c += $(pie-ccflag)
CFLAGS-tst-ifunc-textrel.c += $(pic-ccflag)
LDFLAGS-ifuncmain6pie = -Wl,-z,lazy
$(objpfx)ifuncmain1pie: $(objpfx)ifuncmod1.so
$(objpfx)ifuncmain1staticpie: $(objpfx)ifuncdep1pic.o
$(objpfx)ifuncmain1vispie: $(objpfx)ifuncmod1.so
@@ -1460,8 +1465,6 @@ $(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \
tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \
LD_HWCAP_MASK=0x1
tst-env-setuid-tunables-ENV = \
GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096
$(objpfx)tst-debug1: $(libdl)
$(objpfx)tst-debug1.out: $(objpfx)tst-debug1mod1.so
+14 -4
View File
@@ -1173,6 +1173,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
goto call_lose;
}
/* dlopen of an executable is not valid because it is not possible
to perform proper relocations, handle static TLS, or run the
ELF constructors. For PIE, the check needs the dynamic
section, so there is another check below. */
if (__glibc_unlikely (type != ET_DYN)
&& __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0))
{
@@ -1209,9 +1213,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
elf_get_dynamic_info (l, NULL);
/* Make sure we are not dlopen'ing an object that has the
DF_1_NOOPEN flag set. */
if (__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)
&& (mode & __RTLD_DLOPEN))
DF_1_NOOPEN flag set, or a PIE object. */
if ((__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)
&& (mode & __RTLD_DLOPEN))
|| (__glibc_unlikely (l->l_flags_1 & DF_1_PIE)
&& __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0)))
{
/* We are not supposed to load this object. Free all resources. */
_dl_unmap_segments (l);
@@ -1222,7 +1228,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
if (l->l_phdr_allocated)
free ((void *) l->l_phdr);
errstring = N_("shared object cannot be dlopen()ed");
if (l->l_flags_1 & DF_1_PIE)
errstring
= N_("cannot dynamically load position-independent executable");
else
errstring = N_("shared object cannot be dlopen()ed");
goto call_lose;
}
+6 -2
View File
@@ -292,8 +292,6 @@ dl_open_worker (void *a)
_dl_debug_state ();
LIBC_PROBE (map_complete, 3, args->nsid, r, new);
_dl_open_check (new);
/* Print scope information. */
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
_dl_show_scope (new, 0);
@@ -366,6 +364,12 @@ dl_open_worker (void *a)
_dl_relocate_object (l, l->l_scope, reloc_mode, 0);
}
/* NB: Workaround for [BZ #20839] which doesn't remove the NODELETE
object when _dl_open_check throws an exception. Move it after
relocation to avoid leaving the NODELETE object mapped without
relocation. */
_dl_open_check (new);
/* If the file is not loaded now as a dependency, add the search
list of the newly loaded object to the scope. */
bool any_tls = false;
+3 -8
View File
@@ -328,14 +328,9 @@ _dl_show_auxv (void)
assert (AT_NULL == 0);
assert (AT_IGNORE == 1);
if (av->a_type == AT_HWCAP || av->a_type == AT_HWCAP2
|| AT_L1I_CACHEGEOMETRY || AT_L1D_CACHEGEOMETRY
|| AT_L2_CACHEGEOMETRY || AT_L3_CACHEGEOMETRY)
{
/* These are handled in a special way per platform. */
if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0)
continue;
}
/* Some entries are handled in a special way per platform. */
if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0)
continue;
if (idx < sizeof (auxvars) / sizeof (auxvars[0])
&& auxvars[idx].form != unknown)
+26 -30
View File
@@ -178,6 +178,7 @@ parse_tunables (char *tunestr, char *valstring)
return;
char *p = tunestr;
size_t off = 0;
while (true)
{
@@ -191,7 +192,11 @@ parse_tunables (char *tunestr, char *valstring)
/* If we reach the end of the string before getting a valid name-value
pair, bail out. */
if (p[len] == '\0')
return;
{
if (__libc_enable_secure)
tunestr[off] = '\0';
return;
}
/* We did not find a valid name-value pair before encountering the
colon. */
@@ -217,35 +222,28 @@ parse_tunables (char *tunestr, char *valstring)
if (tunable_is_name (cur->name, name))
{
/* If we are in a secure context (AT_SECURE) then ignore the tunable
unless it is explicitly marked as secure. Tunable values take
precendence over their envvar aliases. */
/* If we are in a secure context (AT_SECURE) then ignore the
tunable unless it is explicitly marked as secure. Tunable
values take precedence over their envvar aliases. We write
the tunables that are not SXID_ERASE back to TUNESTR, thus
dropping all SXID_ERASE tunables and any invalid or
unrecognized tunables. */
if (__libc_enable_secure)
{
if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE)
{
if (p[len] == '\0')
{
/* Last tunable in the valstring. Null-terminate and
return. */
*name = '\0';
return;
}
else
{
/* Remove the current tunable from the string. We do
this by overwriting the string starting from NAME
(which is where the current tunable begins) with
the remainder of the string. We then have P point
to NAME so that we continue in the correct
position in the valstring. */
char *q = &p[len + 1];
p = name;
while (*q != '\0')
*name++ = *q++;
name[0] = '\0';
len = 0;
}
if (off > 0)
tunestr[off++] = ':';
const char *n = cur->name;
while (*n != '\0')
tunestr[off++] = *n++;
tunestr[off++] = '=';
for (size_t j = 0; j < len; j++)
tunestr[off++] = value[j];
}
if (cur->security_level != TUNABLE_SECLEVEL_NONE)
@@ -258,9 +256,7 @@ parse_tunables (char *tunestr, char *valstring)
}
}
if (p[len] == '\0')
return;
else
if (p[len] != '\0')
p += len + 1;
}
}
+5
View File
@@ -85,6 +85,11 @@ glibc {
tcache_unsorted_limit {
type: SIZE_T
}
mxfast {
type: SIZE_T
minval: 0
security_level: SXID_IGNORE
}
}
cpu {
hwcap_mask {
+7
View File
@@ -2854,6 +2854,13 @@ enum
#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */
#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */
/* AArch64 specific values for the Dyn d_tag field. */
#define DT_AARCH64_VARIANT_PCS (DT_LOPROC + 5)
#define DT_AARCH64_NUM 6
/* AArch64 specific values for the st_other field. */
#define STO_AARCH64_VARIANT_PCS 0x80
/* ARM relocs. */
#define R_ARM_NONE 0 /* No reloc */
+13
View File
@@ -19,7 +19,14 @@ typedef int (*foo_p) (void);
#endif
foo_p foo_ptr = foo;
/* Address-significant access to protected symbols is not supported in
position-dependent mode on several architectures because GCC
generates relocations that assume that the address is local to the
main program. */
#ifdef __PIE__
foo_p foo_procted_ptr = foo_protected;
#endif
extern foo_p get_foo_p (void);
extern foo_p get_foo_hidden_p (void);
@@ -37,12 +44,16 @@ main (void)
if ((*foo_ptr) () != -1)
abort ();
#ifdef __PIE__
if (foo_procted_ptr != foo_protected)
abort ();
#endif
if (foo_protected () != 0)
abort ();
#ifdef __PIE__
if ((*foo_procted_ptr) () != 0)
abort ();
#endif
p = get_foo_p ();
if (p != foo)
@@ -55,8 +66,10 @@ main (void)
abort ();
p = get_foo_protected_p ();
#ifdef __PIE__
if (p != foo_protected)
abort ();
#endif
if (ret_foo_protected != 0 || (*p) () != ret_foo_protected)
abort ();
+9
View File
@@ -14,12 +14,19 @@ get_foo (void)
return foo;
}
/* Address-significant access to protected symbols is not supported in
position-dependent mode on several architectures because GCC
generates relocations that assume that the address is local to the
main program. */
#ifdef __PIE__
foo_p
__attribute__ ((noinline))
get_foo_protected (void)
{
return foo_protected;
}
#endif
int
main (void)
@@ -30,9 +37,11 @@ main (void)
if ((*p) () != -1)
abort ();
#ifdef __PIE__
p = get_foo_protected ();
if ((*p) () != 0)
abort ();
#endif
return 0;
}
+3 -11
View File
@@ -9,7 +9,6 @@
#include "ifunc-sel.h"
typedef int (*foo_p) (void);
extern foo_p foo_ptr;
static int
one (void)
@@ -28,20 +27,17 @@ foo_ifunc (void)
}
extern int foo (void);
extern foo_p get_foo (void);
extern int call_foo (void);
extern foo_p get_foo_p (void);
foo_p my_foo_ptr = foo;
foo_p foo_ptr = foo;
int
main (void)
{
foo_p p;
p = get_foo ();
if (p != foo)
abort ();
if ((*p) () != -30)
if (call_foo () != -30)
abort ();
p = get_foo_p ();
@@ -52,12 +48,8 @@ main (void)
if (foo_ptr != foo)
abort ();
if (my_foo_ptr != foo)
abort ();
if ((*foo_ptr) () != -30)
abort ();
if ((*my_foo_ptr) () != -30)
abort ();
if (foo () != -30)
abort ();
+4 -4
View File
@@ -4,7 +4,7 @@ extern int foo (void);
typedef int (*foo_p) (void);
foo_p foo_ptr = foo;
extern foo_p foo_ptr;
foo_p
get_foo_p (void)
@@ -12,8 +12,8 @@ get_foo_p (void)
return foo_ptr;
}
foo_p
get_foo (void)
int
call_foo (void)
{
return foo;
return foo ();
}
+40 -74
View File
@@ -23,10 +23,6 @@
#define EW_(e, w, t) EW__(e, w, _##t)
#define EW__(e, w, t) e##w##t
#define pldd_assert(name, exp) \
typedef int __assert_##name[((exp) != 0) - 1]
struct E(link_map)
{
EW(Addr) l_addr;
@@ -39,12 +35,12 @@ struct E(link_map)
EW(Addr) l_libname;
};
#if CLASS == __ELF_NATIVE_CLASS
pldd_assert (l_addr, (offsetof (struct link_map, l_addr)
== offsetof (struct E(link_map), l_addr)));
pldd_assert (l_name, (offsetof (struct link_map, l_name)
== offsetof (struct E(link_map), l_name)));
pldd_assert (l_next, (offsetof (struct link_map, l_next)
== offsetof (struct E(link_map), l_next)));
_Static_assert (offsetof (struct link_map, l_addr)
== offsetof (struct E(link_map), l_addr), "l_addr");
_Static_assert (offsetof (struct link_map, l_name)
== offsetof (struct E(link_map), l_name), "l_name");
_Static_assert (offsetof (struct link_map, l_next)
== offsetof (struct E(link_map), l_next), "l_next");
#endif
@@ -54,10 +50,10 @@ struct E(libname_list)
EW(Addr) next;
};
#if CLASS == __ELF_NATIVE_CLASS
pldd_assert (name, (offsetof (struct libname_list, name)
== offsetof (struct E(libname_list), name)));
pldd_assert (next, (offsetof (struct libname_list, next)
== offsetof (struct E(libname_list), next)));
_Static_assert (offsetof (struct libname_list, name)
== offsetof (struct E(libname_list), name), "name");
_Static_assert (offsetof (struct libname_list, next)
== offsetof (struct E(libname_list), next), "next");
#endif
struct E(r_debug)
@@ -69,16 +65,17 @@ struct E(r_debug)
EW(Addr) r_map;
};
#if CLASS == __ELF_NATIVE_CLASS
pldd_assert (r_version, (offsetof (struct r_debug, r_version)
== offsetof (struct E(r_debug), r_version)));
pldd_assert (r_map, (offsetof (struct r_debug, r_map)
== offsetof (struct E(r_debug), r_map)));
_Static_assert (offsetof (struct r_debug, r_version)
== offsetof (struct E(r_debug), r_version), "r_version");
_Static_assert (offsetof (struct r_debug, r_map)
== offsetof (struct E(r_debug), r_map), "r_map");
#endif
static int
E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
E(find_maps) (const char *exe, int memfd, pid_t pid, void *auxv,
size_t auxv_size)
{
EW(Addr) phdr = 0;
unsigned int phnum = 0;
@@ -104,12 +101,9 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
if (phdr == 0 || phnum == 0 || phent == 0)
error (EXIT_FAILURE, 0, gettext ("cannot find program header of process"));
EW(Phdr) *p = alloca (phnum * phent);
if (pread64 (memfd, p, phnum * phent, phdr) != phnum * phent)
{
error (0, 0, gettext ("cannot read program header"));
return EXIT_FAILURE;
}
EW(Phdr) *p = xmalloc (phnum * phent);
if (pread (memfd, p, phnum * phent, phdr) != phnum * phent)
error (EXIT_FAILURE, 0, gettext ("cannot read program header"));
/* Determine the load offset. We need this for interpreting the
other program header entries so we do this in a separate loop.
@@ -129,24 +123,18 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
if (p[i].p_type == PT_DYNAMIC)
{
EW(Dyn) *dyn = xmalloc (p[i].p_filesz);
if (pread64 (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr)
if (pread (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr)
!= p[i].p_filesz)
{
error (0, 0, gettext ("cannot read dynamic section"));
return EXIT_FAILURE;
}
error (EXIT_FAILURE, 0, gettext ("cannot read dynamic section"));
/* Search for the DT_DEBUG entry. */
for (unsigned int j = 0; j < p[i].p_filesz / sizeof (EW(Dyn)); ++j)
if (dyn[j].d_tag == DT_DEBUG && dyn[j].d_un.d_ptr != 0)
{
struct E(r_debug) r;
if (pread64 (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr)
if (pread (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr)
!= sizeof (r))
{
error (0, 0, gettext ("cannot read r_debug"));
return EXIT_FAILURE;
}
error (EXIT_FAILURE, 0, gettext ("cannot read r_debug"));
if (r.r_map != 0)
{
@@ -160,13 +148,10 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
}
else if (p[i].p_type == PT_INTERP)
{
interp = alloca (p[i].p_filesz);
if (pread64 (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr)
interp = xmalloc (p[i].p_filesz);
if (pread (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr)
!= p[i].p_filesz)
{
error (0, 0, gettext ("cannot read program interpreter"));
return EXIT_FAILURE;
}
error (EXIT_FAILURE, 0, gettext ("cannot read program interpreter"));
}
if (list == 0)
@@ -174,14 +159,16 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
if (interp == NULL)
{
// XXX check whether the executable itself is the loader
return EXIT_FAILURE;
exit (EXIT_FAILURE);
}
// XXX perhaps try finding ld.so and _r_debug in it
return EXIT_FAILURE;
exit (EXIT_FAILURE);
}
free (p);
free (interp);
/* Print the PID and program name first. */
printf ("%lu:\t%s\n", (unsigned long int) pid, exe);
@@ -192,47 +179,27 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
do
{
struct E(link_map) m;
if (pread64 (memfd, &m, sizeof (m), list) != sizeof (m))
{
error (0, 0, gettext ("cannot read link map"));
status = EXIT_FAILURE;
goto out;
}
if (pread (memfd, &m, sizeof (m), list) != sizeof (m))
error (EXIT_FAILURE, 0, gettext ("cannot read link map"));
EW(Addr) name_offset = m.l_name;
again:
while (1)
{
ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset);
ssize_t n = pread (memfd, tmpbuf.data, tmpbuf.length, name_offset);
if (n == -1)
{
error (0, 0, gettext ("cannot read object name"));
status = EXIT_FAILURE;
goto out;
}
error (EXIT_FAILURE, 0, gettext ("cannot read object name"));
if (memchr (tmpbuf.data, '\0', n) != NULL)
break;
if (!scratch_buffer_grow (&tmpbuf))
{
error (0, 0, gettext ("cannot allocate buffer for object name"));
status = EXIT_FAILURE;
goto out;
}
error (EXIT_FAILURE, 0,
gettext ("cannot allocate buffer for object name"));
}
if (((char *)tmpbuf.data)[0] == '\0' && name_offset == m.l_name
&& m.l_libname != 0)
{
/* Try the l_libname element. */
struct E(libname_list) ln;
if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln))
{
name_offset = ln.name;
goto again;
}
}
/* The m.l_name and m.l_libname.name for loader linkmap points to same
values (since BZ#387 fix). Trying to use l_libname name as the
shared object name might lead to an infinite loop (BZ#18035). */
/* Skip over the executable. */
if (((char *)tmpbuf.data)[0] != '\0')
@@ -242,7 +209,6 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
}
while (list != 0);
out:
scratch_buffer_free (&tmpbuf);
return status;
}
+30 -34
View File
@@ -17,23 +17,17 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <alloca.h>
#define _FILE_OFFSET_BITS 64
#include <argp.h>
#include <assert.h>
#include <dirent.h>
#include <elf.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <libintl.h>
#include <link.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <scratch_buffer.h>
@@ -76,14 +70,9 @@ static struct argp argp =
options, parse_opt, args_doc, doc, NULL, more_help, NULL
};
// File descriptor of /proc/*/mem file.
static int memfd;
/* Name of the executable */
static char *exe;
/* Local functions. */
static int get_process_info (int dfd, long int pid);
static int get_process_info (const char *exe, int dfd, long int pid);
static void wait_for_ptrace_stop (long int pid);
@@ -102,8 +91,10 @@ main (int argc, char *argv[])
return 1;
}
assert (sizeof (pid_t) == sizeof (int)
|| sizeof (pid_t) == sizeof (long int));
_Static_assert (sizeof (pid_t) == sizeof (int)
|| sizeof (pid_t) == sizeof (long int),
"sizeof (pid_t) != sizeof (int) or sizeof (long int)");
char *endp;
errno = 0;
long int pid = strtol (argv[remaining], &endp, 10);
@@ -119,25 +110,24 @@ main (int argc, char *argv[])
if (dfd == -1)
error (EXIT_FAILURE, errno, gettext ("cannot open %s"), buf);
struct scratch_buffer exebuf;
scratch_buffer_init (&exebuf);
/* Name of the executable */
struct scratch_buffer exe;
scratch_buffer_init (&exe);
ssize_t nexe;
while ((nexe = readlinkat (dfd, "exe",
exebuf.data, exebuf.length)) == exebuf.length)
exe.data, exe.length)) == exe.length)
{
if (!scratch_buffer_grow (&exebuf))
if (!scratch_buffer_grow (&exe))
{
nexe = -1;
break;
}
}
if (nexe == -1)
exe = (char *) "<program name undetermined>";
/* Default stack allocation is at least 1024. */
snprintf (exe.data, exe.length, "<program name undetermined>");
else
{
exe = exebuf.data;
exe[nexe] = '\0';
}
((char*)exe.data)[nexe] = '\0';
/* Stop all threads since otherwise the list of loaded modules might
change while we are reading it. */
@@ -155,8 +145,8 @@ main (int argc, char *argv[])
error (EXIT_FAILURE, errno, gettext ("cannot prepare reading %s/task"),
buf);
struct dirent64 *d;
while ((d = readdir64 (dir)) != NULL)
struct dirent *d;
while ((d = readdir (dir)) != NULL)
{
if (! isdigit (d->d_name[0]))
continue;
@@ -182,7 +172,7 @@ main (int argc, char *argv[])
wait_for_ptrace_stop (tid);
struct thread_list *newp = alloca (sizeof (*newp));
struct thread_list *newp = xmalloc (sizeof (*newp));
newp->tid = tid;
newp->next = thread_list;
thread_list = newp;
@@ -190,17 +180,22 @@ main (int argc, char *argv[])
closedir (dir);
int status = get_process_info (dfd, pid);
if (thread_list == NULL)
error (EXIT_FAILURE, 0, gettext ("no valid %s/task entries"), buf);
int status = get_process_info (exe.data, dfd, pid);
assert (thread_list != NULL);
do
{
ptrace (PTRACE_DETACH, thread_list->tid, NULL, NULL);
struct thread_list *prev = thread_list;
thread_list = thread_list->next;
free (prev);
}
while (thread_list != NULL);
close (dfd);
scratch_buffer_free (&exe);
return status;
}
@@ -281,9 +276,10 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
static int
get_process_info (int dfd, long int pid)
get_process_info (const char *exe, int dfd, long int pid)
{
memfd = openat (dfd, "mem", O_RDONLY);
/* File descriptor of /proc/<pid>/mem file. */
int memfd = openat (dfd, "mem", O_RDONLY);
if (memfd == -1)
goto no_info;
@@ -333,9 +329,9 @@ get_process_info (int dfd, long int pid)
int retval;
if (e_ident[EI_CLASS] == ELFCLASS32)
retval = find_maps32 (pid, auxv, auxv_size);
retval = find_maps32 (exe, memfd, pid, auxv, auxv_size);
else
retval = find_maps64 (pid, auxv, auxv_size);
retval = find_maps64 (exe, memfd, pid, auxv, auxv_size);
free (auxv);
close (memfd);
+1 -1
View File
@@ -52,7 +52,7 @@ $(objpfx)rtld-libc.a: $(foreach dir,$(rtld-subdirs),\
mv -f $@T $@
# Use the verbose option of ar and tar when not running silently.
ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s
ifeq ($(silent-make),no) # if not -s
verbose := v
else # -s
verbose :=
+49
View File
@@ -0,0 +1,49 @@
/* dlopen test for PIE objects.
Copyright (C) 2019 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/>. */
/* This test attempts to open the (otherwise unrelated) PIE test
program elf/tst-pie1 and expects the attempt to fail. */
#include <dlfcn.h>
#include <stddef.h>
#include <string.h>
#include <support/check.h>
#include <support/support.h>
static void
test_mode (int mode)
{
char *pie_path = xasprintf ("%s/elf/tst-pie1", support_objdir_root);
if (dlopen (pie_path, mode) != NULL)
FAIL_EXIT1 ("dlopen succeeded unexpectedly (%d)", mode);
const char *message = dlerror ();
const char *expected
= "cannot dynamically load position-independent executable";
if (strstr (message, expected) == NULL)
FAIL_EXIT1 ("unexpected error message (mode %d): %s", mode, message);
}
static int
do_test (void)
{
test_mode (RTLD_LAZY);
test_mode (RTLD_NOW);
return 0;
}
#include <support/test-driver.c>
+93 -19
View File
@@ -25,35 +25,76 @@
#include "config.h"
#undef _LIBC
#define test_parent test_parent_tunables
#define test_child test_child_tunables
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <intprops.h>
#include <array_length.h>
static int test_child_tunables (void);
static int test_parent_tunables (void);
#include <support/check.h>
#include <support/support.h>
#include <support/test-driver.h>
#include <support/capture_subprocess.h>
#include "tst-env-setuid.c"
const char *teststrings[] =
{
"glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
"glibc.malloc.check=2:glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
"glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096:glibc.malloc.check=2",
"glibc.malloc.perturb=0x800",
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
"glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
"glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096",
"not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
"glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2",
"glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096",
":glibc.malloc.garbage=2:glibc.malloc.check=1",
"glibc.malloc.check=1:glibc.malloc.check=2",
"not_valid.malloc.check=2",
"glibc.not_valid.check=2",
};
#define CHILD_VALSTRING_VALUE "glibc.malloc.mmap_threshold=4096"
#define PARENT_VALSTRING_VALUE \
"glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096"
const char *resultstrings[] =
{
"glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=4096",
"glibc.malloc.perturb=0x800",
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=4096",
"",
"",
"",
"",
"",
"",
};
static int
test_child_tunables (void)
test_child (int off)
{
const char *val = getenv ("GLIBC_TUNABLES");
#if HAVE_TUNABLES
if (val != NULL && strcmp (val, CHILD_VALSTRING_VALUE) == 0)
if (val != NULL && strcmp (val, resultstrings[off]) == 0)
return 0;
if (val != NULL)
printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val);
return 1;
#else
if (val != NULL)
{
printf ("GLIBC_TUNABLES not cleared\n");
printf ("[%d] GLIBC_TUNABLES not cleared\n", off);
return 1;
}
return 0;
@@ -61,15 +102,48 @@ test_child_tunables (void)
}
static int
test_parent_tunables (void)
do_test (int argc, char **argv)
{
const char *val = getenv ("GLIBC_TUNABLES");
/* Setgid child process. */
if (argc == 2)
{
if (getgid () == getegid ())
/* This can happen if the file system is mounted nosuid. */
FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
(intmax_t) getgid ());
if (val != NULL && strcmp (val, PARENT_VALSTRING_VALUE) == 0)
return 0;
int ret = test_child (atoi (argv[1]));
if (val != NULL)
printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
if (ret != 0)
exit (1);
return 1;
exit (EXIT_SUCCESS);
}
else
{
int ret = 0;
/* Spawn tests. */
for (int i = 0; i < array_length (teststrings); i++)
{
char buf[INT_BUFSIZE_BOUND (int)];
printf ("Spawned test for %s (%d)\n", teststrings[i], i);
snprintf (buf, sizeof (buf), "%d\n", i);
if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0)
exit (1);
int status = support_capture_subprogram_self_sgid (buf);
/* Bail out early if unsupported. */
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
return EXIT_UNSUPPORTED;
ret |= status;
}
return ret;
}
}
#define TEST_FUNCTION_ARGV do_test
#include <support/test-driver.c>
+14 -183
View File
@@ -29,173 +29,12 @@
#include <sys/wait.h>
#include <unistd.h>
#include <support/check.h>
#include <support/support.h>
#include <support/test-driver.h>
#include <support/capture_subprocess.h>
static char SETGID_CHILD[] = "setgid-child";
#define CHILD_STATUS 42
/* Return a GID which is not our current GID, but is present in the
supplementary group list. */
static gid_t
choose_gid (void)
{
const int count = 64;
gid_t groups[count];
int ret = getgroups (count, groups);
if (ret < 0)
{
printf ("getgroups: %m\n");
exit (1);
}
gid_t current = getgid ();
for (int i = 0; i < ret; ++i)
{
if (groups[i] != current)
return groups[i];
}
return 0;
}
/* Spawn and execute a program and verify that it returns the CHILD_STATUS. */
static pid_t
do_execve (char **args)
{
pid_t kid = vfork ();
if (kid < 0)
{
printf ("vfork: %m\n");
return -1;
}
if (kid == 0)
{
/* Child process. */
execve (args[0], args, environ);
_exit (-errno);
}
if (kid < 0)
return 1;
int status;
if (waitpid (kid, &status, 0) < 0)
{
printf ("waitpid: %m\n");
return 1;
}
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
return EXIT_UNSUPPORTED;
if (!WIFEXITED (status) || WEXITSTATUS (status) != CHILD_STATUS)
{
printf ("Unexpected exit status %d from child process\n",
WEXITSTATUS (status));
return 1;
}
return 0;
}
/* Copies the executable into a restricted directory, so that we can
safely make it SGID with the TARGET group ID. Then runs the
executable. */
static int
run_executable_sgid (gid_t target)
{
char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
test_dir, (intmax_t) getpid ());
char *execname = xasprintf ("%s/bin", dirname);
int infd = -1;
int outfd = -1;
int ret = 0;
if (mkdir (dirname, 0700) < 0)
{
printf ("mkdir: %m\n");
goto err;
}
infd = open ("/proc/self/exe", O_RDONLY);
if (infd < 0)
{
printf ("open (/proc/self/exe): %m\n");
goto err;
}
outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
if (outfd < 0)
{
printf ("open (%s): %m\n", execname);
goto err;
}
char buf[4096];
for (;;)
{
ssize_t rdcount = read (infd, buf, sizeof (buf));
if (rdcount < 0)
{
printf ("read: %m\n");
goto err;
}
if (rdcount == 0)
break;
char *p = buf;
char *end = buf + rdcount;
while (p != end)
{
ssize_t wrcount = write (outfd, buf, end - p);
if (wrcount == 0)
errno = ENOSPC;
if (wrcount <= 0)
{
printf ("write: %m\n");
goto err;
}
p += wrcount;
}
}
if (fchown (outfd, getuid (), target) < 0)
{
printf ("fchown (%s): %m\n", execname);
goto err;
}
if (fchmod (outfd, 02750) < 0)
{
printf ("fchmod (%s): %m\n", execname);
goto err;
}
if (close (outfd) < 0)
{
printf ("close (outfd): %m\n");
goto err;
}
if (close (infd) < 0)
{
printf ("close (infd): %m\n");
goto err;
}
char *args[] = {execname, SETGID_CHILD, NULL};
ret = do_execve (args);
err:
if (outfd >= 0)
close (outfd);
if (infd >= 0)
close (infd);
if (execname)
{
unlink (execname);
free (execname);
}
if (dirname)
{
rmdir (dirname);
free (dirname);
}
return ret;
}
#ifndef test_child
static int
@@ -256,40 +95,32 @@ do_test (int argc, char **argv)
if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0)
{
if (getgid () == getegid ())
{
/* This can happen if the file system is mounted nosuid. */
fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
(intmax_t) getgid ());
exit (EXIT_UNSUPPORTED);
}
/* This can happen if the file system is mounted nosuid. */
FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
(intmax_t) getgid ());
int ret = test_child ();
if (ret != 0)
exit (1);
exit (CHILD_STATUS);
exit (EXIT_SUCCESS);
}
else
{
if (test_parent () != 0)
exit (1);
/* Try running a setgid program. */
gid_t target = choose_gid ();
if (target == 0)
{
fprintf (stderr,
"Could not find a suitable GID for user %jd, skipping test\n",
(intmax_t) getuid ());
exit (0);
}
int status = support_capture_subprogram_self_sgid (SETGID_CHILD);
return run_executable_sgid (target);
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
return EXIT_UNSUPPORTED;
if (!WIFEXITED (status))
FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
return 0;
}
/* Something went wrong and our argv was corrupted. */
_exit (1);
}
#define TEST_FUNCTION_ARGV do_test
+132
View File
@@ -0,0 +1,132 @@
/* Basic tests for pldd program.
Copyright (C) 2019 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 <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
#include <array_length.h>
#include <gnu/lib-names.h>
#include <support/subprocess.h>
#include <support/capture_subprocess.h>
#include <support/check.h>
static void
target_process (void *arg)
{
pause ();
}
/* The test runs in a container because pldd does not support tracing
a binary started by the loader iself (as with testrun.sh). */
static bool
in_str_list (const char *libname, const char *const strlist[])
{
for (const char *const *str = strlist; *str != NULL; str++)
if (strcmp (libname, *str) == 0)
return true;
return false;
}
static int
do_test (void)
{
/* Create a copy of current test to check with pldd. */
struct support_subprocess target = support_subprocess (target_process, NULL);
/* Run 'pldd' on test subprocess. */
struct support_capture_subprocess pldd;
{
/* Three digits per byte plus null terminator. */
char pid[3 * sizeof (uint32_t) + 1];
snprintf (pid, array_length (pid), "%d", target.pid);
const char prog[] = "/usr/bin/pldd";
pldd = support_capture_subprogram (prog,
(char *const []) { (char *) prog, pid, NULL });
support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout);
}
/* Check 'pldd' output. The test is expected to be linked against only
loader and libc. */
{
pid_t pid;
char buffer[512];
#define STRINPUT(size) "%" # size "s"
FILE *out = fmemopen (pldd.out.buffer, pldd.out.length, "r");
TEST_VERIFY (out != NULL);
/* First line is in the form of <pid>: <full path of executable> */
TEST_COMPARE (fscanf (out, "%u: " STRINPUT (512), &pid, buffer), 2);
TEST_COMPARE (pid, target.pid);
TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0);
/* It expects only one loader and libc loaded by the program. */
bool interpreter_found = false, libc_found = false;
while (fgets (buffer, array_length (buffer), out) != NULL)
{
/* Ignore vDSO. */
if (buffer[0] != '/')
continue;
/* Remove newline so baseline (buffer) can compare against the
LD_SO and LIBC_SO macros unmodified. */
if (buffer[strlen(buffer)-1] == '\n')
buffer[strlen(buffer)-1] = '\0';
const char *libname = basename (buffer);
/* It checks for default names in case of build configure with
--enable-hardcoded-path-in-tests (BZ #24506). */
if (in_str_list (libname,
(const char *const []) { "ld.so", LD_SO, NULL }))
{
TEST_COMPARE (interpreter_found, false);
interpreter_found = true;
continue;
}
if (in_str_list (libname,
(const char *const []) { "libc.so", LIBC_SO, NULL }))
{
TEST_COMPARE (libc_found, false);
libc_found = true;
continue;
}
}
TEST_COMPARE (interpreter_found, true);
TEST_COMPARE (libc_found, true);
fclose (out);
}
support_capture_subprocess_free (&pldd);
support_process_terminate (&target);
return 0;
}
#include <support/test-driver.c>
+3 -1
View File
@@ -73,7 +73,7 @@ modules.so := $(addsuffix .so, $(modules))
ifeq (yes,$(build-shared))
tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
bug-iconv10 bug-iconv11 bug-iconv12
bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv14
ifeq ($(have-thread-library),yes)
tests += bug-iconv3
endif
@@ -316,6 +316,8 @@ $(objpfx)bug-iconv10.out: $(objpfx)gconv-modules \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \
$(addprefix $(objpfx),$(modules.so)) \
+127
View File
@@ -0,0 +1,127 @@
/* Assertion in ISO-2022-JP-3 due to two-character sequence (bug 27256).
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 <iconv.h>
#include <string.h>
#include <errno.h>
#include <support/check.h>
/* Use an escape sequence to return to the initial state. */
static void
with_escape_sequence (void)
{
iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3");
TEST_VERIFY_EXIT (c != (iconv_t) -1);
char in[] = "\e$(O+D\e(B";
char *inbuf = in;
size_t inleft = strlen (in);
char out[3]; /* Space for one output character. */
char *outbuf;
size_t outleft;
outbuf = out;
outleft = sizeof (out);
TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1);
TEST_COMPARE (errno, E2BIG);
TEST_COMPARE (inleft, 3);
TEST_COMPARE (inbuf - in, strlen (in) - 3);
TEST_COMPARE (outleft, sizeof (out) - 2);
TEST_COMPARE (outbuf - out, 2);
TEST_COMPARE (out[0] & 0xff, 0xc3);
TEST_COMPARE (out[1] & 0xff, 0xa6);
/* Return to the initial shift state, producing the pending
character. */
outbuf = out;
outleft = sizeof (out);
TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), 0);
TEST_COMPARE (inleft, 0);
TEST_COMPARE (inbuf - in, strlen (in));
TEST_COMPARE (outleft, sizeof (out) - 2);
TEST_COMPARE (outbuf - out, 2);
TEST_COMPARE (out[0] & 0xff, 0xcc);
TEST_COMPARE (out[1] & 0xff, 0x80);
/* Nothing should be flushed the second time. */
outbuf = out;
outleft = sizeof (out);
TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
TEST_COMPARE (outleft, sizeof (out));
TEST_COMPARE (outbuf - out, 0);
TEST_COMPARE (out[0] & 0xff, 0xcc);
TEST_COMPARE (out[1] & 0xff, 0x80);
TEST_COMPARE (iconv_close (c), 0);
}
/* Use an explicit flush to return to the initial state. */
static void
with_flush (void)
{
iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3");
TEST_VERIFY_EXIT (c != (iconv_t) -1);
char in[] = "\e$(O+D";
char *inbuf = in;
size_t inleft = strlen (in);
char out[3]; /* Space for one output character. */
char *outbuf;
size_t outleft;
outbuf = out;
outleft = sizeof (out);
TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1);
TEST_COMPARE (errno, E2BIG);
TEST_COMPARE (inleft, 0);
TEST_COMPARE (inbuf - in, strlen (in));
TEST_COMPARE (outleft, sizeof (out) - 2);
TEST_COMPARE (outbuf - out, 2);
TEST_COMPARE (out[0] & 0xff, 0xc3);
TEST_COMPARE (out[1] & 0xff, 0xa6);
/* Flush the pending character. */
outbuf = out;
outleft = sizeof (out);
TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
TEST_COMPARE (outleft, sizeof (out) - 2);
TEST_COMPARE (outbuf - out, 2);
TEST_COMPARE (out[0] & 0xff, 0xcc);
TEST_COMPARE (out[1] & 0xff, 0x80);
/* Nothing should be flushed the second time. */
outbuf = out;
outleft = sizeof (out);
TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
TEST_COMPARE (outleft, sizeof (out));
TEST_COMPARE (outbuf - out, 0);
TEST_COMPARE (out[0] & 0xff, 0xcc);
TEST_COMPARE (out[1] & 0xff, 0x80);
TEST_COMPARE (iconv_close (c), 0);
}
static int
do_test (void)
{
with_escape_sequence ();
with_flush ();
return 0;
}
#include <support/test-driver.c>
+48 -19
View File
@@ -67,23 +67,34 @@ enum
CURRENT_SEL_MASK = 7 << 3
};
/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the state
also contains the last two bytes to be output, shifted by 6 bits, and a
one-bit indicator whether they must be preceded by the shift sequence,
in bit 22. */
/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the
state also contains the last two bytes to be output, shifted by 6
bits, and a one-bit indicator whether they must be preceded by the
shift sequence, in bit 22. During ISO-2022-JP-3 to UCS-4
conversion, COUNT may also contain a non-zero pending wide
character, shifted by six bits. This happens for certain inputs in
JISX0213_1_2004_set and JISX0213_2_set if the second wide character
in a combining sequence cannot be written because the buffer is
full. */
/* Since this is a stateful encoding we have to provide code which resets
the output state to the initial state. This has to be done during the
flushing. */
#define EMIT_SHIFT_TO_INIT \
if ((data->__statep->__count & ~7) != ASCII_set) \
if (data->__statep->__count != ASCII_set) \
{ \
if (FROM_DIRECTION) \
{ \
/* It's easy, we don't have to emit anything, we just reset the \
state for the input. */ \
data->__statep->__count &= 7; \
data->__statep->__count |= ASCII_set; \
if (__glibc_likely (outbuf + 4 <= outend)) \
{ \
/* Write out the last character. */ \
*((uint32_t *) outbuf) = data->__statep->__count >> 6; \
outbuf += sizeof (uint32_t); \
data->__statep->__count = ASCII_set; \
} \
else \
/* We don't have enough room in the output buffer. */ \
status = __GCONV_FULL_OUTPUT; \
} \
else \
{ \
@@ -151,7 +162,21 @@ enum
#define LOOPFCT FROM_LOOP
#define BODY \
{ \
uint32_t ch = *inptr; \
uint32_t ch; \
\
/* Output any pending character. */ \
ch = set >> 6; \
if (__glibc_unlikely (ch != 0)) \
{ \
put32 (outptr, ch); \
outptr += 4; \
/* Remove the pending character, but preserve state bits. */ \
set &= (1 << 6) - 1; \
continue; \
} \
\
/* Otherwise read the next input byte. */ \
ch = *inptr; \
\
/* Recognize escape sequences. */ \
if (__glibc_unlikely (ch == ESC)) \
@@ -297,21 +322,25 @@ enum
uint32_t u1 = __jisx0213_to_ucs_combining[ch - 1][0]; \
uint32_t u2 = __jisx0213_to_ucs_combining[ch - 1][1]; \
\
inptr += 2; \
\
put32 (outptr, u1); \
outptr += 4; \
\
/* See whether we have room for two characters. */ \
if (outptr + 8 <= outend) \
if (outptr + 4 <= outend) \
{ \
inptr += 2; \
put32 (outptr, u1); \
outptr += 4; \
put32 (outptr, u2); \
outptr += 4; \
continue; \
} \
else \
{ \
result = __GCONV_FULL_OUTPUT; \
break; \
} \
\
/* Otherwise store only the first character now, and \
put the second one into the queue. */ \
set |= u2 << 6; \
/* Tell the caller why we terminate the loop. */ \
result = __GCONV_FULL_OUTPUT; \
break; \
} \
\
inptr += 2; \
+1 -1
View File
@@ -23,7 +23,7 @@
# endif
# define DT_1_SUPPORTED_MASK \
(DF_1_NOW | DF_1_NODELETE | DF_1_INITFIRST | DF_1_NOOPEN \
| DF_1_ORIGIN | DF_1_NODEFLIB)
| DF_1_ORIGIN | DF_1_NODEFLIB | DF_1_PIE)
#endif /* !_ISOMAC */
#endif /* elf.h */
+1
View File
@@ -21,6 +21,7 @@
#ifdef USE_STAP_PROBE
# include <stap-probe-machine.h>
# include <sys/sdt.h>
/* Our code uses one macro LIBC_PROBE (name, n, arg1, ..., argn).
+4
View File
@@ -112,4 +112,8 @@ ifeq ($(build-static-nss),yes)
CFLAGS += -DSTATIC_NSS
endif
# The test uses dlopen indirectly and would otherwise load system
# objects.
tst-idna_name_classify-ENV = \
LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
$(objpfx)tst-idna_name_classify.out: $(gen-locales)
-5
View File
@@ -73,11 +73,6 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \
tst-fts tst-fts-lfs tst-open-tmpfile \
tst-copy_file_range tst-getcwd-abspath \
# This test includes the compat implementation of copy_file_range,
# which uses internal, unexported libc functions.
tests-static += tst-copy_file_range-compat
tests-internal += tst-copy_file_range-compat
# Likewise for statx, but we do not need static linking here.
tests-internal += tst-statx
-160
View File
@@ -1,160 +0,0 @@
/* Emulation of copy_file_range.
Copyright (C) 2017-2019 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 following macros should be defined before including this
file:
COPY_FILE_RANGE_DECL Declaration specifiers for the function below.
COPY_FILE_RANGE Name of the function to define. */
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
COPY_FILE_RANGE_DECL
ssize_t
COPY_FILE_RANGE (int infd, __off64_t *pinoff,
int outfd, __off64_t *poutoff,
size_t length, unsigned int flags)
{
if (flags != 0)
{
__set_errno (EINVAL);
return -1;
}
{
struct stat64 instat;
struct stat64 outstat;
if (fstat64 (infd, &instat) != 0 || fstat64 (outfd, &outstat) != 0)
return -1;
if (S_ISDIR (instat.st_mode) || S_ISDIR (outstat.st_mode))
{
__set_errno (EISDIR);
return -1;
}
if (!S_ISREG (instat.st_mode) || !S_ISREG (outstat.st_mode))
{
/* We need a regular input file so that the we can seek
backwards in case of a write failure. */
__set_errno (EINVAL);
return -1;
}
if (instat.st_dev != outstat.st_dev)
{
/* Cross-device copies are not supported. */
__set_errno (EXDEV);
return -1;
}
}
/* The output descriptor must not have O_APPEND set. */
{
int flags = __fcntl (outfd, F_GETFL);
if (flags & O_APPEND)
{
__set_errno (EBADF);
return -1;
}
}
/* Avoid an overflow in the result. */
if (length > SSIZE_MAX)
length = SSIZE_MAX;
/* Main copying loop. The buffer size is arbitrary and is a
trade-off between stack size consumption, cache usage, and
amortization of system call overhead. */
size_t copied = 0;
char buf[8192];
while (length > 0)
{
size_t to_read = length;
if (to_read > sizeof (buf))
to_read = sizeof (buf);
/* Fill the buffer. */
ssize_t read_count;
if (pinoff == NULL)
read_count = read (infd, buf, to_read);
else
read_count = __libc_pread64 (infd, buf, to_read, *pinoff);
if (read_count == 0)
/* End of file reached prematurely. */
return copied;
if (read_count < 0)
{
if (copied > 0)
/* Report the number of bytes copied so far. */
return copied;
return -1;
}
if (pinoff != NULL)
*pinoff += read_count;
/* Write the buffer part which was read to the destination. */
char *end = buf + read_count;
for (char *p = buf; p < end; )
{
ssize_t write_count;
if (poutoff == NULL)
write_count = write (outfd, p, end - p);
else
write_count = __libc_pwrite64 (outfd, p, end - p, *poutoff);
if (write_count < 0)
{
/* Adjust the input read position to match what we have
written, so that the caller can pick up after the
error. */
size_t written = p - buf;
/* NB: This needs to be signed so that we can form the
negative value below. */
ssize_t overread = read_count - written;
if (pinoff == NULL)
{
if (overread > 0)
{
/* We are on an error recovery path, so we
cannot deal with failure here. */
int save_errno = errno;
(void) __libc_lseek64 (infd, -overread, SEEK_CUR);
__set_errno (save_errno);
}
}
else /* pinoff != NULL */
*pinoff -= overread;
if (copied + written > 0)
/* Report the number of bytes copied so far. */
return copied + written;
return -1;
}
p += write_count;
if (poutoff != NULL)
*poutoff += write_count;
} /* Write loop. */
copied += read_count;
length -= read_count;
}
return copied;
}
+12 -4
View File
@@ -1,4 +1,4 @@
/* Generic implementation of copy_file_range.
/* Stub implementation of copy_file_range.
Copyright (C) 2017-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -16,7 +16,15 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#define COPY_FILE_RANGE_DECL
#define COPY_FILE_RANGE copy_file_range
#include <errno.h>
#include <unistd.h>
#include <io/copy_file_range-compat.c>
ssize_t
copy_file_range (int infd, __off64_t *pinoff,
int outfd, __off64_t *poutoff,
size_t length, unsigned int flags)
{
__set_errno (ENOSYS);
return -1;
}
stub_warning (copy_file_range)
+9 -551
View File
@@ -20,22 +20,15 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <libgen.h>
#include <poll.h>
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <support/check.h>
#include <support/namespace.h>
#include <support/support.h>
#include <support/temp_file.h>
#include <support/test-driver.h>
#include <support/xunistd.h>
#ifdef CLONE_NEWNS
# include <sys/mount.h>
#endif
/* Boolean flags which indicate whether to use pointers with explicit
output flags. */
@@ -49,10 +42,6 @@ static int infd;
static char *outfile;
static int outfd;
/* Like the above, but on a different file system. xdevfile can be
NULL if no suitable file system has been found. */
static char *xdevfile;
/* Input and output offsets. Set according to do_inoff and do_outoff
before the test. The offsets themselves are always set to
zero. */
@@ -61,13 +50,10 @@ static off64_t *pinoff;
static off64_t outoff;
static off64_t *poutoff;
/* These are a collection of copy sizes used in tests. The selection
takes into account that the fallback implementation uses an
internal buffer of 8192 bytes. */
/* These are a collection of copy sizes used in tests. */
enum { maximum_size = 99999 };
static const int typical_sizes[] =
{ 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, 16383, 16384, 16385,
maximum_size };
{ 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, maximum_size };
/* The random contents of this array can be used as a pattern to check
for correct write operations. */
@@ -76,101 +62,6 @@ static unsigned char random_data[maximum_size];
/* The size chosen by the test harness. */
static int current_size;
/* Maximum writable file offset. Updated by find_maximum_offset
below. */
static off64_t maximum_offset;
/* Error code when crossing the offset. */
static int maximum_offset_errno;
/* If true: Writes which cross the limit will fail. If false: Writes
which cross the limit will result in a partial write. */
static bool maximum_offset_hard_limit;
/* Fills maximum_offset etc. above. Truncates outfd as a side
effect. */
static void
find_maximum_offset (void)
{
xftruncate (outfd, 0);
if (maximum_offset != 0)
return;
uint64_t upper = -1;
upper >>= 1; /* Maximum of off64_t. */
TEST_VERIFY ((off64_t) upper > 0);
TEST_VERIFY ((off64_t) (upper + 1) < 0);
if (lseek64 (outfd, upper, SEEK_SET) >= 0)
{
if (write (outfd, "", 1) == 1)
FAIL_EXIT1 ("created a file larger than the off64_t range");
}
uint64_t lower = 1024 * 1024; /* A reasonable minimum file size. */
/* Loop invariant: writing at lower succeeds, writing at upper fails. */
while (lower + 1 < upper)
{
uint64_t middle = (lower + upper) / 2;
if (test_verbose > 0)
printf ("info: %s: remaining test range %" PRIu64 " .. %" PRIu64
", probe at %" PRIu64 "\n", __func__, lower, upper, middle);
xftruncate (outfd, 0);
if (lseek64 (outfd, middle, SEEK_SET) >= 0
&& write (outfd, "", 1) == 1)
lower = middle;
else
upper = middle;
}
TEST_VERIFY (lower + 1 == upper);
maximum_offset = lower;
printf ("info: maximum writable file offset: %" PRIu64 " (%" PRIx64 ")\n",
lower, lower);
/* Check that writing at the valid offset actually works. */
xftruncate (outfd, 0);
xlseek (outfd, lower, SEEK_SET);
TEST_COMPARE (write (outfd, "", 1), 1);
/* Cross the boundary with a two-byte write. This can either result
in a short write, or a failure. */
xlseek (outfd, lower, SEEK_SET);
ssize_t ret = write (outfd, " ", 2);
if (ret < 0)
{
maximum_offset_errno = errno;
maximum_offset_hard_limit = true;
}
else
maximum_offset_hard_limit = false;
/* Check that writing at the next offset actually fails. This also
obtains the expected errno value. */
xftruncate (outfd, 0);
const char *action;
if (lseek64 (outfd, lower + 1, SEEK_SET) != 0)
{
if (write (outfd, "", 1) != -1)
FAIL_EXIT1 ("write to impossible offset %" PRIu64 " succeeded",
lower + 1);
action = "writing";
int errno_copy = errno;
if (maximum_offset_hard_limit)
TEST_COMPARE (errno_copy, maximum_offset_errno);
else
maximum_offset_errno = errno_copy;
}
else
{
action = "seeking";
maximum_offset_errno = errno;
}
printf ("info: %s out of range fails with %m (%d)\n",
action, maximum_offset_errno);
xftruncate (outfd, 0);
xlseek (outfd, 0, SEEK_SET);
}
/* Perform a copy of a file. */
static void
simple_file_copy (void)
@@ -247,390 +138,6 @@ simple_file_copy (void)
free (bytes);
}
/* Test that reading from a pipe willfails. */
static void
pipe_as_source (void)
{
int pipefds[2];
xpipe (pipefds);
for (int length = 0; length < 2; ++length)
{
if (test_verbose > 0)
printf ("info: %s: length=%d\n", __func__, length);
/* Make sure that there is something to copy in the pipe. */
xwrite (pipefds[1], "@", 1);
TEST_COMPARE (copy_file_range (pipefds[0], pinoff, outfd, poutoff,
length, 0), -1);
/* Linux 4.10 and later return EINVAL. Older kernels return
EXDEV. */
TEST_VERIFY (errno == EINVAL || errno == EXDEV);
TEST_COMPARE (inoff, 0);
TEST_COMPARE (outoff, 0);
TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 0);
/* Make sure that nothing was read. */
char buf = 'A';
TEST_COMPARE (read (pipefds[0], &buf, 1), 1);
TEST_COMPARE (buf, '@');
}
xclose (pipefds[0]);
xclose (pipefds[1]);
}
/* Test that writing to a pipe fails. */
static void
pipe_as_destination (void)
{
/* Make sure that there is something to read in the input file. */
xwrite (infd, "abc", 3);
xlseek (infd, 0, SEEK_SET);
int pipefds[2];
xpipe (pipefds);
for (int length = 0; length < 2; ++length)
{
if (test_verbose > 0)
printf ("info: %s: length=%d\n", __func__, length);
TEST_COMPARE (copy_file_range (infd, pinoff, pipefds[1], poutoff,
length, 0), -1);
/* Linux 4.10 and later return EINVAL. Older kernels return
EXDEV. */
TEST_VERIFY (errno == EINVAL || errno == EXDEV);
TEST_COMPARE (inoff, 0);
TEST_COMPARE (outoff, 0);
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
/* Make sure that nothing was written. */
struct pollfd pollfd = { .fd = pipefds[0], .events = POLLIN, };
TEST_COMPARE (poll (&pollfd, 1, 0), 0);
}
xclose (pipefds[0]);
xclose (pipefds[1]);
}
/* Test a write failure after (potentially) writing some bytes.
Failure occurs near the start of the buffer. */
static void
delayed_write_failure_beginning (void)
{
/* We need to write something to provoke the error. */
if (current_size == 0)
return;
xwrite (infd, random_data, sizeof (random_data));
xlseek (infd, 0, SEEK_SET);
/* Write failure near the start. The actual error code varies among
file systems. */
find_maximum_offset ();
off64_t where = maximum_offset;
if (current_size == 1)
++where;
outoff = where;
if (do_outoff)
xlseek (outfd, 1, SEEK_SET);
else
xlseek (outfd, where, SEEK_SET);
if (maximum_offset_hard_limit || where > maximum_offset)
{
TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
sizeof (random_data), 0), -1);
TEST_COMPARE (errno, maximum_offset_errno);
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
TEST_COMPARE (inoff, 0);
if (do_outoff)
TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1);
else
TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where);
TEST_COMPARE (outoff, where);
struct stat64 st;
xfstat (outfd, &st);
TEST_COMPARE (st.st_size, 0);
}
else
{
/* The offset is not a hard limit. This means we write one
byte. */
TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
sizeof (random_data), 0), 1);
if (do_inoff)
{
TEST_COMPARE (inoff, 1);
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
}
else
{
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 1);
TEST_COMPARE (inoff, 0);
}
if (do_outoff)
{
TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1);
TEST_COMPARE (outoff, where + 1);
}
else
{
TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where + 1);
TEST_COMPARE (outoff, where);
}
struct stat64 st;
xfstat (outfd, &st);
TEST_COMPARE (st.st_size, where + 1);
}
}
/* Test a write failure after (potentially) writing some bytes.
Failure occurs near the end of the buffer. */
static void
delayed_write_failure_end (void)
{
if (current_size <= 1)
/* This would be same as the first test because there is not
enough data to write to make a difference. */
return;
xwrite (infd, random_data, sizeof (random_data));
xlseek (infd, 0, SEEK_SET);
find_maximum_offset ();
off64_t where = maximum_offset - current_size + 1;
if (current_size == sizeof (random_data))
/* Otherwise we do not reach the non-writable byte. */
++where;
outoff = where;
if (do_outoff)
xlseek (outfd, 1, SEEK_SET);
else
xlseek (outfd, where, SEEK_SET);
ssize_t ret = copy_file_range (infd, pinoff, outfd, poutoff,
sizeof (random_data), 0);
if (ret < 0)
{
TEST_COMPARE (ret, -1);
TEST_COMPARE (errno, maximum_offset_errno);
struct stat64 st;
xfstat (outfd, &st);
TEST_COMPARE (st.st_size, 0);
}
else
{
/* The first copy succeeded. This happens in the emulation
because the internal buffer of limited size does not
necessarily cross the off64_t boundary on the first write
operation. */
if (test_verbose > 0)
printf ("info: copy_file_range (%zu) returned %zd\n",
sizeof (random_data), ret);
TEST_VERIFY (ret > 0);
TEST_VERIFY (ret < maximum_size);
struct stat64 st;
xfstat (outfd, &st);
TEST_COMPARE (st.st_size, where + ret);
if (do_inoff)
{
TEST_COMPARE (inoff, ret);
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
}
else
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), ret);
char *buffer = xmalloc (ret);
TEST_COMPARE (pread64 (outfd, buffer, ret, where), ret);
TEST_VERIFY (memcmp (buffer, random_data, ret) == 0);
free (buffer);
/* The second copy fails. */
TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
sizeof (random_data), 0), -1);
TEST_COMPARE (errno, maximum_offset_errno);
}
}
/* Test a write failure across devices. */
static void
cross_device_failure (void)
{
if (xdevfile == NULL)
/* Subtest not supported due to missing cross-device file. */
return;
/* We need something to write. */
xwrite (infd, random_data, sizeof (random_data));
xlseek (infd, 0, SEEK_SET);
int xdevfd = xopen (xdevfile, O_RDWR | O_LARGEFILE, 0);
TEST_COMPARE (copy_file_range (infd, pinoff, xdevfd, poutoff,
current_size, 0), -1);
TEST_COMPARE (errno, EXDEV);
TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
struct stat64 st;
xfstat (xdevfd, &st);
TEST_COMPARE (st.st_size, 0);
xclose (xdevfd);
}
/* Try to exercise ENOSPC behavior with a tempfs file system (so that
we do not have to fill up a regular file system to get the error).
This function runs in a subprocess, so that we do not change the
mount namespace of the actual test process. */
static void
enospc_failure_1 (void *closure)
{
#ifdef CLONE_NEWNS
support_become_root ();
/* Make sure that we do not alter the file system mounts of the
parents. */
if (! support_enter_mount_namespace ())
{
printf ("warning: ENOSPC test skipped\n");
return;
}
char *mountpoint = closure;
if (mount ("none", mountpoint, "tmpfs", MS_NODEV | MS_NOEXEC,
"size=500k") != 0)
{
printf ("warning: could not mount tmpfs at %s: %m\n", mountpoint);
return;
}
/* The source file must reside on the same file system. */
char *intmpfsfile = xasprintf ("%s/%s", mountpoint, "in");
int intmpfsfd = xopen (intmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600);
xwrite (intmpfsfd, random_data, sizeof (random_data));
xlseek (intmpfsfd, 1, SEEK_SET);
inoff = 1;
char *outtmpfsfile = xasprintf ("%s/%s", mountpoint, "out");
int outtmpfsfd = xopen (outtmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600);
/* Fill the file with data until ENOSPC is reached. */
while (true)
{
ssize_t ret = write (outtmpfsfd, random_data, sizeof (random_data));
if (ret < 0 && errno != ENOSPC)
FAIL_EXIT1 ("write to %s: %m", outtmpfsfile);
if (ret < sizeof (random_data))
break;
}
TEST_COMPARE (write (outtmpfsfd, "", 1), -1);
TEST_COMPARE (errno, ENOSPC);
off64_t maxsize = xlseek (outtmpfsfd, 0, SEEK_CUR);
TEST_VERIFY_EXIT (maxsize > sizeof (random_data));
/* Constructed the expected file contents. */
char *expected = xmalloc (maxsize);
TEST_COMPARE (pread64 (outtmpfsfd, expected, maxsize, 0), maxsize);
/* Go back a little, so some bytes can be written. */
enum { offset = 20000 };
TEST_VERIFY_EXIT (offset < maxsize);
TEST_VERIFY_EXIT (offset < sizeof (random_data));
memcpy (expected + maxsize - offset, random_data + 1, offset);
if (do_outoff)
{
outoff = maxsize - offset;
xlseek (outtmpfsfd, 2, SEEK_SET);
}
else
xlseek (outtmpfsfd, -offset, SEEK_CUR);
/* First call is expected to succeed because we made room for some
bytes. */
TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff,
maximum_size, 0), offset);
if (do_inoff)
{
TEST_COMPARE (inoff, 1 + offset);
TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1);
}
else
TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset);
if (do_outoff)
{
TEST_COMPARE (outoff, maxsize);
TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2);
}
else
TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize);
struct stat64 st;
xfstat (outtmpfsfd, &st);
TEST_COMPARE (st.st_size, maxsize);
char *actual = xmalloc (st.st_size);
TEST_COMPARE (pread64 (outtmpfsfd, actual, st.st_size, 0), st.st_size);
TEST_VERIFY (memcmp (expected, actual, maxsize) == 0);
/* Second call should fail with ENOSPC. */
TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff,
maximum_size, 0), -1);
TEST_COMPARE (errno, ENOSPC);
/* Offsets should be unchanged. */
if (do_inoff)
{
TEST_COMPARE (inoff, 1 + offset);
TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1);
}
else
TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset);
if (do_outoff)
{
TEST_COMPARE (outoff, maxsize);
TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2);
}
else
TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize);
TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_END), maxsize);
TEST_COMPARE (pread64 (outtmpfsfd, actual, maxsize, 0), maxsize);
TEST_VERIFY (memcmp (expected, actual, maxsize) == 0);
free (actual);
free (expected);
xclose (intmpfsfd);
xclose (outtmpfsfd);
free (intmpfsfile);
free (outtmpfsfile);
#else /* !CLONE_NEWNS */
puts ("warning: ENOSPC test skipped (no mount namespaces)");
#endif
}
/* Call enospc_failure_1 in a subprocess. */
static void
enospc_failure (void)
{
char *mountpoint
= support_create_temp_directory ("tst-copy_file_range-enospc-");
support_isolate_in_subprocess (enospc_failure_1, mountpoint);
free (mountpoint);
}
/* The target file descriptor must have O_APPEND enabled. */
static void
oappend_failure (void)
{
/* Add data, to make sure we do not fail because there is
insufficient input data. */
xwrite (infd, random_data, current_size);
xlseek (infd, 0, SEEK_SET);
xclose (outfd);
outfd = xopen (outfile, O_RDWR | O_APPEND, 0);
TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
current_size, 0), -1);
TEST_COMPARE (errno, EBADF);
}
/* Test that a short input file results in a shortened copy. */
static void
short_copy (void)
@@ -721,14 +228,6 @@ struct test_case
static struct test_case tests[] =
{
{ "simple_file_copy", simple_file_copy, .sizes = true },
{ "pipe_as_source", pipe_as_source, },
{ "pipe_as_destination", pipe_as_destination, },
{ "delayed_write_failure_beginning", delayed_write_failure_beginning,
.sizes = true },
{ "delayed_write_failure_end", delayed_write_failure_end, .sizes = true },
{ "cross_device_failure", cross_device_failure, .sizes = true },
{ "enospc_failure", enospc_failure, },
{ "oappend_failure", oappend_failure, .sizes = true },
{ "short_copy", short_copy, .sizes = true },
};
@@ -739,58 +238,18 @@ do_test (void)
*p = rand () >> 24;
infd = create_temp_file ("tst-copy_file_range-in-", &infile);
outfd = create_temp_file ("tst-copy_file_range-out-", &outfile);
{
int outfd = create_temp_file ("tst-copy_file_range-out-", &outfile);
if (!support_descriptor_supports_holes (outfd))
FAIL_UNSUPPORTED ("File %s does not support holes", outfile);
xclose (outfd);
}
/* Try to find a different directory from the default input/output
file. */
{
struct stat64 instat;
xfstat (infd, &instat);
static const char *const candidates[] =
{ NULL, "/var/tmp", "/dev/shm" };
for (const char *const *c = candidates; c < array_end (candidates); ++c)
ssize_t ret = copy_file_range (infd, NULL, outfd, NULL, 0, 0);
if (ret != 0)
{
const char *path = *c;
char *to_free = NULL;
if (path == NULL)
{
to_free = xreadlink ("/proc/self/exe");
path = dirname (to_free);
}
struct stat64 cstat;
xstat (path, &cstat);
if (cstat.st_dev == instat.st_dev)
{
free (to_free);
continue;
}
printf ("info: using alternate temporary files directory: %s\n", path);
xdevfile = xasprintf ("%s/tst-copy_file_range-xdev-XXXXXX", path);
free (to_free);
break;
if (errno == ENOSYS)
FAIL_UNSUPPORTED ("copy_file_range is not support on this system");
FAIL_EXIT1 ("copy_file_range probing call: %m");
}
if (xdevfile != NULL)
{
int xdevfd = mkstemp (xdevfile);
if (xdevfd < 0)
FAIL_EXIT1 ("mkstemp (\"%s\"): %m", xdevfile);
struct stat64 xdevst;
xfstat (xdevfd, &xdevst);
TEST_VERIFY (xdevst.st_dev != instat.st_dev);
add_temp_file (xdevfile);
xclose (xdevfd);
}
else
puts ("warning: no alternate directory on different file system found");
}
xclose (infd);
xclose (outfd);
for (do_inoff = 0; do_inoff < 2; ++do_inoff)
for (do_outoff = 0; do_outoff < 2; ++do_outoff)
@@ -832,7 +291,6 @@ do_test (void)
free (infile);
free (outfile);
free (xdevfile);
return 0;
}
+15 -2
View File
@@ -65,7 +65,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \
tst-sprintf-ub tst-sprintf-chk-ub
tst-sprintf-ub tst-sprintf-chk-ub tst-wfile-sync
tests-internal = tst-vtables tst-vtables-interposed tst-readline
@@ -73,6 +73,9 @@ ifeq (yes,$(build-shared))
# Add test-fopenloc only if shared library is enabled since it depends on
# shared localedata objects.
tests += tst-fopenloc
# Add tst-bz24228 only if shared library is enabled since it can never meet its
# objective with static linking because the relevant code just is not there.
tests += tst-bz24228
endif
test-srcs = test-freopen
@@ -157,11 +160,14 @@ CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\"
CFLAGS-tst-sprintf-ub.c += -Wno-restrict
CFLAGS-tst-sprintf-chk-ub.c += -Wno-restrict
LDFLAGS-tst-bz24228 = -Wl,--version-script=tst-bz24228.map
tst_wprintf2-ARGS = "Some Text"
test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace
tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace
tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace
tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace
generated += test-fmemopen.mtrace test-fmemopen.check
generated += tst-fopenloc.mtrace tst-fopenloc.check
@@ -170,6 +176,7 @@ generated += tst-bz22415.mtrace tst-bz22415.check
aux := fileops genops stdfiles stdio strops
ifeq ($(build-shared),yes)
generated += tst-bz24228.mtrace tst-bz24228.check
aux += oldfileops oldstdfiles
endif
@@ -184,7 +191,8 @@ tests-special += $(objpfx)test-freopen.out $(objpfx)test-fmemopen-mem.out \
ifeq (yes,$(build-shared))
# Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared
# library is enabled since they depend on tst-fopenloc.out.
tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out
tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \
$(objpfx)tst-bz24228-mem.out
endif
endif
@@ -212,6 +220,7 @@ $(objpfx)tst-ungetwc1.out: $(gen-locales)
$(objpfx)tst-ungetwc2.out: $(gen-locales)
$(objpfx)tst-widetext.out: $(gen-locales)
$(objpfx)tst_wprintf2.out: $(gen-locales)
$(objpfx)tst-wfile-sync.out: $(gen-locales)
endif
$(objpfx)test-freopen.out: test-freopen.sh $(objpfx)test-freopen
@@ -235,3 +244,7 @@ $(objpfx)tst-fopenloc-mem.out: $(objpfx)tst-fopenloc.out
$(objpfx)tst-bz22415-mem.out: $(objpfx)tst-bz22415.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-bz22415.mtrace > $@; \
$(evaluate-test)
$(objpfx)tst-bz24228-mem.out: $(objpfx)tst-bz24228.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-bz24228.mtrace > $@; \
$(evaluate-test)
+12 -4
View File
@@ -789,9 +789,16 @@ _IO_unbuffer_all (void)
for (fp = (FILE *) _IO_list_all; fp; fp = fp->_chain)
{
int legacy = 0;
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
if (__glibc_unlikely (_IO_vtable_offset (fp) != 0))
legacy = 1;
#endif
if (! (fp->_flags & _IO_UNBUFFERED)
/* Iff stream is un-orientated, it wasn't used. */
&& fp->_mode != 0)
&& (legacy || fp->_mode != 0))
{
#ifdef _IO_MTSAFE_IO
int cnt;
@@ -805,7 +812,7 @@ _IO_unbuffer_all (void)
__sched_yield ();
#endif
if (! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
if (! legacy && ! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
{
fp->_flags |= _IO_USER_BUF;
@@ -816,7 +823,7 @@ _IO_unbuffer_all (void)
_IO_SETBUF (fp, NULL, 0);
if (fp->_mode > 0)
if (! legacy && fp->_mode > 0)
_IO_wsetb (fp, NULL, NULL, 0);
#ifdef _IO_MTSAFE_IO
@@ -827,7 +834,8 @@ _IO_unbuffer_all (void)
/* Make sure that never again the wide char functions can be
used. */
fp->_mode = -1;
if (! legacy)
fp->_mode = -1;
}
#ifdef _IO_MTSAFE_IO
+5
View File
@@ -87,6 +87,11 @@ _IO_check_libio (void)
stdout->_vtable_offset = stderr->_vtable_offset =
((int) sizeof (struct _IO_FILE)
- (int) sizeof (struct _IO_FILE_complete));
if (_IO_stdin_.vtable != &_IO_old_file_jumps
|| _IO_stdout_.vtable != &_IO_old_file_jumps
|| _IO_stderr_.vtable != &_IO_old_file_jumps)
IO_set_accept_foreign_vtables (&_IO_vtable_check);
}
}
+29
View File
@@ -0,0 +1,29 @@
/* BZ #24228 check for memory corruption in legacy libio
Copyright (C) 2019 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 <mcheck.h>
#include <support/test-driver.h>
static int
do_test (void)
{
mtrace ();
return 0;
}
#include <support/test-driver.c>
+5
View File
@@ -0,0 +1,5 @@
# Hide the symbol from libc.so.6 to switch to the libio/oldfileops.c
# implementation when it is available for the architecture.
{
local: _IO_stdin_used;
};
+39
View File
@@ -0,0 +1,39 @@
/* Test that _IO_wfile_sync does not crash (bug 20568).
Copyright (C) 2019 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 <locale.h>
#include <stdio.h>
#include <wchar.h>
#include <support/check.h>
#include <support/xunistd.h>
static int
do_test (void)
{
TEST_VERIFY_EXIT (setlocale (LC_ALL, "de_DE.UTF-8") != NULL);
/* Fill the stdio buffer and advance the read pointer. */
TEST_VERIFY_EXIT (fgetwc (stdin) != WEOF);
/* This calls _IO_wfile_sync, it should not crash. */
TEST_VERIFY_EXIT (setvbuf (stdin, NULL, _IONBF, 0) == 0);
/* Verify that the external file offset has been synchronized. */
TEST_COMPARE (xlseek (0, 0, SEEK_CUR), 1);
return 0;
}
#include <support/test-driver.c>
+1
View File
@@ -0,0 +1 @@
This is a test of _IO_wfile_sync.
+3 -2
View File
@@ -508,11 +508,12 @@ _IO_wfile_sync (FILE *fp)
generate the wide characters up to the current reading
position. */
int nread;
size_t wnread = (fp->_wide_data->_IO_read_ptr
- fp->_wide_data->_IO_read_base);
fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
fp->_IO_read_base,
fp->_IO_read_end, delta);
fp->_IO_read_end, wnread);
fp->_IO_read_ptr = fp->_IO_read_base + nread;
delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
}
+4 -2
View File
@@ -14946,12 +14946,14 @@ am_pm "<U5348><U524D>";"<U5348><U5F8C>"
t_fmt_ampm "%p%I<U6642>%M<U5206>%S<U79D2>"
era "+:2:1990//01//01:+*:<U5E73><U6210>:%EC%Ey<U5E74>";/
era "+:2:2020//01//01:+*:<U4EE4><U548C>:%EC%Ey<U5E74>";/
"+:1:2019//05//01:2019//12//31:<U4EE4><U548C>:%EC<U5143><U5E74>";/
"+:2:1990//01//01:2019//04//30:<U5E73><U6210>:%EC%Ey<U5E74>";/
"+:1:1989//01//08:1989//12//31:<U5E73><U6210>:%EC<U5143><U5E74>";/
"+:2:1927//01//01:1989//01//07:<U662D><U548C>:%EC%Ey<U5E74>";/
"+:1:1926//12//25:1926//12//31:<U662D><U548C>:%EC<U5143><U5E74>";/
"+:2:1913//01//01:1926//12//24:<U5927><U6B63>:%EC%Ey<U5E74>";/
"+:2:1912//07//30:1912//12//31:<U5927><U6B63>:%EC<U5143><U5E74>";/
"+:1:1912//07//30:1912//12//31:<U5927><U6B63>:%EC<U5143><U5E74>";/
"+:6:1873//01//01:1912//07//29:<U660E><U6CBB>:%EC%Ey<U5E74>";/
"+:1:0001//01//01:1872//12//31:<U897F><U66A6>:%EC%Ey<U5E74>";/
"+:1:-0001//12//31:-*:<U7D00><U5143><U524D>:%EC%Ey<U5E74>"
+3 -1
View File
@@ -54,7 +54,7 @@ tests-internal += \
tst-dynarray-at-fail \
ifneq (no,$(have-tunables))
tests += tst-malloc-usable-tunables
tests += tst-malloc-usable-tunables tst-mxfast
tests-static += tst-malloc-usable-static-tunables
endif
@@ -196,6 +196,8 @@ tst-malloc-usable-static-ENV = $(tst-malloc-usable-ENV)
tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3
tst-malloc-usable-static-tunables-ENV = $(tst-malloc-usable-tunables-ENV)
tst-mxfast-ENV = GLIBC_TUNABLES=glibc.malloc.tcache_count=0:glibc.malloc.mxfast=0
ifeq ($(experimental-malloc),yes)
CPPFLAGS-malloc.c += -DUSE_TCACHE=1
else
+2
View File
@@ -237,6 +237,7 @@ TUNABLE_CALLBACK_FNDECL (set_tcache_max, size_t)
TUNABLE_CALLBACK_FNDECL (set_tcache_count, size_t)
TUNABLE_CALLBACK_FNDECL (set_tcache_unsorted_limit, size_t)
#endif
TUNABLE_CALLBACK_FNDECL (set_mxfast, size_t)
#else
/* Initialization routine. */
#include <string.h>
@@ -324,6 +325,7 @@ ptmalloc_init (void)
TUNABLE_GET (tcache_unsorted_limit, size_t,
TUNABLE_CALLBACK (set_tcache_unsorted_limit));
# endif
TUNABLE_GET (mxfast, size_t, TUNABLE_CALLBACK (set_mxfast));
#else
const char *s = NULL;
if (__glibc_likely (_environ != NULL))
+37 -17
View File
@@ -321,6 +321,10 @@ __malloc_assert (const char *assertion, const char *file, unsigned int line,
/* This is another arbitrary limit, which tunables can change. Each
tcache bin will hold at most this number of chunks. */
# define TCACHE_FILL_COUNT 7
/* Maximum chunks in tcache bins for tunables. This value must fit the range
of tcache->counts[] entries, else they may overflow. */
# define MAX_TCACHE_COUNT UINT16_MAX
#endif
@@ -1631,7 +1635,7 @@ static INTERNAL_SIZE_T global_max_fast;
#define set_max_fast(s) \
global_max_fast = (((s) == 0) \
? SMALLBIN_WIDTH : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
? MIN_CHUNK_SIZE / 2 : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
static inline INTERNAL_SIZE_T
get_max_fast (void)
@@ -2915,7 +2919,7 @@ typedef struct tcache_entry
time), this is for performance reasons. */
typedef struct tcache_perthread_struct
{
char counts[TCACHE_MAX_BINS];
uint16_t counts[TCACHE_MAX_BINS];
tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;
@@ -2928,7 +2932,6 @@ static __always_inline void
tcache_put (mchunkptr chunk, size_t tc_idx)
{
tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
assert (tc_idx < TCACHE_MAX_BINS);
/* Mark this chunk as "in the tcache" so the test in _int_free will
detect a double free. */
@@ -2945,8 +2948,6 @@ static __always_inline void *
tcache_get (size_t tc_idx)
{
tcache_entry *e = tcache->entries[tc_idx];
assert (tc_idx < TCACHE_MAX_BINS);
assert (tcache->entries[tc_idx] > 0);
tcache->entries[tc_idx] = e->next;
--(tcache->counts[tc_idx]);
e->key = NULL;
@@ -3051,9 +3052,8 @@ __libc_malloc (size_t bytes)
DIAG_PUSH_NEEDS_COMMENT;
if (tc_idx < mp_.tcache_bins
/*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */
&& tcache
&& tcache->entries[tc_idx] != NULL)
&& tcache->counts[tc_idx] > 0)
{
return tcache_get (tc_idx);
}
@@ -3876,10 +3876,14 @@ _int_malloc (mstate av, size_t bytes)
{
victim->fd_nextsize = fwd;
victim->bk_nextsize = fwd->bk_nextsize;
if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd))
malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)");
fwd->bk_nextsize = victim;
victim->bk_nextsize->fd_nextsize = victim;
}
bck = fwd->bk;
if (bck->fd != fwd)
malloc_printerr ("malloc(): largebin double linked list corrupted (bk)");
}
}
else
@@ -5120,8 +5124,11 @@ static inline int
__always_inline
do_set_tcache_count (size_t value)
{
LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
mp_.tcache_count = value;
if (value <= MAX_TCACHE_COUNT)
{
LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
mp_.tcache_count = value;
}
return 1;
}
@@ -5135,6 +5142,19 @@ do_set_tcache_unsorted_limit (size_t value)
}
#endif
static inline int
__always_inline
do_set_mxfast (size_t value)
{
if (value >= 0 && value <= MAX_FAST_SIZE)
{
LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
set_max_fast (value);
return 1;
}
return 0;
}
int
__libc_mallopt (int param_number, int value)
{
@@ -5154,13 +5174,7 @@ __libc_mallopt (int param_number, int value)
switch (param_number)
{
case M_MXFAST:
if (value >= 0 && value <= MAX_FAST_SIZE)
{
LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
set_max_fast (value);
}
else
res = 0;
do_set_mxfast (value);
break;
case M_TRIM_THRESHOLD:
@@ -5426,6 +5440,12 @@ __malloc_info (int options, FILE *fp)
__libc_lock_lock (ar_ptr->mutex);
/* Account for top chunk. The top-most available chunk is
treated specially and is never in any bin. See "initial_top"
comments. */
avail = chunksize (ar_ptr->top);
nblocks = 1; /* Top always exists. */
for (size_t i = 0; i < NFASTBINS; ++i)
{
mchunkptr p = fastbin (ar_ptr, i);
@@ -5511,7 +5531,7 @@ __malloc_info (int options, FILE *fp)
for (size_t i = 0; i < nsizes; ++i)
if (sizes[i].count != 0 && i != NFASTBINS)
fprintf (fp, " \
fprintf (fp, "\
<size from=\"%zu\" to=\"%zu\" total=\"%zu\" count=\"%zu\"/>\n",
sizes[i].from, sizes[i].to, sizes[i].total, sizes[i].count);
+46 -26
View File
@@ -121,6 +121,41 @@ lock_and_info (const void *caller, Dl_info *mem)
return res;
}
static void tr_freehook (void *, const void *);
static void * tr_mallochook (size_t, const void *);
static void * tr_reallochook (void *, size_t, const void *);
static void * tr_memalignhook (size_t, size_t, const void *);
/* Set all the default non-trace hooks. */
static __always_inline void
set_default_hooks (void)
{
__free_hook = tr_old_free_hook;
__malloc_hook = tr_old_malloc_hook;
__realloc_hook = tr_old_realloc_hook;
__memalign_hook = tr_old_memalign_hook;
}
/* Set all of the tracing hooks used for mtrace. */
static __always_inline void
set_trace_hooks (void)
{
__free_hook = tr_freehook;
__malloc_hook = tr_mallochook;
__realloc_hook = tr_reallochook;
__memalign_hook = tr_memalignhook;
}
/* Save the current set of hooks as the default hooks. */
static __always_inline void
save_default_hooks (void)
{
tr_old_free_hook = __free_hook;
tr_old_malloc_hook = __malloc_hook;
tr_old_realloc_hook = __realloc_hook;
tr_old_memalign_hook = __memalign_hook;
}
static void
tr_freehook (void *ptr, const void *caller)
{
@@ -138,12 +173,12 @@ tr_freehook (void *ptr, const void *caller)
tr_break ();
__libc_lock_lock (lock);
}
__free_hook = tr_old_free_hook;
set_default_hooks ();
if (tr_old_free_hook != NULL)
(*tr_old_free_hook)(ptr, caller);
else
free (ptr);
__free_hook = tr_freehook;
set_trace_hooks ();
__libc_lock_unlock (lock);
}
@@ -155,12 +190,12 @@ tr_mallochook (size_t size, const void *caller)
Dl_info mem;
Dl_info *info = lock_and_info (caller, &mem);
__malloc_hook = tr_old_malloc_hook;
set_default_hooks ();
if (tr_old_malloc_hook != NULL)
hdr = (void *) (*tr_old_malloc_hook)(size, caller);
else
hdr = (void *) malloc (size);
__malloc_hook = tr_mallochook;
set_trace_hooks ();
tr_where (caller, info);
/* We could be printing a NULL here; that's OK. */
@@ -185,16 +220,12 @@ tr_reallochook (void *ptr, size_t size, const void *caller)
Dl_info mem;
Dl_info *info = lock_and_info (caller, &mem);
__free_hook = tr_old_free_hook;
__malloc_hook = tr_old_malloc_hook;
__realloc_hook = tr_old_realloc_hook;
set_default_hooks ();
if (tr_old_realloc_hook != NULL)
hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
else
hdr = (void *) realloc (ptr, size);
__free_hook = tr_freehook;
__malloc_hook = tr_mallochook;
__realloc_hook = tr_reallochook;
set_trace_hooks ();
tr_where (caller, info);
if (hdr == NULL)
@@ -230,14 +261,12 @@ tr_memalignhook (size_t alignment, size_t size, const void *caller)
Dl_info mem;
Dl_info *info = lock_and_info (caller, &mem);
__memalign_hook = tr_old_memalign_hook;
__malloc_hook = tr_old_malloc_hook;
set_default_hooks ();
if (tr_old_memalign_hook != NULL)
hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
else
hdr = (void *) memalign (alignment, size);
__memalign_hook = tr_memalignhook;
__malloc_hook = tr_mallochook;
set_trace_hooks ();
tr_where (caller, info);
/* We could be printing a NULL here; that's OK. */
@@ -305,14 +334,8 @@ mtrace (void)
malloc_trace_buffer = mtb;
setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
fprintf (mallstream, "= Start\n");
tr_old_free_hook = __free_hook;
__free_hook = tr_freehook;
tr_old_malloc_hook = __malloc_hook;
__malloc_hook = tr_mallochook;
tr_old_realloc_hook = __realloc_hook;
__realloc_hook = tr_reallochook;
tr_old_memalign_hook = __memalign_hook;
__memalign_hook = tr_memalignhook;
save_default_hooks ();
set_trace_hooks ();
#ifdef _LIBC
if (!added_atexit_handler)
{
@@ -338,10 +361,7 @@ muntrace (void)
file. */
FILE *f = mallstream;
mallstream = NULL;
__free_hook = tr_old_free_hook;
__malloc_hook = tr_old_malloc_hook;
__realloc_hook = tr_old_realloc_hook;
__memalign_hook = tr_old_memalign_hook;
set_default_hooks ();
fprintf (f, "= End\n");
fclose (f);
+39
View File
@@ -72,13 +72,28 @@ test_large_allocations (size_t size)
void * ptr_to_realloc;
test_setup ();
DIAG_PUSH_NEEDS_COMMENT;
#if __GNUC_PREREQ (7, 0)
/* GCC 7 warns about too-large allocations; here we want to test
that they fail. */
DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
#endif
TEST_VERIFY (malloc (size) == NULL);
#if __GNUC_PREREQ (7, 0)
DIAG_POP_NEEDS_COMMENT;
#endif
TEST_VERIFY (errno == ENOMEM);
ptr_to_realloc = malloc (16);
TEST_VERIFY_EXIT (ptr_to_realloc != NULL);
test_setup ();
#if __GNUC_PREREQ (7, 0)
DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
#endif
TEST_VERIFY (realloc (ptr_to_realloc, size) == NULL);
#if __GNUC_PREREQ (7, 0)
DIAG_POP_NEEDS_COMMENT;
#endif
TEST_VERIFY (errno == ENOMEM);
free (ptr_to_realloc);
@@ -135,7 +150,13 @@ test_large_aligned_allocations (size_t size)
for (align = 1; align <= pagesize; align *= 2)
{
test_setup ();
#if __GNUC_PREREQ (7, 0)
DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
#endif
TEST_VERIFY (memalign (align, size) == NULL);
#if __GNUC_PREREQ (7, 0)
DIAG_POP_NEEDS_COMMENT;
#endif
TEST_VERIFY (errno == ENOMEM);
/* posix_memalign expects an alignment that is a power of 2 *and* a
@@ -151,7 +172,13 @@ test_large_aligned_allocations (size_t size)
if ((size % align) == 0)
{
test_setup ();
#if __GNUC_PREREQ (7, 0)
DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
#endif
TEST_VERIFY (aligned_alloc (align, size) == NULL);
#if __GNUC_PREREQ (7, 0)
DIAG_POP_NEEDS_COMMENT;
#endif
TEST_VERIFY (errno == ENOMEM);
}
}
@@ -159,11 +186,23 @@ test_large_aligned_allocations (size_t size)
/* Both valloc and pvalloc return page-aligned memory. */
test_setup ();
#if __GNUC_PREREQ (7, 0)
DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
#endif
TEST_VERIFY (valloc (size) == NULL);
#if __GNUC_PREREQ (7, 0)
DIAG_POP_NEEDS_COMMENT;
#endif
TEST_VERIFY (errno == ENOMEM);
test_setup ();
#if __GNUC_PREREQ (7, 0)
DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
#endif
TEST_VERIFY (pvalloc (size) == NULL);
#if __GNUC_PREREQ (7, 0)
DIAG_POP_NEEDS_COMMENT;
#endif
TEST_VERIFY (errno == ENOMEM);
}
+10
View File
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <libc-diag.h>
static int errors = 0;
@@ -41,9 +42,18 @@ do_test (void)
errno = 0;
DIAG_PUSH_NEEDS_COMMENT;
#if __GNUC_PREREQ (7, 0)
/* GCC 7 warns about too-large allocations; here we want to test
that they fail. */
DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
#endif
/* An attempt to allocate a huge value should return NULL and set
errno to ENOMEM. */
p = memalign (sizeof (void *), -1);
#if __GNUC_PREREQ (7, 0)
DIAG_POP_NEEDS_COMMENT;
#endif
save = errno;
+50
View File
@@ -0,0 +1,50 @@
/* Test that glibc.malloc.mxfast tunable works.
Copyright (C) 2019 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/>. */
/* This test verifies that setting the glibc.malloc.mxfast tunable to
zero results in free'd blocks being returned to the small bins, not
the fast bins. */
#include <malloc.h>
#include <support/check.h>
int
do_test (void)
{
struct mallinfo m;
char *volatile p1;
char *volatile p2;
/* Arbitrary value; must be in default fastbin range. */
p1 = malloc (3);
/* Something large so that p1 isn't a "top block" */
p2 = malloc (512);
free (p1);
m = mallinfo ();
/* This will fail if there are any blocks in the fastbins. */
TEST_COMPARE (m.smblks, 0);
/* To keep gcc happy. */
free (p2);
return 0;
}
#include <support/test-driver.c>
+5 -5
View File
@@ -1404,10 +1404,13 @@ failure occurs. The return value is zero if the end of the input file
is encountered immediately.
If no bytes can be copied, to report an error, @code{copy_file_range}
returns the value @math{-1} and sets @code{errno}. The following
@code{errno} error conditions are specific to this function:
returns the value @math{-1} and sets @code{errno}. The table below
lists some of the error conditions for this function.
@table @code
@item ENOSYS
The kernel does not implement the required functionality.
@item EISDIR
At least one of the descriptors @var{inputfd} or @var{outputfd} refers
to a directory.
@@ -1437,9 +1440,6 @@ reading.
The argument @var{outputfd} is not a valid file descriptor open for
writing, or @var{outputfd} has been opened with @code{O_APPEND}.
@item EXDEV
The input and output files reside on different file systems.
@end table
In addition, @code{copy_file_range} can fail with the error codes
+14 -2
View File
@@ -189,8 +189,8 @@ per-thread cache. The default (and maximum) value is 1032 bytes on
@deftp Tunable glibc.malloc.tcache_count
The maximum number of chunks of each size to cache. The default is 7.
There is no upper limit, other than available system memory. If set
to zero, the per-thread cache is effectively disabled.
The upper limit is 65535. If set to zero, the per-thread cache is effectively
disabled.
The approximate maximum overhead of the per-thread cache is thus equal
to the number of bins times the chunk count in each bin times the size
@@ -214,6 +214,18 @@ pre-fill the per-thread cache with. The default, or when set to zero,
is no limit.
@end deftp
@deftp Tunable glibc.malloc.mxfast
One of the optimizations malloc uses is to maintain a series of ``fast
bins'' that hold chunks up to a specific size. The default and
maximum size which may be held this way is 80 bytes on 32-bit systems
or 160 bytes on 64-bit systems. Applications which value size over
speed may choose to reduce the size of requests which are serviced
from fast bins with this tunable. Note that the value specified
includes malloc's internal overhead, which is normally the size of one
pointer, so add 4 on 32-bit systems or 8 on 64-bit systems to the size
passed to @code{malloc} for the largest bin size to enable.
@end deftp
@node Elision Tunables
@section Elision Tunables
@cindex elision tunables
+2 -1
View File
@@ -319,7 +319,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \
tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \
tst-rwlock-pwn
tst-rwlock-pwn \
tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall
tests-internal := tst-rwlock19 tst-rwlock20 \
tst-sem11 tst-sem12 tst-sem13 \
+3 -1
View File
@@ -572,7 +572,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
/* Place the thread descriptor at the end of the stack. */
#if TLS_TCB_AT_TP
pd = (struct pthread *) ((char *) mem + size) - 1;
pd = (struct pthread *) ((((uintptr_t) mem + size)
- TLS_TCB_SIZE)
& ~__static_tls_align_m1);
#elif TLS_DTV_AT_TP
pd = (struct pthread *) ((((uintptr_t) mem + size
- __static_tls_size)
+3 -2
View File
@@ -86,6 +86,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
pthread_cleanup_pop (0);
}
void *pd_result = pd->result;
if (__glibc_likely (result == 0))
{
/* We mark the thread as terminated and as joined. */
@@ -93,7 +94,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
/* Store the return value if the caller is interested. */
if (thread_return != NULL)
*thread_return = pd->result;
*thread_return = pd_result;
/* Free the TCB. */
__free_tcb (pd);
@@ -101,7 +102,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
else
pd->joinid = NULL;
LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd->result);
LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd_result);
return result;
}
+59 -6
View File
@@ -56,7 +56,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
return 0;
}
if (lll_trylock (mutex->__data.__lock) == 0)
if (atomic_load_relaxed (&(mutex->__data.__lock)) == 0
&& lll_trylock (mutex->__data.__lock) == 0)
{
/* Record the ownership. */
mutex->__data.__owner = id;
@@ -79,7 +80,10 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
/*FALL THROUGH*/
case PTHREAD_MUTEX_ADAPTIVE_NP:
case PTHREAD_MUTEX_ERRORCHECK_NP:
if (lll_trylock (mutex->__data.__lock) != 0)
/* Mutex type is already loaded, lock check overhead should
be minimal. */
if (atomic_load_relaxed (&(mutex->__data.__lock)) != 0
|| lll_trylock (mutex->__data.__lock) != 0)
break;
/* Record the ownership. */
@@ -94,6 +98,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
&mutex->__data.__list.__next);
/* We need to set op_pending before starting the operation. Also
see comments at ENQUEUE_MUTEX. */
__asm ("" ::: "memory");
oldval = mutex->__data.__lock;
do
@@ -119,7 +126,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
/* But it is inconsistent unless marked otherwise. */
mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
/* We must not enqueue the mutex before we have acquired it.
Also see comments at ENQUEUE_MUTEX. */
__asm ("" ::: "memory");
ENQUEUE_MUTEX (mutex);
/* We need to clear op_pending after we enqueue the mutex. */
__asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Note that we deliberately exist here. If we fall
@@ -135,6 +147,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
int kind = PTHREAD_MUTEX_TYPE (mutex);
if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP)
{
/* We do not need to ensure ordering wrt another memory
access. Also see comments at ENQUEUE_MUTEX. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
NULL);
return EDEADLK;
@@ -142,6 +156,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP)
{
/* We do not need to ensure ordering wrt another memory
access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
NULL);
@@ -160,6 +176,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
id, 0);
if (oldval != 0 && (oldval & FUTEX_OWNER_DIED) == 0)
{
/* We haven't acquired the lock as it is already acquired by
another owner. We do not need to ensure ordering wrt another
memory access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EBUSY;
@@ -173,13 +192,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
if (oldval == id)
lll_unlock (mutex->__data.__lock,
PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
/* FIXME This violates the mutex destruction requirements. See
__pthread_mutex_unlock_full. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return ENOTRECOVERABLE;
}
}
while ((oldval & FUTEX_OWNER_DIED) != 0);
/* We must not enqueue the mutex before we have acquired it.
Also see comments at ENQUEUE_MUTEX. */
__asm ("" ::: "memory");
ENQUEUE_MUTEX (mutex);
/* We need to clear op_pending after we enqueue the mutex. */
__asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
mutex->__data.__owner = id;
@@ -211,10 +237,15 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
}
if (robust)
/* Note: robust PI futexes are signaled by setting bit 0. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
(void *) (((uintptr_t) &mutex->__data.__list.__next)
| 1));
{
/* Note: robust PI futexes are signaled by setting bit 0. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
(void *) (((uintptr_t) &mutex->__data.__list.__next)
| 1));
/* We need to set op_pending before starting the operation. Also
see comments at ENQUEUE_MUTEX. */
__asm ("" ::: "memory");
}
oldval = mutex->__data.__lock;
@@ -223,12 +254,16 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
{
if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
{
/* We do not need to ensure ordering wrt another memory
access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EDEADLK;
}
if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
{
/* We do not need to ensure ordering wrt another memory
access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Just bump the counter. */
@@ -250,6 +285,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
{
if ((oldval & FUTEX_OWNER_DIED) == 0)
{
/* We haven't acquired the lock as it is already acquired by
another owner. We do not need to ensure ordering wrt another
memory access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EBUSY;
@@ -270,6 +308,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
if (INTERNAL_SYSCALL_ERROR_P (e, __err)
&& INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK)
{
/* The kernel has not yet finished the mutex owner death.
We do not need to ensure ordering wrt another memory
access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EBUSY;
@@ -287,7 +328,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
/* But it is inconsistent unless marked otherwise. */
mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
/* We must not enqueue the mutex before we have acquired it.
Also see comments at ENQUEUE_MUTEX. */
__asm ("" ::: "memory");
ENQUEUE_MUTEX (mutex);
/* We need to clear op_pending after we enqueue the mutex. */
__asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Note that we deliberately exit here. If we fall
@@ -310,13 +356,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
PTHREAD_ROBUST_MUTEX_PSHARED (mutex)),
0, 0);
/* To the kernel, this will be visible after the kernel has
acquired the mutex in the syscall. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return ENOTRECOVERABLE;
}
if (robust)
{
/* We must not enqueue the mutex before we have acquired it.
Also see comments at ENQUEUE_MUTEX. */
__asm ("" ::: "memory");
ENQUEUE_MUTEX_PI (mutex);
/* We need to clear op_pending after we enqueue the mutex. */
__asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
}
+16 -9
View File
@@ -94,15 +94,22 @@ __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
/* Same as in __pthread_rwlock_rdlock_full:
We started the read phase, so we are also responsible for
updating the write-phase futex. Relaxed MO is sufficient.
Note that there can be no other reader that we have to wake
because all other readers will see the read phase started by us
(or they will try to start it themselves); if a writer started
the read phase, we cannot have started it. Furthermore, we
cannot discard a PTHREAD_RWLOCK_FUTEX_USED flag because we will
overwrite the value set by the most recent writer (or the readers
before it in case of explicit hand-over) and we know that there
are no waiting readers. */
atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0);
We have to do the same steps as a writer would when handing over the
read phase to use because other readers cannot distinguish between
us and the writer.
Note that __pthread_rwlock_tryrdlock callers will not have to be
woken up because they will either see the read phase started by us
or they will try to start it themselves; however, callers of
__pthread_rwlock_rdlock_full just increase the reader count and then
check what state the lock is in, so they cannot distinguish between
us and a writer that acquired and released the lock in the
meantime. */
if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0)
& PTHREAD_RWLOCK_FUTEX_USED) != 0)
{
int private = __pthread_rwlock_get_private (rwlock);
futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private);
}
}
return 0;
+8 -1
View File
@@ -46,8 +46,15 @@ __pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
&rwlock->__data.__readers, &r,
r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED))
{
/* We have become the primary writer and we cannot have shared
the PTHREAD_RWLOCK_FUTEX_USED flag with someone else, so we
can simply enable blocking (see full wrlock code). */
atomic_store_relaxed (&rwlock->__data.__writers_futex, 1);
atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
/* If we started a write phase, we need to enable readers to
wait. If we did not, we must not change it because other threads
may have set the PTHREAD_RWLOCK_FUTEX_USED in the meantime. */
if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
atomic_store_relaxed (&rwlock->__data.__cur_writer,
THREAD_GETMEM (THREAD_SELF, tid));
return 0;
+5 -3
View File
@@ -107,13 +107,14 @@ __unregister_atfork (void *dso_handle)
}
void
__run_fork_handlers (enum __run_fork_handler_type who)
__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking)
{
struct fork_handler *runp;
if (who == atfork_run_prepare)
{
lll_lock (atfork_lock, LLL_PRIVATE);
if (do_locking)
lll_lock (atfork_lock, LLL_PRIVATE);
size_t sl = fork_handler_list_size (&fork_handlers);
for (size_t i = sl; i > 0; i--)
{
@@ -133,7 +134,8 @@ __run_fork_handlers (enum __run_fork_handler_type who)
else if (who == atfork_run_parent && runp->parent_handler)
runp->parent_handler ();
}
lll_unlock (atfork_lock, LLL_PRIVATE);
if (do_locking)
lll_unlock (atfork_lock, LLL_PRIVATE);
}
}
+355
View File
@@ -0,0 +1,355 @@
/* Bug 23844: Test for pthread_rwlock_tryrdlock stalls.
Copyright (C) 2019 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/>. */
/* For a full analysis see comment:
https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14
Provided here for reference:
--- Analysis of pthread_rwlock_tryrdlock() stall ---
A read lock begins to execute.
In __pthread_rwlock_rdlock_full:
We can attempt a read lock, but find that the lock is
in a write phase (PTHREAD_RWLOCK_WRPHASE, or WP-bit
is set), and the lock is held by a primary writer
(PTHREAD_RWLOCK_WRLOCKED is set). In this case we must
wait for explicit hand over from the writer to us or
one of the other waiters. The read lock threads are
about to execute:
341 r = (atomic_fetch_add_acquire (&rwlock->__data.__readers,
342 (1 << PTHREAD_RWLOCK_READER_SHIFT))
343 + (1 << PTHREAD_RWLOCK_READER_SHIFT));
An unlock beings to execute.
Then in __pthread_rwlock_wrunlock:
547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers);
...
549 while (!atomic_compare_exchange_weak_release
550 (&rwlock->__data.__readers, &r,
551 ((r ^ PTHREAD_RWLOCK_WRLOCKED)
552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0
553 : PTHREAD_RWLOCK_WRPHASE))))
554 {
...
556 }
We clear PTHREAD_RWLOCK_WRLOCKED, and if there are
no readers so we leave the lock in PTHRAD_RWLOCK_WRPHASE.
Back in the read lock.
The read lock adjusts __readres as above.
383 while ((r & PTHREAD_RWLOCK_WRPHASE) != 0
384 && (r & PTHREAD_RWLOCK_WRLOCKED) == 0)
385 {
...
390 if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, &r,
391 r ^ PTHREAD_RWLOCK_WRPHASE))
392 {
And then attemps to start the read phase.
Assume there happens to be a tryrdlock at this point, noting
that PTHREAD_RWLOCK_WRLOCKED is clear, and PTHREAD_RWLOCK_WRPHASE
is 1. So the try lock attemps to start the read phase.
In __pthread_rwlock_tryrdlock:
44 if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
45 {
...
49 if (((r & PTHREAD_RWLOCK_WRLOCKED) != 0)
50 && (rwlock->__data.__flags
51 == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP))
52 return EBUSY;
53 rnew = r + (1 << PTHREAD_RWLOCK_READER_SHIFT);
54 }
...
89 while (!atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers,
90 &r, rnew));
And succeeds.
Back in the write unlock:
557 if ((r >> PTHREAD_RWLOCK_READER_SHIFT) != 0)
558 {
...
563 if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0)
564 & PTHREAD_RWLOCK_FUTEX_USED) != 0)
565 futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private);
566 }
We note that PTHREAD_RWLOCK_FUTEX_USED is non-zero
and don't wake anyone. This is OK because we handed
over to the trylock. It will be the trylock's responsibility
to wake any waiters.
Back in the read lock:
The read lock fails to install PTHRAD_REWLOCK_WRPHASE as 0 because
the __readers value was adjusted by the trylock, and so it falls through
to waiting on the lock for explicit handover from either a new writer
or a new reader.
448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
449 1 | PTHREAD_RWLOCK_FUTEX_USED,
450 abstime, private);
We use PTHREAD_RWLOCK_FUTEX_USED to indicate the futex
is in use.
At this point we have readers waiting on the read lock
to unlock. The wrlock is done. The trylock is finishing
the installation of the read phase.
92 if ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
93 {
...
105 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0);
106 }
The trylock does note that we were the one that
installed the read phase, but the comments are not
correct, the execution ordering above shows that
readers might indeed be waiting, and they are.
The atomic_store_relaxed throws away PTHREAD_RWLOCK_FUTEX_USED,
and the waiting reader is never worken becuase as noted
above it is conditional on the futex being used.
The solution is for the trylock thread to inspect
PTHREAD_RWLOCK_FUTEX_USED and wake the waiting readers.
--- Analysis of pthread_rwlock_trywrlock() stall ---
A write lock begins to execute, takes the write lock,
and then releases the lock...
In pthread_rwlock_wrunlock():
547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers);
...
549 while (!atomic_compare_exchange_weak_release
550 (&rwlock->__data.__readers, &r,
551 ((r ^ PTHREAD_RWLOCK_WRLOCKED)
552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0
553 : PTHREAD_RWLOCK_WRPHASE))))
554 {
...
556 }
... leaving it in the write phase with zero readers
(the case where we leave the write phase in place
during a write unlock).
A write trylock begins to execute.
In __pthread_rwlock_trywrlock:
40 while (((r & PTHREAD_RWLOCK_WRLOCKED) == 0)
41 && (((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0)
42 || (prefer_writer && ((r & PTHREAD_RWLOCK_WRPHASE) != 0))))
43 {
The lock is not locked.
There are no readers.
45 if (atomic_compare_exchange_weak_acquire (
46 &rwlock->__data.__readers, &r,
47 r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED))
We atomically install the write phase and we take the
exclusive write lock.
48 {
49 atomic_store_relaxed (&rwlock->__data.__writers_futex, 1);
We get this far.
A reader lock begins to execute.
In pthread_rwlock_rdlock:
437 for (;;)
438 {
439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
441 {
442 int private = __pthread_rwlock_get_private (rwlock);
443 if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
444 && (!atomic_compare_exchange_weak_relaxed
445 (&rwlock->__data.__wrphase_futex,
446 &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED)))
447 continue;
448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
449 1 | PTHREAD_RWLOCK_FUTEX_USED,
450 abstime, private);
We are in a write phase, so the while() on line 439 is true.
The value of wpf does not have PTHREAD_RWLOCK_FUTEX_USED set
since this is the first reader to lock.
The atomic operation sets wpf with PTHREAD_RELOCK_FUTEX_USED
on the expectation that this reader will be woken during
the handoff.
Back in pthread_rwlock_trywrlock:
50 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
51 atomic_store_relaxed (&rwlock->__data.__cur_writer,
52 THREAD_GETMEM (THREAD_SELF, tid));
53 return 0;
54 }
...
57 }
We write 1 to __wrphase_futex discarding PTHREAD_RWLOCK_FUTEX_USED,
and so in the unlock we will not awaken the waiting reader.
The solution to this is to realize that if we did not start the write
phase we need not write 1 or any other value to __wrphase_futex.
This ensures that any readers (which saw __wrphase_futex != 0) can
set PTHREAD_RWLOCK_FUTEX_USED and this can be used at unlock to
wake them.
If we installed the write phase then all other readers are looping
here:
In __pthread_rwlock_rdlock_full:
437 for (;;)
438 {
439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
441 {
...
508 }
waiting for the write phase to be installed or removed before they
can begin waiting on __wrphase_futex (part of the algorithm), or
taking a concurrent read lock, and thus we can safely write 1 to
__wrphase_futex.
If we did not install the write phase then the readers may already
be waiting on the futex, the original writer wrote 1 to __wrphase_futex
as part of starting the write phase, and we cannot also write 1
without loosing the PTHREAD_RWLOCK_FUTEX_USED bit.
---
Summary for the pthread_rwlock_tryrdlock() stall:
The stall is caused by pthread_rwlock_tryrdlock failing to check
that PTHREAD_RWLOCK_FUTEX_USED is set in the __wrphase_futex futex
and then waking the futex.
The fix for bug 23844 ensures that waiters on __wrphase_futex are
correctly woken. Before the fix the test stalls as readers can
wait forever on __wrphase_futex. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <support/xthread.h>
#include <errno.h>
/* We need only one lock to reproduce the issue. We will need multiple
threads to get the exact case where we have a read, try, and unlock
all interleaving to produce the case where the readers are waiting
and the try fails to wake them. */
pthread_rwlock_t onelock;
/* The number of threads is arbitrary but empirically chosen to have
enough threads that we see the condition where waiting readers are
not woken by a successful tryrdlock. */
#define NTHREADS 32
_Atomic int do_exit;
void *
run_loop (void *arg)
{
int i = 0, ret;
while (!do_exit)
{
/* Arbitrarily choose if we are the writer or reader. Choose a
high enough ratio of readers to writers to make it likely
that readers block (and eventually are susceptable to
stalling).
If we are a writer, take the write lock, and then unlock.
If we are a reader, try the lock, then lock, then unlock. */
if ((i % 8) != 0)
xpthread_rwlock_wrlock (&onelock);
else
{
if ((ret = pthread_rwlock_tryrdlock (&onelock)) != 0)
{
if (ret == EBUSY)
xpthread_rwlock_rdlock (&onelock);
else
exit (EXIT_FAILURE);
}
}
/* Thread does some work and then unlocks. */
xpthread_rwlock_unlock (&onelock);
i++;
}
return NULL;
}
int
do_test (void)
{
int i;
pthread_t tids[NTHREADS];
xpthread_rwlock_init (&onelock, NULL);
for (i = 0; i < NTHREADS; i++)
tids[i] = xpthread_create (NULL, run_loop, NULL);
/* Run for some amount of time. Empirically speaking exercising
the stall via pthread_rwlock_tryrdlock is much harder, and on
a 3.5GHz 4 core x86_64 VM system it takes somewhere around
20-200s to stall, approaching 100% stall past 200s. We can't
wait that long for a regression test so we just test for 20s,
and expect the stall to happen with a 5-10% chance (enough for
developers to see). */
sleep (20);
/* Then exit. */
printf ("INFO: Exiting...\n");
do_exit = 1;
/* If any readers stalled then we will timeout waiting for them. */
for (i = 0; i < NTHREADS; i++)
xpthread_join (tids[i]);
printf ("INFO: Done.\n");
xpthread_rwlock_destroy (&onelock);
printf ("PASS: No pthread_rwlock_tryrdlock stalls detected.\n");
return 0;
}
#define TIMEOUT 30
#include <support/test-driver.c>
+108
View File
@@ -0,0 +1,108 @@
/* Bug 23844: Test for pthread_rwlock_trywrlock stalls.
Copyright (C) 2019 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/>. */
/* For a full analysis see comments in tst-rwlock-tryrdlock-stall.c.
Summary for the pthread_rwlock_trywrlock() stall:
The stall is caused by pthread_rwlock_trywrlock setting
__wrphase_futex futex to 1 and loosing the
PTHREAD_RWLOCK_FUTEX_USED bit.
The fix for bug 23844 ensures that waiters on __wrphase_futex are
correctly woken. Before the fix the test stalls as readers can
wait forever on __wrphase_futex. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <support/xthread.h>
#include <errno.h>
/* We need only one lock to reproduce the issue. We will need multiple
threads to get the exact case where we have a read, try, and unlock
all interleaving to produce the case where the readers are waiting
and the try clears the PTHREAD_RWLOCK_FUTEX_USED bit and a
subsequent unlock fails to wake them. */
pthread_rwlock_t onelock;
/* The number of threads is arbitrary but empirically chosen to have
enough threads that we see the condition where waiting readers are
not woken by a successful unlock. */
#define NTHREADS 32
_Atomic int do_exit;
void *
run_loop (void *arg)
{
int i = 0, ret;
while (!do_exit)
{
/* Arbitrarily choose if we are the writer or reader. Choose a
high enough ratio of readers to writers to make it likely
that readers block (and eventually are susceptable to
stalling).
If we are a writer, take the write lock, and then unlock.
If we are a reader, try the lock, then lock, then unlock. */
if ((i % 8) != 0)
{
if ((ret = pthread_rwlock_trywrlock (&onelock)) != 0)
{
if (ret == EBUSY)
xpthread_rwlock_wrlock (&onelock);
else
exit (EXIT_FAILURE);
}
}
else
xpthread_rwlock_rdlock (&onelock);
/* Thread does some work and then unlocks. */
xpthread_rwlock_unlock (&onelock);
i++;
}
return NULL;
}
int
do_test (void)
{
int i;
pthread_t tids[NTHREADS];
xpthread_rwlock_init (&onelock, NULL);
for (i = 0; i < NTHREADS; i++)
tids[i] = xpthread_create (NULL, run_loop, NULL);
/* Run for some amount of time. The pthread_rwlock_tryrwlock stall
is very easy to trigger and happens in seconds under the test
conditions. */
sleep (10);
/* Then exit. */
printf ("INFO: Exiting...\n");
do_exit = 1;
/* If any readers stalled then we will timeout waiting for them. */
for (i = 0; i < NTHREADS; i++)
xpthread_join (tids[i]);
printf ("INFO: Done.\n");
xpthread_rwlock_destroy (&onelock);
printf ("PASS: No pthread_rwlock_tryrwlock stalls detected.\n");
return 0;
}
#include <support/test-driver.c>
+49 -41
View File
@@ -19,12 +19,16 @@
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <support/support.h>
#include <support/check.h>
#include <support/xthread.h>
struct test_s
{
int a;
int b;
__attribute__ ((aligned(0x20))) int a;
__attribute__ ((aligned(0x200))) int b;
};
#define INIT_A 1
@@ -36,15 +40,34 @@ __thread struct test_s s __attribute__ ((tls_model ("initial-exec"))) =
.b = INIT_B
};
/* Use noinline in combination with not static to ensure that the
alignment check is really done. Otherwise it was optimized out! */
__attribute__ ((noinline)) void
check_alignment (const char *thr_name, const char *ptr_name,
int *ptr, int alignment)
{
uintptr_t offset_aligment = ((uintptr_t) ptr) & (alignment - 1);
if (offset_aligment)
{
FAIL_EXIT1 ("%s (%p) is not 0x%x-byte aligned in %s thread\n",
ptr_name, ptr, alignment, thr_name);
}
}
static void
check_s (const char *thr_name)
{
if (s.a != INIT_A || s.b != INIT_B)
FAIL_EXIT1 ("initial value of s in %s thread wrong\n", thr_name);
check_alignment (thr_name, "s.a", &s.a, 0x20);
check_alignment (thr_name, "s.b", &s.b, 0x200);
}
static void *
tf (void *arg)
{
if (s.a != INIT_A || s.b != INIT_B)
{
puts ("initial value of s in child thread wrong");
exit (1);
}
check_s ("child");
++s.a;
@@ -55,25 +78,14 @@ tf (void *arg)
int
do_test (void)
{
if (s.a != INIT_A || s.b != INIT_B)
{
puts ("initial value of s in main thread wrong");
exit (1);
}
check_s ("main");
pthread_attr_t a;
if (pthread_attr_init (&a) != 0)
{
puts ("attr_init failed");
exit (1);
}
xpthread_attr_init (&a);
if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
{
puts ("attr_setstacksize failed");
return 1;
}
#define STACK_SIZE (1 * 1024 * 1024)
xpthread_attr_setstacksize (&a, STACK_SIZE);
#define N 10
int i;
@@ -83,29 +95,25 @@ do_test (void)
pthread_t th[M];
int j;
for (j = 0; j < M; ++j, ++s.a)
if (pthread_create (&th[j], &a, tf, NULL) != 0)
{
puts ("pthread_create failed");
exit (1);
}
th[j] = xpthread_create (&a, tf, NULL);
for (j = 0; j < M; ++j)
if (pthread_join (th[j], NULL) != 0)
{
puts ("pthread_join failed");
exit (1);
}
xpthread_join (th[j]);
}
if (pthread_attr_destroy (&a) != 0)
{
puts ("attr_destroy failed");
exit (1);
}
/* Also check the alignment of the tls variables if a misaligned stack is
specified. */
pthread_t th;
void *thr_stack = NULL;
thr_stack = xposix_memalign (0x200, STACK_SIZE + 1);
xpthread_attr_setstack (&a, thr_stack + 1, STACK_SIZE);
th = xpthread_create (&a, tf, NULL);
xpthread_join (th);
free (thr_stack);
xpthread_attr_destroy (&a);
return 0;
}
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
#include <support/test-driver.c>
+2 -2
View File
@@ -248,7 +248,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
: NULL);
ndomain = (ndomain ? newbuf + ndomaindiff
: NULL);
buffer = newbuf;
*tofreep = buffer = newbuf;
}
nhost = memcpy (buffer + bufused,
@@ -319,7 +319,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
{
buflen *= 2;
buffer = xrealloc (buffer, buflen);
*tofreep = buffer = xrealloc (buffer, buflen);
}
else if (status == NSS_STATUS_RETURN
|| status == NSS_STATUS_NOTFOUND
+3 -1
View File
@@ -60,7 +60,9 @@ tests = test-netdb test-digits-dots tst-nss-getpwent bug17079 \
xtests = bug-erange
tests-container = \
tst-nss-test3
tst-nss-test3 \
tst-nss-db-endpwent \
tst-nss-db-endgrent
# Tests which need libdl
ifeq (yes,$(build-shared))
+12 -3
View File
@@ -142,7 +142,7 @@ _nss_compat_setgrent (int stayopen)
}
static enum nss_status
static enum nss_status __attribute_warn_unused_result__
internal_endgrent (ent_t *ent)
{
if (ent->stream != NULL)
@@ -163,6 +163,15 @@ internal_endgrent (ent_t *ent)
return NSS_STATUS_SUCCESS;
}
/* Like internal_endgrent, but preserve errno in all cases. */
static void
internal_endgrent_noerror (ent_t *ent)
{
int saved_errno = errno;
enum nss_status unused __attribute__ ((unused)) = internal_endgrent (ent);
__set_errno (saved_errno);
}
enum nss_status
_nss_compat_endgrent (void)
{
@@ -483,7 +492,7 @@ _nss_compat_getgrnam_r (const char *name, struct group *grp,
if (result == NSS_STATUS_SUCCESS)
result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop);
internal_endgrent (&ent);
internal_endgrent_noerror (&ent);
return result;
}
@@ -612,7 +621,7 @@ _nss_compat_getgrgid_r (gid_t gid, struct group *grp,
if (result == NSS_STATUS_SUCCESS)
result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop);
internal_endgrent (&ent);
internal_endgrent_noerror (&ent);
return result;
}
+11 -2
View File
@@ -133,7 +133,7 @@ internal_setgrent (ent_t *ent)
}
static enum nss_status
static enum nss_status __attribute_warn_unused_result__
internal_endgrent (ent_t *ent)
{
if (ent->stream != NULL)
@@ -157,6 +157,15 @@ internal_endgrent (ent_t *ent)
return NSS_STATUS_SUCCESS;
}
/* Like internal_endgrent, but preserve errno in all cases. */
static void
internal_endgrent_noerror (ent_t *ent)
{
int saved_errno = errno;
enum nss_status unused __attribute__ ((unused)) = internal_endgrent (ent);
__set_errno (saved_errno);
}
/* Add new group record. */
static void
add_group (long int *start, long int *size, gid_t **groupsp, long int limit,
@@ -501,7 +510,7 @@ _nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start,
done:
scratch_buffer_free (&tmpbuf);
internal_endgrent (&intern);
internal_endgrent_noerror (&intern);
return status;
}
+12 -3
View File
@@ -259,7 +259,7 @@ _nss_compat_setpwent (int stayopen)
}
static enum nss_status
static enum nss_status __attribute_warn_unused_result__
internal_endpwent (ent_t *ent)
{
if (ent->stream != NULL)
@@ -287,6 +287,15 @@ internal_endpwent (ent_t *ent)
return NSS_STATUS_SUCCESS;
}
/* Like internal_endpwent, but preserve errno in all cases. */
static void
internal_endpwent_noerror (ent_t *ent)
{
int saved_errno = errno;
enum nss_status unused __attribute__ ((unused)) = internal_endpwent (ent);
__set_errno (saved_errno);
}
enum nss_status
_nss_compat_endpwent (void)
{
@@ -822,7 +831,7 @@ _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
if (result == NSS_STATUS_SUCCESS)
result = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop);
internal_endpwent (&ent);
internal_endpwent_noerror (&ent);
return result;
}
@@ -1061,7 +1070,7 @@ _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
if (result == NSS_STATUS_SUCCESS)
result = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop);
internal_endpwent (&ent);
internal_endpwent_noerror (&ent);
return result;
}
+11 -3
View File
@@ -215,7 +215,7 @@ _nss_compat_setspent (int stayopen)
}
static enum nss_status
static enum nss_status __attribute_warn_unused_result__
internal_endspent (ent_t *ent)
{
if (ent->stream != NULL)
@@ -244,6 +244,15 @@ internal_endspent (ent_t *ent)
return NSS_STATUS_SUCCESS;
}
/* Like internal_endspent, but preserve errno in all cases. */
static void
internal_endspent_noerror (ent_t *ent)
{
int saved_errno = errno;
enum nss_status unused __attribute__ ((unused)) = internal_endspent (ent);
__set_errno (saved_errno);
}
enum nss_status
_nss_compat_endspent (void)
{
@@ -261,7 +270,6 @@ _nss_compat_endspent (void)
return result;
}
static enum nss_status
getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent,
char *group, char *buffer, size_t buflen,
@@ -786,7 +794,7 @@ _nss_compat_getspnam_r (const char *name, struct spwd *pwd,
if (result == NSS_STATUS_SUCCESS)
result = internal_getspnam_r (name, pwd, &ent, buffer, buflen, errnop);
internal_endspent (&ent);
internal_endspent_noerror (&ent);
return result;
}
+5 -1
View File
@@ -63,5 +63,9 @@ internal_setent (const char *file, struct nss_db_map *mapping)
void
internal_endent (struct nss_db_map *mapping)
{
munmap (mapping->header, mapping->len);
if (mapping->header != NULL)
{
munmap (mapping->header, mapping->len);
mapping->header = NULL;
}
}
+54
View File
@@ -0,0 +1,54 @@
/* Test for endgrent changing errno for BZ #24696
Copyright (C) 2019 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 <stdlib.h>
#include <sys/types.h>
#include <grp.h>
#include <unistd.h>
#include <errno.h>
#include <support/check.h>
#include <support/support.h>
/* The following test verifies that if the db NSS Service is initialized
with no database (getgrent), that a subsequent closure (endgrent) does
not set errno. In the case of the db service it is not an error to close
the service and so it should not set errno. */
static int
do_test (void)
{
/* Just make sure it's not there, although usually it won't be. */
unlink ("/var/db/group.db");
/* This, in conjunction with the testroot's nsswitch.conf, causes
the nss_db module to be "connected" and initialized - but the
testroot has no group.db, so no mapping will be created. */
getgrent ();
errno = 0;
/* Before the fix, this would call munmap (NULL) and set errno. */
endgrent ();
if (errno != 0)
FAIL_EXIT1 ("endgrent set errno to %d\n", errno);
return 0;
}
#include <support/test-driver.c>
@@ -0,0 +1 @@
group : db files
+66
View File
@@ -0,0 +1,66 @@
/* Test for endpwent->getpwent crash for BZ #24695
Copyright (C) 2019 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 <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <pwd.h>
#include <support/support.h>
#include <support/check.h>
/* It is entirely allowed to start with a getpwent call without
resetting the state of the service via a call to setpwent.
You can also call getpwent more times than you have entries in
the service, and it should not fail. This test iteratates the
database once, gets to the end, and then attempts a second
iteration to look for crashes. */
static void
try_it (void)
{
struct passwd *pw;
/* setpwent is intentionally omitted here. The first call to
getpwent detects that it's first and initializes. The second
time try_it is called, this "first call" was not detected before
the fix, and getpwent would crash. */
while ((pw = getpwent ()) != NULL)
;
/* We only care if this segfaults or not. */
endpwent ();
}
static int
do_test (void)
{
char *cmd;
cmd = xasprintf ("%s/makedb -o /var/db/passwd.db /var/db/passwd.in",
support_bindir_prefix);
system (cmd);
free (cmd);
try_it ();
try_it ();
return 0;
}
#include <support/test-driver.c>
@@ -0,0 +1 @@
passwd: db
@@ -0,0 +1,4 @@
.root root:x:0:0:root:/root:/bin/bash
=0 root:x:0:0:root:/root:/bin/bash
.bin bin:x:1:1:bin:/bin:/sbin/nologin
=1 bin:x:1:1:bin:/bin:/sbin/nologin
+5 -5
View File
@@ -87,7 +87,7 @@ __extension__ typedef unsigned long long int __uintmax_t;
32 -- "natural" 32-bit type (always int)
64 -- "natural" 64-bit type (long or long long)
LONG32 -- 32-bit type, traditionally long
QUAD -- 64-bit type, always long long
QUAD -- 64-bit type, traditionally long long
WORD -- natural type of __WORDSIZE bits (int or long)
LONGWORD -- type of __WORDSIZE bits, traditionally long
@@ -113,14 +113,14 @@ __extension__ typedef unsigned long long int __uintmax_t;
#define __SLONGWORD_TYPE long int
#define __ULONGWORD_TYPE unsigned long int
#if __WORDSIZE == 32
# define __SQUAD_TYPE __quad_t
# define __UQUAD_TYPE __u_quad_t
# define __SQUAD_TYPE __int64_t
# define __UQUAD_TYPE __uint64_t
# define __SWORD_TYPE int
# define __UWORD_TYPE unsigned int
# define __SLONG32_TYPE long int
# define __ULONG32_TYPE unsigned long int
# define __S64_TYPE __quad_t
# define __U64_TYPE __u_quad_t
# define __S64_TYPE __int64_t
# define __U64_TYPE __uint64_t
/* We want __extension__ before typedef's that use nonstandard base types
such as `long long' in C89 mode. */
# define __STD_TYPE __extension__ typedef
+13 -12
View File
@@ -827,31 +827,32 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
{
size_t home_len = strlen (p->pw_dir);
size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
char *d;
char *d, *newp;
bool use_alloca = glob_use_alloca (alloca_used,
home_len + rest_len + 1);
if (__glibc_unlikely (malloc_dirname))
free (dirname);
malloc_dirname = 0;
if (glob_use_alloca (alloca_used, home_len + rest_len + 1))
dirname = alloca_account (home_len + rest_len + 1,
alloca_used);
if (use_alloca)
newp = alloca_account (home_len + rest_len + 1, alloca_used);
else
{
dirname = malloc (home_len + rest_len + 1);
if (dirname == NULL)
newp = malloc (home_len + rest_len + 1);
if (newp == NULL)
{
scratch_buffer_free (&pwtmpbuf);
retval = GLOB_NOSPACE;
goto out;
}
malloc_dirname = 1;
}
d = mempcpy (dirname, p->pw_dir, home_len);
d = mempcpy (newp, p->pw_dir, home_len);
if (end_name != NULL)
d = mempcpy (d, end_name, rest_len);
*d = '\0';
if (__glibc_unlikely (malloc_dirname))
free (dirname);
dirname = newp;
malloc_dirname = !use_alloca;
dirlen = home_len + rest_len;
dirname_modified = 1;
}
+4 -2
View File
@@ -1293,8 +1293,10 @@ proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs,
else if (naccepted)
{
char *buf = (char *) re_string_get_buffer (&mctx->input);
if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
naccepted) != 0)
if (mctx->input.valid_len - *pidx < naccepted
|| (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
naccepted)
!= 0))
return -1;
}
}
+8 -25
View File
@@ -154,37 +154,20 @@ typedef unsigned int uint;
#include <bits/stdint-intn.h>
#if !__GNUC_PREREQ (2, 7)
/* These were defined by ISO C without the first `_'. */
typedef unsigned char u_int8_t;
typedef unsigned short int u_int16_t;
typedef unsigned int u_int32_t;
# if __WORDSIZE == 64
typedef unsigned long int u_int64_t;
# else
__extension__ typedef unsigned long long int u_int64_t;
# endif
typedef int register_t;
#else
/* For GCC 2.7 and later, we can use specific type-size attributes. */
# define __u_intN_t(N, MODE) \
typedef unsigned int u_int##N##_t __attribute__ ((__mode__ (MODE)))
__u_intN_t (8, __QI__);
__u_intN_t (16, __HI__);
__u_intN_t (32, __SI__);
__u_intN_t (64, __DI__);
typedef __uint8_t u_int8_t;
typedef __uint16_t u_int16_t;
typedef __uint32_t u_int32_t;
typedef __uint64_t u_int64_t;
#if __GNUC_PREREQ (2, 7)
typedef int register_t __attribute__ ((__mode__ (__word__)));
#else
typedef int register_t;
#endif
/* Some code from BIND tests this macro to see if the types above are
defined. */
#endif
#define __BIT_TYPES_DEFINED__ 1
+5 -4
View File
@@ -1,4 +1,4 @@
/* BZ #18877 and #21270 mmap offset test.
/* BZ #18877, BZ #21270, and BZ #24699 mmap offset test.
Copyright (C) 2015-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -24,6 +24,7 @@
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <mmap_info.h>
#include <support/check.h>
@@ -76,7 +77,7 @@ do_test_bz18877 (void)
/* Check if invalid offset are handled correctly by mmap. */
static int
do_test_bz21270 (void)
do_test_large_offset (void)
{
/* For architectures with sizeof (off_t) < sizeof (off64_t) mmap is
implemented with __SYS_mmap2 syscall and the offset is represented in
@@ -90,7 +91,7 @@ do_test_bz21270 (void)
const size_t length = 4096;
void *addr = mmap64 (NULL, length, prot, flags, fd, offset);
if (sizeof (off_t) < sizeof (off64_t))
if (mmap64_maximum_offset (page_shift) < UINT64_MAX)
{
if ((addr != MAP_FAILED) && (errno != EINVAL))
FAIL_RET ("mmap succeed");
@@ -110,7 +111,7 @@ do_test (void)
int ret = 0;
ret += do_test_bz18877 ();
ret += do_test_bz21270 ();
ret += do_test_large_offset ();
return ret;
}
+5 -32
View File
@@ -16,11 +16,9 @@
# License along with the GNU C Library; if not, see
# <http://www.gnu.org/licenses/>.
# Check installed headers for cleanliness. For each header, confirm
# that it's possible to compile a file that includes that header and
# does nothing else, in several different compilation modes. Also,
# scan the header for a set of obsolete typedefs that should no longer
# appear.
# For each installed header, confirm that it's possible to compile a
# file that includes that header and does nothing else, in several
# different compilation modes.
# These compilation switches assume GCC or compatible, which is probably
# fine since we also assume that when _building_ glibc.
@@ -31,13 +29,6 @@ cxx_modes="-std=c++98 -std=gnu++98 -std=c++11 -std=gnu++11"
# These are probably the most commonly used three.
lib_modes="-D_DEFAULT_SOURCE=1 -D_GNU_SOURCE=1 -D_XOPEN_SOURCE=700"
# sys/types.h+bits/types.h have to define the obsolete types.
# rpc(svc)/* have the obsolete types too deeply embedded in their API
# to remove.
skip_obsolete_type_check='*/sys/types.h|*/bits/types.h|*/rpc/*|*/rpcsvc/*'
obsolete_type_re=\
'\<((__)?(quad_t|u(short|int|long|_(char|short|int([0-9]+_t)?|long|quad_t))))\>'
if [ $# -lt 3 ]; then
echo "usage: $0 c|c++ \"compile command\" header header header..." >&2
exit 2
@@ -46,14 +37,10 @@ case "$1" in
(c)
lang_modes="$c_modes"
cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.c)
already="$skip_obsolete_type_check"
;;
(c++)
lang_modes="$cxx_modes"
cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.cc)
# The obsolete-type check can be skipped for C++; it is
# sufficient to do it for C.
already="*"
;;
(*)
echo "usage: $0 c|c++ \"compile command\" header header header..." >&2
@@ -151,22 +138,8 @@ $expanded_lib_mode
int avoid_empty_translation_unit;
EOF
if $cc_cmd -fsyntax-only $lang_mode "$cih_test_c" 2>&1
then
includes=$($cc_cmd -fsyntax-only -H $lang_mode \
"$cih_test_c" 2>&1 | sed -ne 's/^[.][.]* //p')
for h in $includes; do
# Don't repeat work.
eval 'case "$h" in ('"$already"') continue;; esac'
if grep -qE "$obsolete_type_re" "$h"; then
echo "*** Obsolete types detected:"
grep -HE "$obsolete_type_re" "$h"
failed=1
fi
already="$already|$h"
done
else
failed=1
then :
else failed=1
fi
done
done
+466
View File
@@ -0,0 +1,466 @@
#! /usr/bin/python3
# Copyright (C) 2019 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/>.
"""Verifies that installed headers do not use any obsolete constructs:
* legacy BSD typedefs superseded by <stdint.h>:
ushort uint ulong u_char u_short u_int u_long u_intNN_t quad_t u_quad_t
(sys/types.h is allowed to _define_ these types, but not to use them
to define anything else).
"""
import argparse
import collections
import re
import sys
# Simplified lexical analyzer for C preprocessing tokens.
# Does not implement trigraphs.
# Does not implement backslash-newline in the middle of any lexical
# item other than a string literal.
# Does not implement universal-character-names in identifiers.
# Treats prefixed strings (e.g. L"...") as two tokens (L and "...")
# Accepts non-ASCII characters only within comments and strings.
# Caution: The order of the outermost alternation matters.
# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST,
# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must
# be last.
# Caution: There should be no capturing groups other than the named
# captures in the outermost alternation.
# For reference, these are all of the C punctuators as of C11:
# [ ] ( ) { } , ; ? ~
# ! != * *= / /= ^ ^= = ==
# # ##
# % %= %> %: %:%:
# & &= &&
# | |= ||
# + += ++
# - -= -- ->
# . ...
# : :>
# < <% <: << <<= <=
# > >= >> >>=
# The BAD_* tokens are not part of the official definition of pp-tokens;
# they match unclosed strings, character constants, and block comments,
# so that the regex engine doesn't have to backtrack all the way to the
# beginning of a broken construct and then emit dozens of junk tokens.
PP_TOKEN_RE_ = re.compile(r"""
(?P<STRING> \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\")
|(?P<BAD_STRING> \"(?:[^\"\\\r\n]|\\[ -~])*)
|(?P<CHARCONST> \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\')
|(?P<BAD_CHARCONST> \'(?:[^\'\\\r\n]|\\[ -~])*)
|(?P<BLOCK_COMMENT> /\*(?:\*(?!/)|[^*])*\*/)
|(?P<BAD_BLOCK_COM> /\*(?:\*(?!/)|[^*])*\*?)
|(?P<LINE_COMMENT> //[^\r\n]*)
|(?P<IDENT> [_a-zA-Z][_a-zA-Z0-9]*)
|(?P<PP_NUMBER> \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*)
|(?P<PUNCTUATOR>
[,;?~(){}\[\]]
| [!*/^=]=?
| \#\#?
| %(?:[=>]|:(?:%:)?)?
| &[=&]?
|\|[=|]?
|\+[=+]?
| -[=->]?
|\.(?:\.\.)?
| :>?
| <(?:[%:]|<(?:=|<=?)?)?
| >(?:=|>=?)?)
|(?P<ESCNL> \\(?:\r|\n|\r\n))
|(?P<WHITESPACE> [ \t\n\r\v\f]+)
|(?P<OTHER> .)
""", re.DOTALL | re.VERBOSE)
HEADER_NAME_RE_ = re.compile(r"""
< [^>\r\n]+ >
| " [^"\r\n]+ "
""", re.DOTALL | re.VERBOSE)
ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""")
# based on the sample code in the Python re documentation
Token_ = collections.namedtuple("Token", (
"kind", "text", "line", "column", "context"))
Token_.__doc__ = """
One C preprocessing token, comment, or chunk of whitespace.
'kind' identifies the token type, which will be one of:
STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT,
PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME,
or OTHER. The BAD_* alternatives in PP_TOKEN_RE_ are
handled within tokenize_c, below.
'text' is the sequence of source characters making up the token;
no decoding whatsoever is performed.
'line' and 'column' give the position of the first character of the
token within the source file. They are both 1-based.
'context' indicates whether or not this token occurred within a
preprocessing directive; it will be None for running text,
'<null>' for the leading '#' of a directive line (because '#'
all by itself on a line is a "null directive"), or the name of
the directive for tokens within a directive line, starting with
the IDENT for the name itself.
"""
def tokenize_c(file_contents, reporter):
"""Yield a series of Token objects, one for each preprocessing
token, comment, or chunk of whitespace within FILE_CONTENTS.
The REPORTER object is expected to have one method,
reporter.error(token, message), which will be called to
indicate a lexical error at the position of TOKEN.
If MESSAGE contains the four-character sequence '{!r}', that
is expected to be replaced by repr(token.text).
"""
Token = Token_
PP_TOKEN_RE = PP_TOKEN_RE_
ENDLINE_RE = ENDLINE_RE_
HEADER_NAME_RE = HEADER_NAME_RE_
line_num = 1
line_start = 0
pos = 0
limit = len(file_contents)
directive = None
at_bol = True
while pos < limit:
if directive == "include":
mo = HEADER_NAME_RE.match(file_contents, pos)
if mo:
kind = "HEADER_NAME"
directive = "after_include"
else:
mo = PP_TOKEN_RE.match(file_contents, pos)
kind = mo.lastgroup
if kind != "WHITESPACE":
directive = "after_include"
else:
mo = PP_TOKEN_RE.match(file_contents, pos)
kind = mo.lastgroup
text = mo.group()
line = line_num
column = mo.start() - line_start
adj_line_start = 0
# only these kinds can contain a newline
if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT",
"STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"):
for tmo in ENDLINE_RE.finditer(text):
line_num += 1
adj_line_start = tmo.end()
if adj_line_start:
line_start = mo.start() + adj_line_start
# Track whether or not we are scanning a preprocessing directive.
if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start):
at_bol = True
directive = None
else:
if kind == "PUNCTUATOR" and text == "#" and at_bol:
directive = "<null>"
elif kind == "IDENT" and directive == "<null>":
directive = text
at_bol = False
# Report ill-formed tokens and rewrite them as their well-formed
# equivalents, so downstream processing doesn't have to know about them.
# (Rewriting instead of discarding provides better error recovery.)
if kind == "BAD_BLOCK_COM":
reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""),
"unclosed block comment")
text += "*/"
kind = "BLOCK_COMMENT"
elif kind == "BAD_STRING":
reporter.error(Token("BAD_STRING", "", line, column+1, ""),
"unclosed string")
text += "\""
kind = "STRING"
elif kind == "BAD_CHARCONST":
reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""),
"unclosed char constant")
text += "'"
kind = "CHARCONST"
tok = Token(kind, text, line, column+1,
"include" if directive == "after_include" else directive)
# Do not complain about OTHER tokens inside macro definitions.
# $ and @ appear in macros defined by headers intended to be
# included from assembly language, e.g. sysdeps/mips/sys/asm.h.
if kind == "OTHER" and directive != "define":
self.error(tok, "stray {!r} in program")
yield tok
pos = mo.end()
#
# Base and generic classes for individual checks.
#
class ConstructChecker:
"""Scan a stream of C preprocessing tokens and possibly report
problems with them. The REPORTER object passed to __init__ has
one method, reporter.error(token, message), which should be
called to indicate a problem detected at the position of TOKEN.
If MESSAGE contains the four-character sequence '{!r}' then that
will be replaced with a textual representation of TOKEN.
"""
def __init__(self, reporter):
self.reporter = reporter
def examine(self, tok):
"""Called once for each token in a header file.
Call self.reporter.error if a problem is detected.
"""
raise NotImplementedError
def eof(self):
"""Called once at the end of the stream. Subclasses need only
override this if it might have something to do."""
pass
class NoCheck(ConstructChecker):
"""Generic checker class which doesn't do anything. Substitute this
class for a real checker when a particular check should be skipped
for some file."""
def examine(self, tok):
pass
#
# Check for obsolete type names.
#
# The obsolete type names we're looking for:
OBSOLETE_TYPE_RE_ = re.compile(r"""\A
(__)?
( quad_t
| u(?: short | int | long
| _(?: char | short | int(?:[0-9]+_t)? | long | quad_t )))
\Z""", re.VERBOSE)
class ObsoleteNotAllowed(ConstructChecker):
"""Don't allow any use of the obsolete typedefs."""
def examine(self, tok):
if OBSOLETE_TYPE_RE_.match(tok.text):
self.reporter.error(tok, "use of {!r}")
class ObsoletePrivateDefinitionsAllowed(ConstructChecker):
"""Allow definitions of the private versions of the
obsolete typedefs; that is, 'typedef [anything] __obsolete;'
"""
def __init__(self, reporter):
super().__init__(reporter)
self.in_typedef = False
self.prev_token = None
def examine(self, tok):
# bits/types.h hides 'typedef' in a macro sometimes.
if (tok.kind == "IDENT"
and tok.text in ("typedef", "__STD_TYPE")
and tok.context is None):
self.in_typedef = True
elif tok.kind == "PUNCTUATOR" and tok.text == ";" and self.in_typedef:
self.in_typedef = False
if self.prev_token.kind == "IDENT":
m = OBSOLETE_TYPE_RE_.match(self.prev_token.text)
if m and m.group(1) != "__":
self.reporter.error(self.prev_token, "use of {!r}")
self.prev_token = None
else:
self._check_prev()
self.prev_token = tok
def eof(self):
self._check_prev()
def _check_prev(self):
if (self.prev_token is not None
and self.prev_token.kind == "IDENT"
and OBSOLETE_TYPE_RE_.match(self.prev_token.text)):
self.reporter.error(self.prev_token, "use of {!r}")
class ObsoletePublicDefinitionsAllowed(ConstructChecker):
"""Allow definitions of the public versions of the obsolete
typedefs. Only specific forms of definition are allowed:
typedef __obsolete obsolete; // identifiers must agree
typedef __uintN_t u_intN_t; // N must agree
typedef unsigned long int ulong;
typedef unsigned short int ushort;
typedef unsigned int uint;
"""
def __init__(self, reporter):
super().__init__(reporter)
self.typedef_tokens = []
def examine(self, tok):
if tok.kind in ("WHITESPACE", "BLOCK_COMMENT",
"LINE_COMMENT", "NL", "ESCNL"):
pass
elif (tok.kind == "IDENT" and tok.text == "typedef"
and tok.context is None):
if self.typedef_tokens:
self.reporter.error(tok, "typedef inside typedef")
self._reset()
self.typedef_tokens.append(tok)
elif tok.kind == "PUNCTUATOR" and tok.text == ";":
self._finish()
elif self.typedef_tokens:
self.typedef_tokens.append(tok)
def eof(self):
self._reset()
def _reset(self):
while self.typedef_tokens:
tok = self.typedef_tokens.pop(0)
if tok.kind == "IDENT" and OBSOLETE_TYPE_RE_.match(tok.text):
self.reporter.error(tok, "use of {!r}")
def _finish(self):
if not self.typedef_tokens: return
if self.typedef_tokens[-1].kind == "IDENT":
m = OBSOLETE_TYPE_RE_.match(self.typedef_tokens[-1].text)
if m:
if self._permissible_public_definition(m):
self.typedef_tokens.clear()
self._reset()
def _permissible_public_definition(self, m):
if m.group(1) == "__": return False
name = m.group(2)
toks = self.typedef_tokens
ntok = len(toks)
if ntok == 3 and toks[1].kind == "IDENT":
defn = toks[1].text
n = OBSOLETE_TYPE_RE_.match(defn)
if n and n.group(1) == "__" and n.group(2) == name:
return True
if (name[:5] == "u_int" and name[-2:] == "_t"
and defn[:6] == "__uint" and defn[-2:] == "_t"
and name[5:-2] == defn[6:-2]):
return True
return False
if (name == "ulong" and ntok == 5
and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
and toks[2].kind == "IDENT" and toks[2].text == "long"
and toks[3].kind == "IDENT" and toks[3].text == "int"):
return True
if (name == "ushort" and ntok == 5
and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
and toks[2].kind == "IDENT" and toks[2].text == "short"
and toks[3].kind == "IDENT" and toks[3].text == "int"):
return True
if (name == "uint" and ntok == 4
and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
and toks[2].kind == "IDENT" and toks[2].text == "int"):
return True
return False
def ObsoleteTypedefChecker(reporter, fname):
"""Factory: produce an instance of the appropriate
obsolete-typedef checker for FNAME."""
# The obsolete rpc/ and rpcsvc/ headers are allowed to use the
# obsolete types, because it would be more trouble than it's
# worth to remove them from headers that we intend to stop
# installing eventually anyway.
if (fname.startswith("rpc/")
or fname.startswith("rpcsvc/")
or "/rpc/" in fname
or "/rpcsvc/" in fname):
return NoCheck(reporter)
# bits/types.h is allowed to define the __-versions of the
# obsolete types.
if (fname == "bits/types.h"
or fname.endswith("/bits/types.h")):
return ObsoletePrivateDefinitionsAllowed(reporter)
# sys/types.h is allowed to use the __-versions of the
# obsolete types, but only to define the unprefixed versions.
if (fname == "sys/types.h"
or fname.endswith("/sys/types.h")):
return ObsoletePublicDefinitionsAllowed(reporter)
return ObsoleteNotAllowed(reporter)
#
# Master control
#
class HeaderChecker:
"""Perform all of the checks on each header. This is also the
"reporter" object expected by tokenize_c and ConstructChecker.
"""
def __init__(self):
self.fname = None
self.status = 0
def error(self, tok, message):
self.status = 1
if '{!r}' in message:
message = message.format(tok.text)
sys.stderr.write("{}:{}:{}: error: {}\n".format(
self.fname, tok.line, tok.column, message))
def check(self, fname):
self.fname = fname
try:
with open(fname, "rt") as fp:
contents = fp.read()
except OSError as e:
sys.stderr.write("{}: {}\n".format(fname, e.strerror))
self.status = 1
return
typedef_checker = ObsoleteTypedefChecker(self, self.fname)
for tok in tokenize_c(contents, self):
typedef_checker.examine(tok)
def main():
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("headers", metavar="header", nargs="+",
help="one or more headers to scan for obsolete constructs")
args = ap.parse_args()
checker = HeaderChecker()
for fname in args.headers:
# Headers whose installed name begins with "finclude/" contain
# Fortran, not C, and this program should completely ignore them.
if not (fname.startswith("finclude/") or "/finclude/" in fname):
checker.check(fname)
sys.exit(checker.status)
main()
+11 -2
View File
@@ -66,6 +66,10 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
tst-scanf-round \
tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \
scanf14a scanf16a \
tst-printf-bz25691 \
tst-vfprintf-width-prec-alloc \
tst-grouping2 \
# tests
test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
@@ -75,10 +79,12 @@ tests-special += $(objpfx)tst-unbputc.out $(objpfx)tst-printf.out \
$(objpfx)tst-printf-bz18872-mem.out \
$(objpfx)tst-setvbuf1-cmp.out \
$(objpfx)tst-vfprintf-width-prec-mem.out \
$(objpfx)tst-printfsz-islongdouble.out
$(objpfx)tst-printfsz-islongdouble.out \
$(objpfx)tst-printf-bz25691-mem.out
generated += tst-printf-bz18872.c tst-printf-bz18872.mtrace \
tst-printf-bz18872-mem.out \
tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out
tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out \
tst-printf-bz25691.mtrace tst-printf-bz25691-mem.out
endif
include ../Rules
@@ -91,6 +97,7 @@ $(objpfx)bug14.out: $(gen-locales)
$(objpfx)scanf13.out: $(gen-locales)
$(objpfx)test-vfprintf.out: $(gen-locales)
$(objpfx)tst-grouping.out: $(gen-locales)
$(objpfx)tst-grouping2.out: $(gen-locales)
$(objpfx)tst-sprintf.out: $(gen-locales)
$(objpfx)tst-sscanf.out: $(gen-locales)
$(objpfx)tst-swprintf.out: $(gen-locales)
@@ -100,6 +107,8 @@ endif
tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace
tst-vfprintf-width-prec-ENV = \
MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace
tst-printf-bz25691-ENV = \
MALLOC_TRACE=$(objpfx)tst-printf-bz25691.mtrace
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' > $@; \
+1 -1
View File
@@ -57,7 +57,7 @@ do_test (void)
ret = fprintf (fp, "%." SN3 "d", 1);
printf ("ret = %d\n", ret);
if (ret != -1 || errno != EOVERFLOW)
if (ret != N3)
return 1;
/* GCC 9 warns about output of more than INT_MAX characters; this is
+39
View File
@@ -0,0 +1,39 @@
/* Test printf with grouping and large width (bug 29530)
Copyright (C) 2022 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 <locale.h>
#include <stdio.h>
#include <support/check.h>
#include <support/support.h>
static int
do_test (void)
{
const int field_width = 1000;
char buf[field_width + 1];
xsetlocale (LC_NUMERIC, "de_DE.UTF-8");
/* This used to crash in group_number. */
TEST_COMPARE (sprintf (buf, "%'*d", field_width, 1000), field_width);
TEST_COMPARE_STRING (buf + field_width - 6, " 1.000");
return 0;
}
#include <support/test-driver.c>
+108
View File
@@ -0,0 +1,108 @@
/* Test for memory leak with large width (BZ#25691).
Copyright (C) 2020 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 <string.h>
#include <wchar.h>
#include <stdint.h>
#include <locale.h>
#include <mcheck.h>
#include <support/check.h>
#include <support/support.h>
static int
do_test (void)
{
mtrace ();
/* For 's' conversion specifier with 'l' modifier the array must be
converted to multibyte characters up to the precision specific
value. */
{
/* The input size value is to force a heap allocation on temporary
buffer (in the old implementation). */
const size_t winputsize = 64 * 1024 + 1;
wchar_t *winput = xmalloc (winputsize * sizeof (wchar_t));
wmemset (winput, L'a', winputsize - 1);
winput[winputsize - 1] = L'\0';
char result[9];
const char expected[] = "aaaaaaaa";
int ret;
ret = snprintf (result, sizeof (result), "%.65537ls", winput);
TEST_COMPARE (ret, winputsize - 1);
TEST_COMPARE_BLOB (result, sizeof (result), expected, sizeof (expected));
ret = snprintf (result, sizeof (result), "%ls", winput);
TEST_COMPARE (ret, winputsize - 1);
TEST_COMPARE_BLOB (result, sizeof (result), expected, sizeof (expected));
free (winput);
}
/* For 's' converstion specifier the array is interpreted as a multibyte
character sequence and converted to wide characters up to the precision
specific value. */
{
/* The input size value is to force a heap allocation on temporary
buffer (in the old implementation). */
const size_t mbssize = 32 * 1024;
char *mbs = xmalloc (mbssize);
memset (mbs, 'a', mbssize - 1);
mbs[mbssize - 1] = '\0';
const size_t expectedsize = 32 * 1024;
wchar_t *expected = xmalloc (expectedsize * sizeof (wchar_t));
wmemset (expected, L'a', expectedsize - 1);
expected[expectedsize-1] = L'\0';
const size_t resultsize = mbssize * sizeof (wchar_t);
wchar_t *result = xmalloc (resultsize);
int ret;
ret = swprintf (result, resultsize, L"%.65537s", mbs);
TEST_COMPARE (ret, mbssize - 1);
TEST_COMPARE_BLOB (result, (ret + 1) * sizeof (wchar_t),
expected, expectedsize * sizeof (wchar_t));
ret = swprintf (result, resultsize, L"%1$.65537s", mbs);
TEST_COMPARE (ret, mbssize - 1);
TEST_COMPARE_BLOB (result, (ret + 1) * sizeof (wchar_t),
expected, expectedsize * sizeof (wchar_t));
/* Same test, but with an invalid multibyte sequence. */
mbs[mbssize - 2] = 0xff;
ret = swprintf (result, resultsize, L"%.65537s", mbs);
TEST_COMPARE (ret, -1);
ret = swprintf (result, resultsize, L"%1$.65537s", mbs);
TEST_COMPARE (ret, -1);
free (mbs);
free (result);
free (expected);
}
return 0;
}
#include <support/test-driver.c>
@@ -0,0 +1,41 @@
/* Test large width or precision does not involve large allocation.
Copyright (C) 2020 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 <sys/resource.h>
#include <support/check.h>
char test_string[] = "test";
static int
do_test (void)
{
struct rlimit limit;
TEST_VERIFY_EXIT (getrlimit (RLIMIT_AS, &limit) == 0);
limit.rlim_cur = 200 * 1024 * 1024;
TEST_VERIFY_EXIT (setrlimit (RLIMIT_AS, &limit) == 0);
FILE *fp = fopen ("/dev/null", "w");
TEST_VERIFY_EXIT (fp != NULL);
TEST_COMPARE (fprintf (fp, "%1000000000d", 1), 1000000000);
TEST_COMPARE (fprintf (fp, "%.1000000000s", test_string), 4);
TEST_COMPARE (fprintf (fp, "%1000000000d %1000000000d", 1, 2), 2000000001);
TEST_COMPARE (fprintf (fp, "%2$.*1$s", 0x7fffffff, test_string), 4);
return 0;
}
#include <support/test-driver.c>
+183 -264
View File
@@ -31,6 +31,7 @@
#include <locale/localeinfo.h>
#include <stdio.h>
#include <scratch_buffer.h>
#include <intprops.h>
/* This code is shared between the standard stdio implementation found
in GNU C library and the libio implementation originally found in
@@ -45,10 +46,6 @@
#include <wctype.h>
#endif
/* In some cases we need extra space for all the output which is not
counted in the width of the string. We assume 32 characters is
enough. */
#define EXTSIZ 32
#define ARGCHECK(S, Format) \
do \
{ \
@@ -68,22 +65,38 @@
} while (0)
#define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
#define done_add(val) \
do { \
unsigned int _val = val; \
assert ((unsigned int) done < (unsigned int) INT_MAX); \
if (__glibc_unlikely (INT_MAX - done < _val)) \
{ \
done = -1; \
__set_errno (EOVERFLOW); \
goto all_done; \
} \
done += _val; \
} while (0)
/* Add LENGTH to DONE. Return the new value of DONE, or -1 on
overflow (and set errno accordingly). */
static inline int
done_add_func (size_t length, int done)
{
if (done < 0)
return done;
int ret;
if (INT_ADD_WRAPV (done, length, &ret))
{
__set_errno (EOVERFLOW);
return -1;
}
return ret;
}
#define done_add(val) \
do \
{ \
/* Ensure that VAL has a type similar to int. */ \
_Static_assert (sizeof (val) == sizeof (int), "value int size"); \
_Static_assert ((__typeof__ (val)) -1 < 0, "value signed"); \
done = done_add_func ((val), done); \
if (done < 0) \
goto all_done; \
} \
while (0)
#ifndef COMPILE_WPRINTF
# define vfprintf __vfprintf_internal
# define CHAR_T char
# define OTHER_CHAR_T wchar_t
# define UCHAR_T unsigned char
# define INT_T int
typedef const char *THOUSANDS_SEP_T;
@@ -92,25 +105,14 @@ typedef const char *THOUSANDS_SEP_T;
# define STR_LEN(Str) strlen (Str)
# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
# define PAD(Padchar) \
do { \
if (width > 0) \
{ \
ssize_t written = _IO_padn (s, (Padchar), width); \
if (__glibc_unlikely (written != width)) \
{ \
done = -1; \
goto all_done; \
} \
done_add (written); \
} \
} while (0)
# define PUTC(C, F) _IO_putc_unlocked (C, F)
# define ORIENT if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
return -1
# define CONVERT_FROM_OTHER_STRING __wcsrtombs
#else
# define vfprintf __vfwprintf_internal
# define CHAR_T wchar_t
# define OTHER_CHAR_T char
/* This is a hack!!! There should be a type uwchar_t. */
# define UCHAR_T unsigned int /* uwchar_t */
# define INT_T wint_t
@@ -122,21 +124,9 @@ typedef wchar_t THOUSANDS_SEP_T;
# include <_itowa.h>
# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
# define PAD(Padchar) \
do { \
if (width > 0) \
{ \
ssize_t written = _IO_wpadn (s, (Padchar), width); \
if (__glibc_unlikely (written != width)) \
{ \
done = -1; \
goto all_done; \
} \
done_add (written); \
} \
} while (0)
# define PUTC(C, F) _IO_putwc_unlocked (C, F)
# define ORIENT if (_IO_fwide (s, 1) != 1) return -1
# define CONVERT_FROM_OTHER_STRING __mbsrtowcs
# undef _itoa
# define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case)
@@ -145,6 +135,33 @@ typedef wchar_t THOUSANDS_SEP_T;
# define EOF WEOF
#endif
static inline int
pad_func (FILE *s, CHAR_T padchar, int width, int done)
{
if (width > 0)
{
ssize_t written;
#ifndef COMPILE_WPRINTF
written = _IO_padn (s, padchar, width);
#else
written = _IO_wpadn (s, padchar, width);
#endif
if (__glibc_unlikely (written != width))
return -1;
return done_add_func (width, done);
}
return done;
}
#define PAD(Padchar) \
do \
{ \
done = pad_func (s, (Padchar), width, done); \
if (done < 0) \
goto all_done; \
} \
while (0)
#include "_i18n_number.h"
/* Include the shared code for parsing the format string. */
@@ -164,24 +181,115 @@ typedef wchar_t THOUSANDS_SEP_T;
} \
while (0)
#define outstring(String, Len) \
do \
{ \
assert ((size_t) done <= (size_t) INT_MAX); \
if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len)) \
{ \
done = -1; \
goto all_done; \
} \
if (__glibc_unlikely (INT_MAX - done < (Len))) \
{ \
done = -1; \
__set_errno (EOVERFLOW); \
goto all_done; \
} \
done += (Len); \
} \
while (0)
static inline int
outstring_func (FILE *s, const UCHAR_T *string, size_t length, int done)
{
assert ((size_t) done <= (size_t) INT_MAX);
if ((size_t) PUT (s, string, length) != (size_t) (length))
return -1;
return done_add_func (length, done);
}
#define outstring(String, Len) \
do \
{ \
const void *string_ = (String); \
done = outstring_func (s, string_, (Len), done); \
if (done < 0) \
goto all_done; \
} \
while (0)
/* Write the string SRC to S. If PREC is non-negative, write at most
PREC bytes. If LEFT is true, perform left justification. */
static int
outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec,
int width, bool left, int done)
{
/* Use a small buffer to combine processing of multiple characters.
CONVERT_FROM_OTHER_STRING expects the buffer size in (wide)
characters, and buf_length counts that. */
enum { buf_length = 256 / sizeof (CHAR_T) };
CHAR_T buf[buf_length];
_Static_assert (sizeof (buf) > MB_LEN_MAX,
"buffer is large enough for a single multi-byte character");
/* Add the initial padding if needed. */
if (width > 0 && !left)
{
/* Make a first pass to find the output width, so that we can
add the required padding. */
mbstate_t mbstate = { 0 };
const OTHER_CHAR_T *src_copy = src;
size_t total_written;
if (prec < 0)
total_written = CONVERT_FROM_OTHER_STRING
(NULL, &src_copy, 0, &mbstate);
else
{
/* The source might not be null-terminated. Enforce the
limit manually, based on the output length. */
total_written = 0;
size_t limit = prec;
while (limit > 0 && src_copy != NULL)
{
size_t write_limit = buf_length;
if (write_limit > limit)
write_limit = limit;
size_t written = CONVERT_FROM_OTHER_STRING
(buf, &src_copy, write_limit, &mbstate);
if (written == (size_t) -1)
return -1;
if (written == 0)
break;
total_written += written;
limit -= written;
}
}
/* Output initial padding. */
if (total_written < width)
{
done = pad_func (s, L_(' '), width - total_written, done);
if (done < 0)
return done;
}
}
/* Convert the input string, piece by piece. */
size_t total_written = 0;
{
mbstate_t mbstate = { 0 };
/* If prec is negative, remaining is not decremented, otherwise,
it serves as the write limit. */
size_t remaining = -1;
if (prec >= 0)
remaining = prec;
while (remaining > 0 && src != NULL)
{
size_t write_limit = buf_length;
if (remaining < write_limit)
write_limit = remaining;
size_t written = CONVERT_FROM_OTHER_STRING
(buf, &src, write_limit, &mbstate);
if (written == (size_t) -1)
return -1;
if (written == 0)
break;
done = outstring_func (s, (const UCHAR_T *) buf, written, done);
if (done < 0)
return done;
total_written += written;
if (prec >= 0)
remaining -= written;
}
}
/* Add final padding. */
if (width > 0 && left && total_written < width)
return pad_func (s, L_(' '), width - total_written, done);
return done;
}
/* For handling long_double and longlong we use the same flag. If
`long' and `long long' are effectively the same type define it to
@@ -979,7 +1087,6 @@ static const uint8_t jump_table[] =
LABEL (form_string): \
{ \
size_t len; \
int string_malloced; \
\
/* The string argument could in fact be `char *' or `wchar_t *'. \
But this should not make a difference here. */ \
@@ -991,7 +1098,6 @@ static const uint8_t jump_table[] =
/* Entry point for printing other strings. */ \
LABEL (print_string): \
\
string_malloced = 0; \
if (string == NULL) \
{ \
/* Write "(null)" if there's space. */ \
@@ -1008,41 +1114,12 @@ static const uint8_t jump_table[] =
} \
else if (!is_long && spec != L_('S')) \
{ \
/* This is complicated. We have to transform the multibyte \
string into a wide character string. */ \
const char *mbs = (const char *) string; \
mbstate_t mbstate; \
\
len = prec != -1 ? __strnlen (mbs, (size_t) prec) : strlen (mbs); \
\
/* Allocate dynamically an array which definitely is long \
enough for the wide character version. Each byte in the \
multi-byte string can produce at most one wide character. */ \
if (__glibc_unlikely (len > SIZE_MAX / sizeof (wchar_t))) \
{ \
__set_errno (EOVERFLOW); \
done = -1; \
goto all_done; \
} \
else if (__libc_use_alloca (len * sizeof (wchar_t))) \
string = (CHAR_T *) alloca (len * sizeof (wchar_t)); \
else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t))) \
== NULL) \
{ \
done = -1; \
goto all_done; \
} \
else \
string_malloced = 1; \
\
memset (&mbstate, '\0', sizeof (mbstate_t)); \
len = __mbsrtowcs (string, &mbs, len, &mbstate); \
if (len == (size_t) -1) \
{ \
/* Illegal multibyte character. */ \
done = -1; \
goto all_done; \
} \
done = outstring_converted_wide_string \
(s, (const char *) string, prec, width, left, done); \
if (done < 0) \
goto all_done; \
/* The padding has already been written. */ \
break; \
} \
else \
{ \
@@ -1065,8 +1142,6 @@ static const uint8_t jump_table[] =
outstring (string, len); \
if (left) \
PAD (L' '); \
if (__glibc_unlikely (string_malloced)) \
free (string); \
} \
break;
#else
@@ -1115,7 +1190,6 @@ static const uint8_t jump_table[] =
LABEL (form_string): \
{ \
size_t len; \
int string_malloced; \
\
/* The string argument could in fact be `char *' or `wchar_t *'. \
But this should not make a difference here. */ \
@@ -1127,7 +1201,6 @@ static const uint8_t jump_table[] =
/* Entry point for printing other strings. */ \
LABEL (print_string): \
\
string_malloced = 0; \
if (string == NULL) \
{ \
/* Write "(null)" if there's space. */ \
@@ -1153,51 +1226,12 @@ static const uint8_t jump_table[] =
} \
else \
{ \
const wchar_t *s2 = (const wchar_t *) string; \
mbstate_t mbstate; \
\
memset (&mbstate, '\0', sizeof (mbstate_t)); \
\
if (prec >= 0) \
{ \
/* The string `s2' might not be NUL terminated. */ \
if (__libc_use_alloca (prec)) \
string = (char *) alloca (prec); \
else if ((string = (char *) malloc (prec)) == NULL) \
{ \
done = -1; \
goto all_done; \
} \
else \
string_malloced = 1; \
len = __wcsrtombs (string, &s2, prec, &mbstate); \
} \
else \
{ \
len = __wcsrtombs (NULL, &s2, 0, &mbstate); \
if (len != (size_t) -1) \
{ \
assert (__mbsinit (&mbstate)); \
s2 = (const wchar_t *) string; \
if (__libc_use_alloca (len + 1)) \
string = (char *) alloca (len + 1); \
else if ((string = (char *) malloc (len + 1)) == NULL) \
{ \
done = -1; \
goto all_done; \
} \
else \
string_malloced = 1; \
(void) __wcsrtombs (string, &s2, len + 1, &mbstate); \
} \
} \
\
if (len == (size_t) -1) \
{ \
/* Illegal wide-character string. */ \
done = -1; \
goto all_done; \
} \
done = outstring_converted_wide_string \
(s, (const wchar_t *) string, prec, width, left, done); \
if (done < 0) \
goto all_done; \
/* The padding has already been written. */ \
break; \
} \
\
if ((width -= len) < 0) \
@@ -1211,8 +1245,6 @@ static const uint8_t jump_table[] =
outstring (string, len); \
if (left) \
PAD (' '); \
if (__glibc_unlikely (string_malloced)) \
free (string); \
} \
break;
#endif
@@ -1264,7 +1296,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
/* Buffer intermediate results. */
CHAR_T work_buffer[WORK_BUFFER_SIZE];
CHAR_T *workstart = NULL;
CHAR_T *workend;
/* We have to save the original argument pointer. */
@@ -1373,7 +1404,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
UCHAR_T pad = L_(' ');/* Padding character. */
CHAR_T spec;
workstart = NULL;
workend = work_buffer + WORK_BUFFER_SIZE;
/* Get current character in format string. */
@@ -1465,31 +1495,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
pad = L_(' ');
left = 1;
}
if (__glibc_unlikely (width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
{
__set_errno (EOVERFLOW);
done = -1;
goto all_done;
}
if (width >= WORK_BUFFER_SIZE - EXTSIZ)
{
/* We have to use a special buffer. */
size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
if (__libc_use_alloca (needed))
workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
else
{
workstart = (CHAR_T *) malloc (needed);
if (workstart == NULL)
{
done = -1;
goto all_done;
}
workend = workstart + width + EXTSIZ;
}
}
}
JUMP (*f, step1_jumps);
@@ -1497,31 +1502,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
LABEL (width):
width = read_int (&f);
if (__glibc_unlikely (width == -1
|| width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
if (__glibc_unlikely (width == -1))
{
__set_errno (EOVERFLOW);
done = -1;
goto all_done;
}
if (width >= WORK_BUFFER_SIZE - EXTSIZ)
{
/* We have to use a special buffer. */
size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
if (__libc_use_alloca (needed))
workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
else
{
workstart = (CHAR_T *) malloc (needed);
if (workstart == NULL)
{
done = -1;
goto all_done;
}
workend = workstart + width + EXTSIZ;
}
}
if (*f == L_('$'))
/* Oh, oh. The argument comes from a positional parameter. */
goto do_positional;
@@ -1570,34 +1557,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
}
else
prec = 0;
if (prec > width && prec > WORK_BUFFER_SIZE - EXTSIZ)
{
/* Deallocate any previously allocated buffer because it is
too small. */
if (__glibc_unlikely (workstart != NULL))
free (workstart);
workstart = NULL;
if (__glibc_unlikely (prec >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
{
__set_errno (EOVERFLOW);
done = -1;
goto all_done;
}
size_t needed = ((size_t) prec + EXTSIZ) * sizeof (CHAR_T);
if (__libc_use_alloca (needed))
workend = (CHAR_T *) alloca (needed) + prec + EXTSIZ;
else
{
workstart = (CHAR_T *) malloc (needed);
if (workstart == NULL)
{
done = -1;
goto all_done;
}
workend = workstart + prec + EXTSIZ;
}
}
JUMP (*f, step2_jumps);
/* Process 'h' modifier. There might another 'h' following. */
@@ -1661,10 +1620,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
/* The format is correctly handled. */
++nspecs_done;
if (__glibc_unlikely (workstart != NULL))
free (workstart);
workstart = NULL;
/* Look for next format specifier. */
#ifdef COMPILE_WPRINTF
f = __find_specwc ((end_of_spec = ++f));
@@ -1682,18 +1637,11 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
/* Hand off processing for positional parameters. */
do_positional:
if (__glibc_unlikely (workstart != NULL))
{
free (workstart);
workstart = NULL;
}
done = printf_positional (s, format, readonly_format, ap, &ap_save,
done, nspecs_done, lead_str_end, work_buffer,
save_errno, grouping, thousands_sep, mode_flags);
all_done:
if (__glibc_unlikely (workstart != NULL))
free (workstart);
/* Unlock the stream. */
_IO_funlockfile (s);
_IO_cleanup_region_end (0);
@@ -1737,8 +1685,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
/* Just a counter. */
size_t cnt;
CHAR_T *workstart = NULL;
if (grouping == (const char *) -1)
{
#ifdef COMPILE_WPRINTF
@@ -1927,7 +1873,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
char pad = specs[nspecs_done].info.pad;
CHAR_T spec = specs[nspecs_done].info.spec;
workstart = NULL;
CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
/* Fill in last information. */
@@ -1961,27 +1906,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
prec = specs[nspecs_done].info.prec;
}
/* Maybe the buffer is too small. */
if (MAX (prec, width) + EXTSIZ > WORK_BUFFER_SIZE)
{
if (__libc_use_alloca ((MAX (prec, width) + EXTSIZ)
* sizeof (CHAR_T)))
workend = ((CHAR_T *) alloca ((MAX (prec, width) + EXTSIZ)
* sizeof (CHAR_T))
+ (MAX (prec, width) + EXTSIZ));
else
{
workstart = (CHAR_T *) malloc ((MAX (prec, width) + EXTSIZ)
* sizeof (CHAR_T));
if (workstart == NULL)
{
done = -1;
goto all_done;
}
workend = workstart + (MAX (prec, width) + EXTSIZ);
}
}
/* Process format specifiers. */
while (1)
{
@@ -2055,18 +1979,12 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
break;
}
if (__glibc_unlikely (workstart != NULL))
free (workstart);
workstart = NULL;
/* Write the following constant string. */
outstring (specs[nspecs_done].end_of_fmt,
specs[nspecs_done].next_fmt
- specs[nspecs_done].end_of_fmt);
}
all_done:
if (__glibc_unlikely (workstart != NULL))
free (workstart);
scratch_buffer_free (&argsbuf);
scratch_buffer_free (&specsbuf);
return done;
@@ -2189,7 +2107,8 @@ group_number (CHAR_T *front_ptr, CHAR_T *w, CHAR_T *rear_ptr,
copy_rest:
/* No further grouping to be done. Copy the rest of the
number. */
memmove (w, s, (front_ptr -s) * sizeof (CHAR_T));
w -= s - front_ptr;
memmove (w, front_ptr, (s - front_ptr) * sizeof (CHAR_T));
break;
}
else if (*grouping != '\0')
+1
View File
@@ -74,6 +74,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define HEADER_MAX 256
+18 -170
View File
@@ -30,156 +30,12 @@
#include <sys/wait.h>
#include <unistd.h>
#include <support/check.h>
#include <support/support.h>
#include <support/capture_subprocess.h>
#include <support/test-driver.h>
static char MAGIC_ARGUMENT[] = "run-actual-test";
#define MAGIC_STATUS 19
/* Return a GID which is not our current GID, but is present in the
supplementary group list. */
static gid_t
choose_gid (void)
{
const int count = 64;
gid_t groups[count];
int ret = getgroups (count, groups);
if (ret < 0)
{
printf ("getgroups: %m\n");
exit (1);
}
gid_t current = getgid ();
for (int i = 0; i < ret; ++i)
{
if (groups[i] != current)
return groups[i];
}
return 0;
}
/* Copies the executable into a restricted directory, so that we can
safely make it SGID with the TARGET group ID. Then runs the
executable. */
static int
run_executable_sgid (gid_t target)
{
char *dirname = xasprintf ("%s/secure-getenv.%jd",
test_dir, (intmax_t) getpid ());
char *execname = xasprintf ("%s/bin", dirname);
int infd = -1;
int outfd = -1;
int ret = -1;
if (mkdir (dirname, 0700) < 0)
{
printf ("mkdir: %m\n");
goto err;
}
infd = open ("/proc/self/exe", O_RDONLY);
if (infd < 0)
{
printf ("open (/proc/self/exe): %m\n");
goto err;
}
outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
if (outfd < 0)
{
printf ("open (%s): %m\n", execname);
goto err;
}
char buf[4096];
for (;;)
{
ssize_t rdcount = read (infd, buf, sizeof (buf));
if (rdcount < 0)
{
printf ("read: %m\n");
goto err;
}
if (rdcount == 0)
break;
char *p = buf;
char *end = buf + rdcount;
while (p != end)
{
ssize_t wrcount = write (outfd, buf, end - p);
if (wrcount == 0)
errno = ENOSPC;
if (wrcount <= 0)
{
printf ("write: %m\n");
goto err;
}
p += wrcount;
}
}
if (fchown (outfd, getuid (), target) < 0)
{
printf ("fchown (%s): %m\n", execname);
goto err;
}
if (fchmod (outfd, 02750) < 0)
{
printf ("fchmod (%s): %m\n", execname);
goto err;
}
if (close (outfd) < 0)
{
printf ("close (outfd): %m\n");
goto err;
}
if (close (infd) < 0)
{
printf ("close (infd): %m\n");
goto err;
}
int kid = fork ();
if (kid < 0)
{
printf ("fork: %m\n");
goto err;
}
if (kid == 0)
{
/* Child process. */
char *args[] = { execname, MAGIC_ARGUMENT, NULL };
execve (execname, args, environ);
printf ("execve (%s): %m\n", execname);
_exit (1);
}
int status;
if (waitpid (kid, &status, 0) < 0)
{
printf ("waitpid: %m\n");
goto err;
}
if (!WIFEXITED (status) || WEXITSTATUS (status) != MAGIC_STATUS)
{
printf ("Unexpected exit status %d from child process\n",
status);
goto err;
}
ret = 0;
err:
if (outfd >= 0)
close (outfd);
if (infd >= 0)
close (infd);
if (execname)
{
unlink (execname);
free (execname);
}
if (dirname)
{
rmdir (dirname);
free (dirname);
}
return ret;
}
static int
do_test (void)
@@ -201,15 +57,15 @@ do_test (void)
exit (1);
}
gid_t target = choose_gid ();
if (target == 0)
{
fprintf (stderr,
"Could not find a suitable GID for user %jd, skipping test\n",
(intmax_t) getuid ());
exit (0);
}
return run_executable_sgid (target);
int status = support_capture_subprogram_self_sgid (MAGIC_ARGUMENT);
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
return EXIT_UNSUPPORTED;
if (!WIFEXITED (status))
FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
return 0;
}
static void
@@ -218,23 +74,15 @@ alternative_main (int argc, char **argv)
if (argc == 2 && strcmp (argv[1], MAGIC_ARGUMENT) == 0)
{
if (getgid () == getegid ())
{
/* This can happen if the file system is mounted nosuid. */
fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
(intmax_t) getgid ());
exit (MAGIC_STATUS);
}
/* This can happen if the file system is mounted nosuid. */
FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
(intmax_t) getgid ());
if (getenv ("PATH") == NULL)
{
printf ("PATH variable not present\n");
exit (3);
}
FAIL_EXIT (3, "PATH variable not present\n");
if (secure_getenv ("PATH") != NULL)
{
printf ("PATH variable not filtered out\n");
exit (4);
}
exit (MAGIC_STATUS);
FAIL_EXIT (4, "PATH variable not filtered out\n");
exit (EXIT_SUCCESS);
}
}
+83 -40
View File
@@ -15,17 +15,13 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/* This particular implementation was written by Eric Blake, 2008. */
#ifndef _LIBC
# include <config.h>
#endif
/* Specification of memmem. */
#include <string.h>
#ifndef _LIBC
# define __builtin_expect(expr, val) (expr)
# define __memmem memmem
#endif
@@ -36,51 +32,98 @@
#undef memmem
/* Return the first occurrence of NEEDLE in HAYSTACK. Return HAYSTACK
if NEEDLE_LEN is 0, otherwise NULL if NEEDLE is not found in
HAYSTACK. */
/* Hash character pairs so a small shift table can be used. All bits of
p[0] are included, but not all bits from p[-1]. So if two equal hashes
match on p[-1], p[0] matches too. Hash collisions are harmless and result
in smaller shifts. */
#define hash2(p) (((size_t)(p)[0] - ((size_t)(p)[-1] << 3)) % sizeof (shift))
/* Fast memmem algorithm with guaranteed linear-time performance.
Small needles up to size 2 use a dedicated linear search. Longer needles
up to size 256 use a novel modified Horspool algorithm. It hashes pairs
of characters to quickly skip past mismatches. The main search loop only
exits if the last 2 characters match, avoiding unnecessary calls to memcmp
and allowing for a larger skip if there is no match. A self-adapting
filtering check is used to quickly detect mismatches in long needles.
By limiting the needle length to 256, the shift table can be reduced to 8
bits per entry, lowering preprocessing overhead and minimizing cache effects.
The limit also implies worst-case performance is linear.
Needles larger than 256 characters use the linear-time Two-Way algorithm. */
void *
__memmem (const void *haystack_start, size_t haystack_len,
const void *needle_start, size_t needle_len)
__memmem (const void *haystack, size_t hs_len,
const void *needle, size_t ne_len)
{
/* Abstract memory is considered to be an array of 'unsigned char' values,
not an array of 'char' values. See ISO C 99 section 6.2.6.1. */
const unsigned char *haystack = (const unsigned char *) haystack_start;
const unsigned char *needle = (const unsigned char *) needle_start;
const unsigned char *hs = (const unsigned char *) haystack;
const unsigned char *ne = (const unsigned char *) needle;
if (needle_len == 0)
/* The first occurrence of the empty string is deemed to occur at
the beginning of the string. */
return (void *) haystack;
if (ne_len == 0)
return (void *) hs;
if (ne_len == 1)
return (void *) memchr (hs, ne[0], hs_len);
/* Sanity check, otherwise the loop might search through the whole
memory. */
if (__glibc_unlikely (haystack_len < needle_len))
/* Ensure haystack length is >= needle length. */
if (hs_len < ne_len)
return NULL;
/* Use optimizations in memchr when possible, to reduce the search
size of haystack using a linear algorithm with a smaller
coefficient. However, avoid memchr for long needles, since we
can often achieve sublinear performance. */
if (needle_len < LONG_NEEDLE_THRESHOLD)
const unsigned char *end = hs + hs_len - ne_len;
if (ne_len == 2)
{
haystack = memchr (haystack, *needle, haystack_len);
if (!haystack || __builtin_expect (needle_len == 1, 0))
return (void *) haystack;
haystack_len -= haystack - (const unsigned char *) haystack_start;
if (haystack_len < needle_len)
return NULL;
/* Check whether we have a match. This improves performance since we
avoid the initialization overhead of the two-way algorithm. */
if (memcmp (haystack, needle, needle_len) == 0)
return (void *) haystack;
return two_way_short_needle (haystack, haystack_len, needle, needle_len);
uint32_t nw = ne[0] << 16 | ne[1], hw = hs[0] << 16 | hs[1];
for (hs++; hs <= end && hw != nw; )
hw = hw << 16 | *++hs;
return hw == nw ? (void *)hs - 1 : NULL;
}
else
return two_way_long_needle (haystack, haystack_len, needle, needle_len);
/* Use Two-Way algorithm for very long needles. */
if (__builtin_expect (ne_len > 256, 0))
return two_way_long_needle (hs, hs_len, ne, ne_len);
uint8_t shift[256];
size_t tmp, shift1;
size_t m1 = ne_len - 1;
size_t offset = 0;
memset (shift, 0, sizeof (shift));
for (int i = 1; i < m1; i++)
shift[hash2 (ne + i)] = i;
/* Shift1 is the amount we can skip after matching the hash of the
needle end but not the full needle. */
shift1 = m1 - shift[hash2 (ne + m1)];
shift[hash2 (ne + m1)] = m1;
for ( ; hs <= end; )
{
/* Skip past character pairs not in the needle. */
do
{
hs += m1;
tmp = shift[hash2 (hs)];
}
while (tmp == 0 && hs <= end);
/* If the match is not at the end of the needle, shift to the end
and continue until we match the hash of the needle end. */
hs -= tmp;
if (tmp < m1)
continue;
/* Hash of the last 2 characters matches. If the needle is long,
try to quickly filter out mismatches. */
if (m1 < 15 || memcmp (hs + offset, ne + offset, 8) == 0)
{
if (memcmp (hs, ne, m1) == 0)
return (void *) hs;
/* Adjust filter offset when it doesn't find the mismatch. */
offset = (offset >= 8 ? offset : m1) - 8;
}
/* Skip based on matching the hash of the needle end. */
hs += shift1;
}
return NULL;
}
libc_hidden_def (__memmem)
weak_alias (__memmem, memmem)
libc_hidden_weak (memmem)
#undef LONG_NEEDLE_THRESHOLD
+6 -3
View File
@@ -221,7 +221,7 @@ critical_factorization (const unsigned char *needle, size_t needle_len,
most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching.
If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 *
HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. */
static RETURN_TYPE
static inline RETURN_TYPE
two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
const unsigned char *needle, size_t needle_len)
{
@@ -382,8 +382,11 @@ two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
and sublinear performance O(HAYSTACK_LEN / NEEDLE_LEN) is possible.
If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 *
HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, and
sublinear performance is not possible. */
static RETURN_TYPE
sublinear performance is not possible.
Since this function is large and complex, block inlining to avoid
slowing down the common case of small needles. */
__attribute__((noinline)) static RETURN_TYPE
two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
const unsigned char *needle, size_t needle_len)
{
+2 -1
View File
@@ -33,7 +33,8 @@ __BEGIN_DECLS
#include <stddef.h>
/* Tell the caller that we provide correct C++ prototypes. */
#if defined __cplusplus && __GNUC_PREREQ (4, 4)
#if defined __cplusplus && (__GNUC_PREREQ (4, 4) \
|| __glibc_clang_prereq (3, 5))
# define __CORRECT_ISO_CPP_STRING_H_PROTO
#endif
+114 -45
View File
@@ -16,29 +16,17 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/* This particular implementation was written by Eric Blake, 2008. */
#ifndef _LIBC
# include <config.h>
#endif
/* Specification of strstr. */
#include <string.h>
#include <stdbool.h>
#ifndef _LIBC
# define __builtin_expect(expr, val) (expr)
#endif
#define RETURN_TYPE char *
#define AVAILABLE(h, h_l, j, n_l) \
(((j) + (n_l) <= (h_l)) \
|| ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \
(j) + (n_l) <= (h_l)))
#define CHECK_EOL (1)
#define RET0_IF_0(a) if (!a) goto ret0
#define FASTSEARCH(S,C,N) (void*) strchr ((void*)(S), (C))
#include "str-two-way.h"
#undef strstr
@@ -47,47 +35,128 @@
#define STRSTR strstr
#endif
/* Return the first occurrence of NEEDLE in HAYSTACK. Return HAYSTACK
if NEEDLE is empty, otherwise NULL if NEEDLE is not found in
HAYSTACK. */
static inline char *
strstr2 (const unsigned char *hs, const unsigned char *ne)
{
uint32_t h1 = (ne[0] << 16) | ne[1];
uint32_t h2 = 0;
for (int c = hs[0]; h1 != h2 && c != 0; c = *++hs)
h2 = (h2 << 16) | c;
return h1 == h2 ? (char *)hs - 2 : NULL;
}
static inline char *
strstr3 (const unsigned char *hs, const unsigned char *ne)
{
uint32_t h1 = ((uint32_t)ne[0] << 24) | (ne[1] << 16) | (ne[2] << 8);
uint32_t h2 = 0;
for (int c = hs[0]; h1 != h2 && c != 0; c = *++hs)
h2 = (h2 | c) << 8;
return h1 == h2 ? (char *)hs - 3 : NULL;
}
/* Hash character pairs so a small shift table can be used. All bits of
p[0] are included, but not all bits from p[-1]. So if two equal hashes
match on p[-1], p[0] matches too. Hash collisions are harmless and result
in smaller shifts. */
#define hash2(p) (((size_t)(p)[0] - ((size_t)(p)[-1] << 3)) % sizeof (shift))
/* Fast strstr algorithm with guaranteed linear-time performance.
Small needles up to size 3 use a dedicated linear search. Longer needles
up to size 256 use a novel modified Horspool algorithm. It hashes pairs
of characters to quickly skip past mismatches. The main search loop only
exits if the last 2 characters match, avoiding unnecessary calls to memcmp
and allowing for a larger skip if there is no match. A self-adapting
filtering check is used to quickly detect mismatches in long needles.
By limiting the needle length to 256, the shift table can be reduced to 8
bits per entry, lowering preprocessing overhead and minimizing cache effects.
The limit also implies worst-case performance is linear.
Needles larger than 256 characters use the linear-time Two-Way algorithm. */
char *
STRSTR (const char *haystack, const char *needle)
{
size_t needle_len; /* Length of NEEDLE. */
size_t haystack_len; /* Known minimum length of HAYSTACK. */
const unsigned char *hs = (const unsigned char *) haystack;
const unsigned char *ne = (const unsigned char *) needle;
/* Handle empty NEEDLE special case. */
if (needle[0] == '\0')
return (char *) haystack;
/* Handle short needle special cases first. */
if (ne[0] == '\0')
return (char *)hs;
hs = (const unsigned char *)strchr ((const char*)hs, ne[0]);
if (hs == NULL || ne[1] == '\0')
return (char*)hs;
if (ne[2] == '\0')
return strstr2 (hs, ne);
if (ne[3] == '\0')
return strstr3 (hs, ne);
/* Skip until we find the first matching char from NEEDLE. */
haystack = strchr (haystack, needle[0]);
if (haystack == NULL || needle[1] == '\0')
return (char *) haystack;
/* Ensure HAYSTACK length is at least as long as NEEDLE length.
Since a match may occur early on in a huge HAYSTACK, use strnlen
/* Ensure haystack length is at least as long as needle length.
Since a match may occur early on in a huge haystack, use strnlen
and read ahead a few cachelines for improved performance. */
needle_len = strlen (needle);
haystack_len = __strnlen (haystack, needle_len + 256);
if (haystack_len < needle_len)
size_t ne_len = strlen ((const char*)ne);
size_t hs_len = __strnlen ((const char*)hs, ne_len | 512);
if (hs_len < ne_len)
return NULL;
/* Check whether we have a match. This improves performance since we avoid
the initialization overhead of the two-way algorithm. */
if (memcmp (haystack, needle, needle_len) == 0)
return (char *) haystack;
/* Check whether we have a match. This improves performance since we
avoid initialization overheads. */
if (memcmp (hs, ne, ne_len) == 0)
return (char *) hs;
/* Perform the search. Abstract memory is considered to be an array
of 'unsigned char' values, not an array of 'char' values. See
ISO C 99 section 6.2.6.1. */
if (needle_len < LONG_NEEDLE_THRESHOLD)
return two_way_short_needle ((const unsigned char *) haystack,
haystack_len,
(const unsigned char *) needle, needle_len);
return two_way_long_needle ((const unsigned char *) haystack, haystack_len,
(const unsigned char *) needle, needle_len);
/* Use Two-Way algorithm for very long needles. */
if (__glibc_unlikely (ne_len > 256))
return two_way_long_needle (hs, hs_len, ne, ne_len);
const unsigned char *end = hs + hs_len - ne_len;
uint8_t shift[256];
size_t tmp, shift1;
size_t m1 = ne_len - 1;
size_t offset = 0;
/* Initialize bad character shift hash table. */
memset (shift, 0, sizeof (shift));
for (int i = 1; i < m1; i++)
shift[hash2 (ne + i)] = i;
/* Shift1 is the amount we can skip after matching the hash of the
needle end but not the full needle. */
shift1 = m1 - shift[hash2 (ne + m1)];
shift[hash2 (ne + m1)] = m1;
while (1)
{
if (__glibc_unlikely (hs > end))
{
end += __strnlen ((const char*)end + m1 + 1, 2048);
if (hs > end)
return NULL;
}
/* Skip past character pairs not in the needle. */
do
{
hs += m1;
tmp = shift[hash2 (hs)];
}
while (tmp == 0 && hs <= end);
/* If the match is not at the end of the needle, shift to the end
and continue until we match the hash of the needle end. */
hs -= tmp;
if (tmp < m1)
continue;
/* Hash of the last 2 characters matches. If the needle is long,
try to quickly filter out mismatches. */
if (m1 < 15 || memcmp (hs + offset, ne + offset, 8) == 0)
{
if (memcmp (hs, ne, m1) == 0)
return (void *) hs;
/* Adjust filter offset when it doesn't find the mismatch. */
offset = (offset >= 8 ? offset : m1) - 8;
}
/* Skip based on matching the hash of the needle end. */
hs += shift1;
}
}
libc_hidden_builtin_def (strstr)
#undef LONG_NEEDLE_THRESHOLD
+36 -3
View File
@@ -65,8 +65,8 @@ do_one_test (impl_t *impl, const CHAR *s, int c, size_t n, CHAR *exp_res)
CHAR *res = CALL (impl, s, c, n);
if (res != exp_res)
{
error (0, 0, "Wrong result in function %s %p %p", impl->name,
res, exp_res);
error (0, 0, "Wrong result in function %s (%p, %d, %zu) -> %p != %p",
impl->name, s, c, n, res, exp_res);
ret = 1;
return;
}
@@ -91,7 +91,7 @@ do_test (size_t align, size_t pos, size_t len, size_t n, int seek_char)
}
buf[align + len] = 0;
if (pos < len)
if (pos < MIN(n, len))
{
buf[align + pos] = seek_char;
buf[align + len] = -seek_char;
@@ -107,6 +107,38 @@ do_test (size_t align, size_t pos, size_t len, size_t n, int seek_char)
do_one_test (impl, (CHAR *) (buf + align), seek_char, n, result);
}
static void
do_overflow_tests (void)
{
size_t i, j, len;
const size_t one = 1;
uintptr_t buf_addr = (uintptr_t) buf1;
for (i = 0; i < 750; ++i)
{
do_test (0, i, 751, SIZE_MAX - i, BIG_CHAR);
do_test (0, i, 751, i - buf_addr, BIG_CHAR);
do_test (0, i, 751, -buf_addr - i, BIG_CHAR);
do_test (0, i, 751, SIZE_MAX - buf_addr - i, BIG_CHAR);
do_test (0, i, 751, SIZE_MAX - buf_addr + i, BIG_CHAR);
len = 0;
for (j = 8 * sizeof(size_t) - 1; j ; --j)
{
len |= one << j;
do_test (0, i, 751, len - i, BIG_CHAR);
do_test (0, i, 751, len + i, BIG_CHAR);
do_test (0, i, 751, len - buf_addr - i, BIG_CHAR);
do_test (0, i, 751, len - buf_addr + i, BIG_CHAR);
do_test (0, i, 751, ~len - i, BIG_CHAR);
do_test (0, i, 751, ~len + i, BIG_CHAR);
do_test (0, i, 751, ~len - buf_addr - i, BIG_CHAR);
do_test (0, i, 751, ~len - buf_addr + i, BIG_CHAR);
}
}
}
static void
do_random_tests (void)
{
@@ -221,6 +253,7 @@ test_main (void)
do_test (page_size / 2 - i, i, i, 1, 0x9B);
do_random_tests ();
do_overflow_tests ();
return ret;
}
+61
View File
@@ -134,6 +134,66 @@ do_test (size_t align1, size_t align2, size_t len1, size_t len2,
}
}
static void
do_overflow_tests (void)
{
size_t i, j, len;
const size_t one = 1;
CHAR *s1, *s2;
uintptr_t s1_addr;
s1 = (CHAR *) buf1;
s2 = (CHAR *) buf2;
s1_addr = (uintptr_t)s1;
for (j = 0; j < 200; ++j)
s2[j] = 32 + 23 * j % (BIG_CHAR - 32);
s2[200] = 0;
for (i = 0; i < 750; ++i) {
for (j = 0; j < i; ++j)
s1[j] = 32 + 23 * j % (BIG_CHAR - 32);
s1[i] = '\0';
FOR_EACH_IMPL (impl, 0)
{
s2[200] = '\0';
do_one_test (impl, s2, s1, SIZE_MAX - i);
s2[200] = '\0';
do_one_test (impl, s2, s1, i - s1_addr);
s2[200] = '\0';
do_one_test (impl, s2, s1, -s1_addr - i);
s2[200] = '\0';
do_one_test (impl, s2, s1, SIZE_MAX - s1_addr - i);
s2[200] = '\0';
do_one_test (impl, s2, s1, SIZE_MAX - s1_addr + i);
}
len = 0;
for (j = 8 * sizeof(size_t) - 1; j ; --j)
{
len |= one << j;
FOR_EACH_IMPL (impl, 0)
{
s2[200] = '\0';
do_one_test (impl, s2, s1, len - i);
s2[200] = '\0';
do_one_test (impl, s2, s1, len + i);
s2[200] = '\0';
do_one_test (impl, s2, s1, len - s1_addr - i);
s2[200] = '\0';
do_one_test (impl, s2, s1, len - s1_addr + i);
s2[200] = '\0';
do_one_test (impl, s2, s1, ~len - i);
s2[200] = '\0';
do_one_test (impl, s2, s1, ~len + i);
s2[200] = '\0';
do_one_test (impl, s2, s1, ~len - s1_addr - i);
s2[200] = '\0';
do_one_test (impl, s2, s1, ~len - s1_addr + i);
}
}
}
}
static void
do_random_tests (void)
{
@@ -316,6 +376,7 @@ test_main (void)
}
do_random_tests ();
do_overflow_tests ();
return ret;
}

Some files were not shown because too many files have changed in this diff Show More