diff --git a/ADVISORIES b/ADVISORIES
new file mode 100644
index 0000000000..d4e33f2df3
--- /dev/null
+++ b/ADVISORIES
@@ -0,0 +1,2 @@
+For the GNU C Library Security Advisories, see the git master branch:
+https://sourceware.org/git/?p=glibc.git;a=tree;f=advisories;hb=HEAD
diff --git a/NEWS b/NEWS
index 31281ac408..595998fc6e 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,33 @@ See the end for copying conditions.
Please send GNU C library bug reports via
using `glibc' in the "product" field.
+Version 2.40.1
+
+The following bugs are resolved with this release:
+
+ [19341] ctype: Fallback initialization of TLS using relocations
+ [27821] ungetc: Fix backup buffer leak on program exit
+ [30081] resolv: Do not wait for non-existing second DNS response after error
+ [31394] clone on sparc might fail with -EFAULT for no valid reason
+ [31717] elf: Avoid re-initializing already allocated TLS in dlopen
+ [31890] resolv: Allow short error responses to match any DNS query
+ [31943] _dl_find_object can fail if ld.so contains gaps between load segments
+ [31968] mremap implementation in C does not handle arguments correctly
+ [32026] strerror/strsignal TLS not handled correctly for secondary namespaces
+ [32052] Name space violation in fortify wrappers
+ [32137] libio: Attempt wide backup free only for non-legacy code
+ [32214] Fix missing randomness in __gen_tempname
+ [32231] elf: Change ldconfig auxcache magic number
+ [32245] glibc -Wstringop-overflow= build failure on hppa
+ [32470] x86: Avoid integer truncation with large cache sizes
+ [32483] ctype macros segfault in multithreaded programs with multiple libc.so
+ [32810] Crash on x86-64 if XSAVEC disable via tunable
+ [32987] elf: Fix subprocess status handling for tst-dlopen-sgid
+ [33185] Fix double-free after allocation failure in regcomp
+ [33234] Use TLS initial-exec model for __libc_tsd_CTYPE_* thread variables
+ [33361] nss: Group merge does not react to ERANGE during merge
+ [33601] aarch64: Do not link conform tests with -Wl,-z,force-bti
+
Version 2.40
Major new features:
diff --git a/advisories/GLIBC-SA-2023-0001 b/advisories/GLIBC-SA-2023-0001
deleted file mode 100644
index 3d19c91b6a..0000000000
--- a/advisories/GLIBC-SA-2023-0001
+++ /dev/null
@@ -1,14 +0,0 @@
-printf: incorrect output for integers with thousands separator and width field
-
-When the printf family of functions is called with a format specifier
-that uses an (enable grouping) and a minimum width
-specifier, the resulting output could be larger than reasonably expected
-by a caller that computed a tight bound on the buffer size. The
-resulting larger than expected output could result in a buffer overflow
-in the printf family of functions.
-
-CVE-Id: CVE-2023-25139
-Public-Date: 2023-02-02
-Vulnerable-Commit: e88b9f0e5cc50cab57a299dc7efe1a4eb385161d (2.37)
-Fix-Commit: c980549cc6a1c03c23cc2fe3e7b0fe626a0364b0 (2.38)
-Fix-Commit: 07b9521fc6369d000216b96562ff7c0ed32a16c4 (2.37-4)
diff --git a/advisories/GLIBC-SA-2023-0002 b/advisories/GLIBC-SA-2023-0002
deleted file mode 100644
index 5122669a64..0000000000
--- a/advisories/GLIBC-SA-2023-0002
+++ /dev/null
@@ -1,15 +0,0 @@
-getaddrinfo: Stack read overflow in no-aaaa mode
-
-If the system is configured in no-aaaa mode via /etc/resolv.conf,
-getaddrinfo is called for the AF_UNSPEC address family, and a DNS
-response is received over TCP that is larger than 2048 bytes,
-getaddrinfo may potentially disclose stack contents via the returned
-address data, or crash.
-
-CVE-Id: CVE-2023-4527
-Public-Date: 2023-09-12
-Vulnerable-Commit: f282cdbe7f436c75864e5640a409a10485e9abb2 (2.36)
-Fix-Commit: bd77dd7e73e3530203be1c52c8a29d08270cb25d (2.39)
-Fix-Commit: 4ea972b7edd7e36610e8cde18bf7a8149d7bac4f (2.36-113)
-Fix-Commit: b7529346025a130fee483d42178b5c118da971bb (2.37-38)
-Fix-Commit: b25508dd774b617f99419bdc3cf2ace4560cd2d6 (2.38-19)
diff --git a/advisories/GLIBC-SA-2023-0003 b/advisories/GLIBC-SA-2023-0003
deleted file mode 100644
index d3aef80348..0000000000
--- a/advisories/GLIBC-SA-2023-0003
+++ /dev/null
@@ -1,15 +0,0 @@
-getaddrinfo: Potential use-after-free
-
-When an NSS plugin only implements the _gethostbyname2_r and
-_getcanonname_r callbacks, getaddrinfo could use memory that was freed
-during buffer resizing, potentially causing a crash or read or write to
-arbitrary memory.
-
-CVE-Id: CVE-2023-4806
-Public-Date: 2023-09-12
-Fix-Commit: 973fe93a5675c42798b2161c6f29c01b0e243994 (2.39)
-Fix-Commit: e09ee267c03e3150c2c9ba28625ab130705a485e (2.34-420)
-Fix-Commit: e3ccb230a961b4797510e6a1f5f21fd9021853e7 (2.35-270)
-Fix-Commit: a9728f798ec7f05454c95637ee6581afaa9b487d (2.36-115)
-Fix-Commit: 6529a7466c935f36e9006b854d6f4e1d4876f942 (2.37-39)
-Fix-Commit: 00ae4f10b504bc4564e9f22f00907093f1ab9338 (2.38-20)
diff --git a/advisories/GLIBC-SA-2023-0004 b/advisories/GLIBC-SA-2023-0004
deleted file mode 100644
index 5286a7aa54..0000000000
--- a/advisories/GLIBC-SA-2023-0004
+++ /dev/null
@@ -1,16 +0,0 @@
-tunables: local privilege escalation through buffer overflow
-
-If a tunable of the form NAME=NAME=VAL is passed in the environment of a
-setuid program and NAME is valid, it may result in a buffer overflow,
-which could be exploited to achieve escalated privileges. This flaw was
-introduced in glibc 2.34.
-
-CVE-Id: CVE-2023-4911
-Public-Date: 2023-10-03
-Vulnerable-Commit: 2ed18c5b534d9e92fc006202a5af0df6b72e7aca (2.34)
-Fix-Commit: 1056e5b4c3f2d90ed2b4a55f96add28da2f4c8fa (2.39)
-Fix-Commit: dcc367f148bc92e7f3778a125f7a416b093964d9 (2.34-423)
-Fix-Commit: c84018a05aec80f5ee6f682db0da1130b0196aef (2.35-274)
-Fix-Commit: 22955ad85186ee05834e47e665056148ca07699c (2.36-118)
-Fix-Commit: b4e23c75aea756b4bddc4abcf27a1c6dca8b6bd3 (2.37-45)
-Fix-Commit: 750a45a783906a19591fb8ff6b7841470f1f5701 (2.38-27)
diff --git a/advisories/GLIBC-SA-2023-0005 b/advisories/GLIBC-SA-2023-0005
deleted file mode 100644
index cc4eb90b82..0000000000
--- a/advisories/GLIBC-SA-2023-0005
+++ /dev/null
@@ -1,18 +0,0 @@
-getaddrinfo: DoS due to memory leak
-
-The fix for CVE-2023-4806 introduced a memory leak when an application
-calls getaddrinfo for AF_INET6 with AI_CANONNAME, AI_ALL and AI_V4MAPPED
-flags set.
-
-CVE-Id: CVE-2023-5156
-Public-Date: 2023-09-25
-Vulnerable-Commit: e09ee267c03e3150c2c9ba28625ab130705a485e (2.34-420)
-Vulnerable-Commit: e3ccb230a961b4797510e6a1f5f21fd9021853e7 (2.35-270)
-Vulnerable-Commit: a9728f798ec7f05454c95637ee6581afaa9b487d (2.36-115)
-Vulnerable-Commit: 6529a7466c935f36e9006b854d6f4e1d4876f942 (2.37-39)
-Vulnerable-Commit: 00ae4f10b504bc4564e9f22f00907093f1ab9338 (2.38-20)
-Fix-Commit: 8006457ab7e1cd556b919f477348a96fe88f2e49 (2.34-421)
-Fix-Commit: 17092c0311f954e6f3c010f73ce3a78c24ac279a (2.35-272)
-Fix-Commit: 856bac55f98dc840e7c27cfa82262b933385de90 (2.36-116)
-Fix-Commit: 4473d1b87d04b25cdd0e0354814eeaa421328268 (2.37-42)
-Fix-Commit: 5ee59ca371b99984232d7584fe2b1a758b4421d3 (2.38-24)
diff --git a/advisories/GLIBC-SA-2024-0001 b/advisories/GLIBC-SA-2024-0001
deleted file mode 100644
index 28931c75ae..0000000000
--- a/advisories/GLIBC-SA-2024-0001
+++ /dev/null
@@ -1,15 +0,0 @@
-syslog: Heap buffer overflow in __vsyslog_internal
-
-__vsyslog_internal did not handle a case where printing a SYSLOG_HEADER
-containing a long program name failed to update the required buffer
-size, leading to the allocation and overflow of a too-small buffer on
-the heap.
-
-CVE-Id: CVE-2023-6246
-Public-Date: 2024-01-30
-Vulnerable-Commit: 52a5be0df411ef3ff45c10c7c308cb92993d15b1 (2.37)
-Fix-Commit: 6bd0e4efcc78f3c0115e5ea9739a1642807450da (2.39)
-Fix-Commit: 23514c72b780f3da097ecf33a793b7ba9c2070d2 (2.38-42)
-Fix-Commit: 97a4292aa4a2642e251472b878d0ec4c46a0e59a (2.37-57)
-Vulnerable-Commit: b0e7888d1fa2dbd2d9e1645ec8c796abf78880b9 (2.36-16)
-Fix-Commit: d1a83b6767f68b3cb5b4b4ea2617254acd040c82 (2.36-126)
diff --git a/advisories/GLIBC-SA-2024-0002 b/advisories/GLIBC-SA-2024-0002
deleted file mode 100644
index 940bfcf2fc..0000000000
--- a/advisories/GLIBC-SA-2024-0002
+++ /dev/null
@@ -1,15 +0,0 @@
-syslog: Heap buffer overflow in __vsyslog_internal
-
-__vsyslog_internal used the return value of snprintf/vsnprintf to
-calculate buffer sizes for memory allocation. If these functions (for
-any reason) failed and returned -1, the resulting buffer would be too
-small to hold output.
-
-CVE-Id: CVE-2023-6779
-Public-Date: 2024-01-30
-Vulnerable-Commit: 52a5be0df411ef3ff45c10c7c308cb92993d15b1 (2.37)
-Fix-Commit: 7e5a0c286da33159d47d0122007aac016f3e02cd (2.39)
-Fix-Commit: d0338312aace5bbfef85e03055e1212dd0e49578 (2.38-43)
-Fix-Commit: 67062eccd9a65d7fda9976a56aeaaf6c25a80214 (2.37-58)
-Vulnerable-Commit: b0e7888d1fa2dbd2d9e1645ec8c796abf78880b9 (2.36-16)
-Fix-Commit: 2bc9d7c002bdac38b5c2a3f11b78e309d7765b83 (2.36-127)
diff --git a/advisories/GLIBC-SA-2024-0003 b/advisories/GLIBC-SA-2024-0003
deleted file mode 100644
index b43a5150ab..0000000000
--- a/advisories/GLIBC-SA-2024-0003
+++ /dev/null
@@ -1,13 +0,0 @@
-syslog: Integer overflow in __vsyslog_internal
-
-__vsyslog_internal calculated a buffer size by adding two integers, but
-did not first check if the addition would overflow.
-
-CVE-Id: CVE-2023-6780
-Public-Date: 2024-01-30
-Vulnerable-Commit: 52a5be0df411ef3ff45c10c7c308cb92993d15b1 (2.37)
-Fix-Commit: ddf542da94caf97ff43cc2875c88749880b7259b (2.39)
-Fix-Commit: d37c2b20a4787463d192b32041c3406c2bd91de0 (2.38-44)
-Fix-Commit: 2b58cba076e912961ceaa5fa58588e4b10f791c0 (2.37-59)
-Vulnerable-Commit: b0e7888d1fa2dbd2d9e1645ec8c796abf78880b9 (2.36-16)
-Fix-Commit: b9b7d6a27aa0632f334352fa400771115b3c69b7 (2.36-128)
diff --git a/advisories/GLIBC-SA-2024-0004 b/advisories/GLIBC-SA-2024-0004
deleted file mode 100644
index 08df2b3118..0000000000
--- a/advisories/GLIBC-SA-2024-0004
+++ /dev/null
@@ -1,28 +0,0 @@
-ISO-2022-CN-EXT: fix out-of-bound writes when writing escape sequence
-
-The iconv() function in the GNU C Library versions 2.39 and older may
-overflow the output buffer passed to it by up to 4 bytes when converting
-strings to the ISO-2022-CN-EXT character set, which may be used to
-crash an application or overwrite a neighbouring variable.
-
-ISO-2022-CN-EXT uses escape sequences to indicate character set changes
-(as specified by RFC 1922). While the SOdesignation has the expected
-bounds checks, neither SS2designation nor SS3designation have its;
-allowing a write overflow of 1, 2, or 3 bytes with fixed values:
-'$+I', '$+J', '$+K', '$+L', '$+M', or '$*H'.
-
-CVE-Id: CVE-2024-2961
-Public-Date: 2024-04-17
-Vulnerable-Commit: 755104edc75c53f4a0e7440334e944ad3c6b32fc (2.1.93-169)
-Fix-Commit: f9dc609e06b1136bb0408be9605ce7973a767ada (2.40)
-Fix-Commit: 31da30f23cddd36db29d5b6a1c7619361b271fb4 (2.39-31)
-Fix-Commit: e1135387deded5d73924f6ca20c72a35dc8e1bda (2.38-66)
-Fix-Commit: 89ce64b269a897a7780e4c73a7412016381c6ecf (2.37-89)
-Fix-Commit: 4ed98540a7fd19f458287e783ae59c41e64df7b5 (2.36-164)
-Fix-Commit: 36280d1ce5e245aabefb877fe4d3c6cff95dabfa (2.35-315)
-Fix-Commit: a8b0561db4b9847ebfbfec20075697d5492a363c (2.34-459)
-Fix-Commit: ed4f16ff6bed3037266f1fa682ebd32a18fce29c (2.33-263)
-Fix-Commit: 682ad4c8623e611a971839990ceef00346289cc9 (2.32-140)
-Fix-Commit: 3703c32a8d304c1ee12126134ce69be965f38000 (2.31-154)
-
-Reported-By: Charles Fol
diff --git a/advisories/GLIBC-SA-2024-0005 b/advisories/GLIBC-SA-2024-0005
deleted file mode 100644
index a59596610a..0000000000
--- a/advisories/GLIBC-SA-2024-0005
+++ /dev/null
@@ -1,22 +0,0 @@
-nscd: Stack-based buffer overflow in netgroup cache
-
-If the Name Service Cache Daemon's (nscd) fixed size cache is exhausted
-by client requests then a subsequent client request for netgroup data
-may result in a stack-based buffer overflow. This flaw was introduced
-in glibc 2.15 when the cache was added to nscd.
-
-This vulnerability is only present in the nscd binary.
-
-CVE-Id: CVE-2024-33599
-Public-Date: 2024-04-23
-Vulnerable-Commit: 684ae515993269277448150a1ca70db3b94aa5bd (2.15)
-Fix-Commit: 69c58d5ef9f584ea198bd00f7964d364d0e6b921 (2.31-155)
-Fix-Commit: a77064893bfe8a701770e2f53a4d33805bc47a5a (2.32-141)
-Fix-Commit: 5c75001a96abcd50cbdb74df24c3f013188d076e (2.33-264)
-Fix-Commit: 52f73e5c4e29b14e79167272297977f360ae1e97 (2.34-460)
-Fix-Commit: 7a95873543ce225376faf13bb71c43dea6d24f86 (2.35-316)
-Fix-Commit: caa3151ca460bdd9330adeedd68c3112d97bffe4 (2.36-165)
-Fix-Commit: f75c298e747b2b8b41b1c2f551c011a52c41bfd1 (2.37-91)
-Fix-Commit: 5968aebb86164034b8f8421b4abab2f837a5bdaf (2.38-72)
-Fix-Commit: 1263d583d2e28afb8be53f8d6922f0842036f35d (2.39-35)
-Fix-Commit: 87801a8fd06db1d654eea3e4f7626ff476a9bdaa (2.40)
diff --git a/advisories/GLIBC-SA-2024-0006 b/advisories/GLIBC-SA-2024-0006
deleted file mode 100644
index d44148d3d9..0000000000
--- a/advisories/GLIBC-SA-2024-0006
+++ /dev/null
@@ -1,32 +0,0 @@
-nscd: Null pointer crash after notfound response
-
-If the Name Service Cache Daemon's (nscd) cache fails to add a not-found
-netgroup response to the cache, the client request can result in a null
-pointer dereference. This flaw was introduced in glibc 2.15 when the
-cache was added to nscd.
-
-This vulnerability is only present in the nscd binary.
-
-CVE-Id: CVE-2024-33600
-Public-Date: 2024-04-24
-Vulnerable-Commit: 684ae515993269277448150a1ca70db3b94aa5bd (2.15)
-Fix-Commit: b048a482f088e53144d26a61c390bed0210f49f2 (2.40)
-Fix-Commit: 7835b00dbce53c3c87bbbb1754a95fb5e58187aa (2.40)
-Fix-Commit: c99f886de54446cd4447db6b44be93dabbdc2f8b (2.39-37)
-Fix-Commit: 5a508e0b508c8ad53bd0d2fb48fd71b242626341 (2.39-36)
-Fix-Commit: 2ae9446c1b7a3064743b4a51c0bbae668ee43e4c (2.38-74)
-Fix-Commit: 541ea5172aa658c4bd5c6c6d6fd13903c3d5bb0a (2.38-73)
-Fix-Commit: a8070b31043c7585c36ba68a74298c4f7af075c3 (2.37-93)
-Fix-Commit: 5eea50c4402e39588de98aa1d4469a79774703d4 (2.37-92)
-Fix-Commit: f205b3af56740e3b014915b1bd3b162afe3407ef (2.36-167)
-Fix-Commit: c34f470a615b136170abd16142da5dd0c024f7d1 (2.36-166)
-Fix-Commit: bafadc589fbe21ae330e8c2af74db9da44a17660 (2.35-318)
-Fix-Commit: 4370bef52b0f3f3652c6aa13d7a9bb3ac079746d (2.35-317)
-Fix-Commit: 1f94122289a9bf7dba573f5d60327aaa2b85cf2e (2.34-462)
-Fix-Commit: 966d6ac9e40222b84bb21674cc4f83c8d72a5a26 (2.34-461)
-Fix-Commit: e3eef1b8fbdd3a7917af466ca9c4b7477251ca79 (2.33-266)
-Fix-Commit: f20a8d696b13c6261b52a6434899121f8b19d5a7 (2.33-265)
-Fix-Commit: be602180146de37582a3da3a0caa4b719645de9c (2.32-143)
-Fix-Commit: 394eae338199078b7961b051c191539870742d7b (2.32-142)
-Fix-Commit: 8d7949183760170c61e55def723c1d8050187874 (2.31-157)
-Fix-Commit: 304ce5fe466c4762b21b36c26926a4657b59b53e (2.31-156)
diff --git a/advisories/GLIBC-SA-2024-0007 b/advisories/GLIBC-SA-2024-0007
deleted file mode 100644
index b6928fa27a..0000000000
--- a/advisories/GLIBC-SA-2024-0007
+++ /dev/null
@@ -1,28 +0,0 @@
-nscd: netgroup cache may terminate daemon on memory allocation failure
-
-The Name Service Cache Daemon's (nscd) netgroup cache uses xmalloc or
-xrealloc and these functions may terminate the process due to a memory
-allocation failure resulting in a denial of service to the clients. The
-flaw was introduced in glibc 2.15 when the cache was added to nscd.
-
-This vulnerability is only present in the nscd binary.
-
-Subsequent refactoring of the netgroup cache only added more uses of
-xmalloc and xrealloc. Uses of xmalloc and xrealloc in other parts of
-nscd only occur during startup of the daemon and so are not affected by
-client requests that could trigger an out of memory followed by
-termination.
-
-CVE-Id: CVE-2024-33601
-Public-Date: 2024-04-24
-Vulnerable-Commit: 684ae515993269277448150a1ca70db3b94aa5bd (2.15)
-Fix-Commit: c04a21e050d64a1193a6daab872bca2528bda44b (2.40)
-Fix-Commit: a9a8d3eebb145779a18d90e3966009a1daa63cd8 (2.39-38)
-Fix-Commit: 71af8ca864345d39b746d5cee84b94b430fad5db (2.38-75)
-Fix-Commit: 6e106dc214d6a033a4e945d1c6cf58061f1c5f1f (2.37-94)
-Fix-Commit: b6742463694b1dfdd5120b91ee21cf05d15ec2e2 (2.36-168)
-Fix-Commit: 7a5864cac60e06000394128a5a2817b03542f5a3 (2.35-319)
-Fix-Commit: 86f1d5f4129c373ac6fb6df5bcf38273838843cb (2.34-463)
-Fix-Commit: 4d27d4b9a188786fc6a56745506cec2acfc51f83 (2.33-267)
-Fix-Commit: 3ed195a8ec89da281e3c4bf887a13d281b72d8f4 (2.32-144)
-Fix-Commit: bbf5a58ccb55679217f94de706164d15372fbbc0 (2.31-158)
diff --git a/advisories/GLIBC-SA-2024-0008 b/advisories/GLIBC-SA-2024-0008
deleted file mode 100644
index d93e2a6f0b..0000000000
--- a/advisories/GLIBC-SA-2024-0008
+++ /dev/null
@@ -1,26 +0,0 @@
-nscd: netgroup cache assumes NSS callback uses in-buffer strings
-
-The Name Service Cache Daemon's (nscd) netgroup cache can corrupt memory
-when the NSS callback does not store all strings in the provided buffer.
-The flaw was introduced in glibc 2.15 when the cache was added to nscd.
-
-This vulnerability is only present in the nscd binary.
-
-There is no guarantee from the NSS callback API that the returned
-strings are all within the buffer. However, the netgroup cache code
-assumes that the NSS callback uses in-buffer strings and if it doesn't
-the buffer resizing logic could lead to potential memory corruption.
-
-CVE-Id: CVE-2024-33602
-Public-Date: 2024-04-24
-Vulnerable-Commit: 684ae515993269277448150a1ca70db3b94aa5bd (2.15)
-Fix-Commit: c04a21e050d64a1193a6daab872bca2528bda44b (2.40)
-Fix-Commit: a9a8d3eebb145779a18d90e3966009a1daa63cd8 (2.39-38)
-Fix-Commit: 71af8ca864345d39b746d5cee84b94b430fad5db (2.38-75)
-Fix-Commit: 6e106dc214d6a033a4e945d1c6cf58061f1c5f1f (2.37-94)
-Fix-Commit: b6742463694b1dfdd5120b91ee21cf05d15ec2e2 (2.36-168)
-Fix-Commit: 7a5864cac60e06000394128a5a2817b03542f5a3 (2.35-319)
-Fix-Commit: 86f1d5f4129c373ac6fb6df5bcf38273838843cb (2.34-463)
-Fix-Commit: 4d27d4b9a188786fc6a56745506cec2acfc51f83 (2.33-267)
-Fix-Commit: 3ed195a8ec89da281e3c4bf887a13d281b72d8f4 (2.32-144)
-Fix-Commit: bbf5a58ccb55679217f94de706164d15372fbbc0 (2.31-158)
diff --git a/advisories/README b/advisories/README
deleted file mode 100644
index b8f8a829ca..0000000000
--- a/advisories/README
+++ /dev/null
@@ -1,77 +0,0 @@
-GNU C Library Security Advisory Format
-======================================
-
-Security advisories in this directory follow a simple git commit log
-format, with a heading and free-format description augmented with tags
-to allow parsing key information. References to code changes are
-specific to the glibc repository and follow a specific format:
-
- Tag-name: (release-version)
-
-The indicates a specific commit in the repository. The
-release-version indicates the publicly consumable release in which this
-commit is known to exist. The release-version is derived from the
-git-describe format, (i.e. stripped out from glibc-2.34.NNN-gxxxx) and
-is of the form 2.34-NNN. If the -NNN suffix is absent, it means that
-the change is in that release tarball, otherwise the change is on the
-release/2.YY/master branch and not in any released tarball.
-
-The following tags are currently being used:
-
-CVE-Id:
-This is the CVE-Id assigned under the CVE Program
-(https://www.cve.org/).
-
-Public-Date:
-The date this issue became publicly known.
-
-Vulnerable-Commit:
-The commit that introduced this vulnerability. There could be multiple
-entries, one for each release branch in the glibc repository; the
-release-version portion of this tag should tell you which branch this is
-on.
-
-Fix-Commit:
-The commit that fixed this vulnerability. There could be multiple
-entries for each release branch in the glibc repository, indicating that
-all of those commits contributed to fixing that issue in each of those
-branches.
-
-Reported-By:
-The entity that reported this issue. There could be multiple entries, one for
-each reporter.
-
-Adding an Advisory
-------------------
-
-An advisory for a CVE needs to be added on the master branch in two steps:
-
-1. Add the text of the advisory without any Fix-Commit tags along with
- the fix for the CVE. Add the Vulnerable-Commit tag, if applicable.
- The advisories directory does not exist in release branches, so keep
- the advisory text commit distinct from the code changes, to ease
- backports. Ask for the GLIBC-SA advisory number from the security
- team.
-
-2. Finish all backports on release branches and then back on the msater
- branch, add all commit refs to the advisory using the Fix-Commit
- tags. Don't bother adding the release-version subscript since the
- next step will overwrite it.
-
-3. Run the process-advisories.sh script in the scripts directory on the
- advisory:
-
- scripts/process-advisories.sh update GLIBC-SA-YYYY-NNNN
-
- (replace YYYY-NNNN with the actual advisory number).
-
-4. Verify the updated advisory and push the result.
-
-Getting a NEWS snippet from advisories
---------------------------------------
-
-Run:
-
- scripts/process-advisories.sh news
-
-and copy the content into the NEWS file.
diff --git a/assert/Makefile b/assert/Makefile
index 35dc908ddb..c0fe660bd6 100644
--- a/assert/Makefile
+++ b/assert/Makefile
@@ -38,6 +38,7 @@ tests := \
test-assert-perr \
tst-assert-c++ \
tst-assert-g++ \
+ tst-assert-sa-2025-0001 \
# tests
ifeq ($(have-cxx-thread_local),yes)
diff --git a/assert/assert.c b/assert/assert.c
index c29629f5f6..b6e37d694c 100644
--- a/assert/assert.c
+++ b/assert/assert.c
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -65,7 +66,8 @@ __assert_fail_base (const char *fmt, const char *assertion, const char *file,
(void) __fxprintf (NULL, "%s", str);
(void) fflush (stderr);
- total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
+ total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1,
+ GLRO(dl_pagesize));
struct abort_msg_s *buf = __mmap (NULL, total, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
if (__glibc_likely (buf != MAP_FAILED))
diff --git a/assert/tst-assert-sa-2025-0001.c b/assert/tst-assert-sa-2025-0001.c
new file mode 100644
index 0000000000..102cb0078d
--- /dev/null
+++ b/assert/tst-assert-sa-2025-0001.c
@@ -0,0 +1,92 @@
+/* Test for CVE-2025-0395.
+ Copyright The GNU Toolchain Authors.
+ 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
+ . */
+
+/* Test that a large enough __progname does not result in a buffer overflow
+ when printing an assertion failure. This was CVE-2025-0395. */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern const char *__progname;
+
+int
+do_test (int argc, char **argv)
+{
+
+ support_need_proc ("Reads /proc/self/maps to add guards to writable maps.");
+ ignore_stderr ();
+
+ /* XXX assumes that the assert is on a 2 digit line number. */
+ const char *prompt = ": %s:99: do_test: Assertion `argc < 1' failed.\n";
+
+ int ret = fprintf (stderr, prompt, __FILE__);
+ if (ret < 0)
+ FAIL_EXIT1 ("fprintf failed: %m\n");
+
+ size_t pagesize = getpagesize ();
+ size_t namesize = pagesize - 1 - ret;
+
+ /* Alter the progname so that the assert message fills the entire page. */
+ char progname[namesize];
+ memset (progname, 'A', namesize - 1);
+ progname[namesize - 1] = '\0';
+ __progname = progname;
+
+ FILE *f = xfopen ("/proc/self/maps", "r");
+ char *line = NULL;
+ size_t len = 0;
+ uintptr_t prev_to = 0;
+
+ /* Pad the beginning of every writable mapping with a PROT_NONE map. This
+ ensures that the mmap in the assert_fail path never ends up below a
+ writable map and will terminate immediately in case of a buffer
+ overflow. */
+ while (xgetline (&line, &len, f))
+ {
+ uintptr_t from, to;
+ char perm[4];
+
+ sscanf (line, "%" SCNxPTR "-%" SCNxPTR " %c%c%c%c ",
+ &from, &to,
+ &perm[0], &perm[1], &perm[2], &perm[3]);
+
+ bool writable = (memchr (perm, 'w', 4) != NULL);
+
+ if (prev_to != 0 && from - prev_to > pagesize && writable)
+ xmmap ((void *) from - pagesize, pagesize, PROT_NONE,
+ MAP_ANONYMOUS | MAP_PRIVATE, 0);
+
+ prev_to = to;
+ }
+
+ xfclose (f);
+
+ assert (argc < 1);
+ return 0;
+}
+
+#define EXPECTED_SIGNAL SIGABRT
+#define TEST_FUNCTION_ARGV do_test
+#include
diff --git a/benchtests/atanh-inputs b/benchtests/atanh-inputs
index 455aa65b65..4985293254 100644
--- a/benchtests/atanh-inputs
+++ b/benchtests/atanh-inputs
@@ -1,6 +1,7 @@
## args: double
## ret: double
## includes: math.h
+## name: workload-random
0x1.5a2730bacd94ap-1
-0x1.b57eb40fc048ep-21
-0x1.c0b185fb450e2p-17
diff --git a/benchtests/sinh-inputs b/benchtests/sinh-inputs
index 7b1ac46a39..2fcb2fabf8 100644
--- a/benchtests/sinh-inputs
+++ b/benchtests/sinh-inputs
@@ -1,6 +1,7 @@
## args: double
## ret: double
## includes: math.h
+## name: workload-random
0x1.bcb6129b5ff2bp8
-0x1.63057386325ebp9
0x1.62f1d7dc4e8bfp9
diff --git a/configure b/configure
index 1d543548cd..77e1601250 100755
--- a/configure
+++ b/configure
@@ -4901,6 +4901,9 @@ with_fp_cond=1
# A preconfigure script may define another name to TLS descriptor variant
mtls_descriptor=gnu2
+# A preconfigure script may define another name to traditional TLS variant
+mtls_traditional=gnu
+
if frags=`ls -d $srcdir/sysdeps/*/preconfigure 2> /dev/null`
then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysdeps preconfigure fragments" >&5
@@ -7223,6 +7226,39 @@ printf "%s\n" "$libc_cv_mtls_descriptor" >&6; }
config_vars="$config_vars
have-mtls-descriptor = $libc_cv_mtls_descriptor"
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for traditional tls support" >&5
+printf %s "checking for traditional tls support... " >&6; }
+if test ${libc_cv_test_mtls_traditional+y}
+then :
+ printf %s "(cached) " >&6
+else case e in #(
+ e) cat > conftest.c <&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+then
+ libc_cv_test_mtls_traditional=$mtls_traditional
+else
+ libc_cv_test_mtls_traditional=no
+fi
+rm -f conftest* ;;
+esac
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_test_mtls_traditional" >&5
+printf "%s\n" "$libc_cv_test_mtls_traditional" >&6; }
+config_vars="$config_vars
+have-test-mtls-traditional = $libc_cv_test_mtls_traditional"
+
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if -Wno-ignored-attributes is required for aliases" >&5
printf %s "checking if -Wno-ignored-attributes is required for aliases... " >&6; }
if test ${libc_cv_wno_ignored_attributes+y}
diff --git a/configure.ac b/configure.ac
index 9cbc0bf68f..eb4f26d592 100644
--- a/configure.ac
+++ b/configure.ac
@@ -469,6 +469,9 @@ with_fp_cond=1
# A preconfigure script may define another name to TLS descriptor variant
mtls_descriptor=gnu2
+# A preconfigure script may define another name to traditional TLS variant
+mtls_traditional=gnu
+
dnl Let sysdeps/*/preconfigure act here.
LIBC_PRECONFIGURE([$srcdir], [for sysdeps])
@@ -1334,6 +1337,28 @@ rm -f conftest*])
AC_SUBST(libc_cv_mtls_descriptor)
LIBC_CONFIG_VAR([have-mtls-descriptor], [$libc_cv_mtls_descriptor])
+dnl Check if CC supports traditional tls.
+AC_CACHE_CHECK([for traditional tls support],
+ libc_cv_test_mtls_traditional,
+[dnl
+cat > conftest.c <&AS_MESSAGE_LOG_FD])
+then
+ libc_cv_test_mtls_traditional=$mtls_traditional
+else
+ libc_cv_test_mtls_traditional=no
+fi
+rm -f conftest*])
+LIBC_CONFIG_VAR([have-test-mtls-traditional],
+ [$libc_cv_test_mtls_traditional])
+
dnl clang emits an warning for a double alias redirection, to warn the
dnl original symbol is sed even when weak definition overrides it.
dnl It is a usual pattern for weak_alias, where multiple alias point to
diff --git a/ctype/Makefile b/ctype/Makefile
index 3e09938bd1..b7cd5f2282 100644
--- a/ctype/Makefile
+++ b/ctype/Makefile
@@ -36,6 +36,23 @@ aux := ctype-info
tests := \
test_ctype \
+ tst-ctype-tls-dlmopen \
+ tst-ctype-tls-dlopen-static \
# tests
+tests-static := \
+ tst-ctype-tls-dlopen-static \
+ # tests-static
+
+modules-names := \
+ tst-ctype-tls-mod \
+ # modules-names
+
include ../Rules
+
+$(objpfx)tst-ctype-tls-dlmopen: $(shared-thread-library)
+$(objpfx)tst-ctype-tls-dlmopen.out: $(objpfx)tst-ctype-tls-mod.so
+$(objpfx)tst-ctype-tls-dlopen-static: $(static-thread-library)
+$(objpfx)tst-ctype-tls-dlopen-static.out: $(objpfx)tst-ctype-tls-mod.so
+tst-ctype-tls-dlopen-static-ENV = \
+ LD_LIBRARY_PATH=$(ld-library-path):$(common-objpfx):$(common-objpfx)elf
diff --git a/ctype/ctype-info.c b/ctype/ctype-info.c
index 9032547567..b6cdf7eb66 100644
--- a/ctype/ctype-info.c
+++ b/ctype/ctype-info.c
@@ -19,20 +19,28 @@
#include
#include
-__libc_tsd_define (, const uint16_t *, CTYPE_B)
-__libc_tsd_define (, const int32_t *, CTYPE_TOLOWER)
-__libc_tsd_define (, const int32_t *, CTYPE_TOUPPER)
+/* Fallback initialization using relocations. See the _nl_C_locobj
+ initializers in locale/xlocale.c. Usually, this is overwritten by
+ __ctype_init before user code runs, but this does not happen for
+ threads in secondary namespaces. With the initializers, secondary
+ namespaces at least get locale data from the C locale. */
+__thread const uint16_t * __libc_tsd_CTYPE_B attribute_tls_model_ie
+ = (const uint16_t *) _nl_C_LC_CTYPE_class + 128;
+__thread const int32_t * __libc_tsd_CTYPE_TOLOWER attribute_tls_model_ie
+ = (const int32_t *) _nl_C_LC_CTYPE_tolower + 128;
+__thread const int32_t * __libc_tsd_CTYPE_TOUPPER attribute_tls_model_ie
+ = (const int32_t *) _nl_C_LC_CTYPE_toupper + 128;
void
__ctype_init (void)
{
- const uint16_t **bp = __libc_tsd_address (const uint16_t *, CTYPE_B);
- *bp = (const uint16_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_CLASS) + 128;
- const int32_t **up = __libc_tsd_address (const int32_t *, CTYPE_TOUPPER);
- *up = ((int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOUPPER) + 128);
- const int32_t **lp = __libc_tsd_address (const int32_t *, CTYPE_TOLOWER);
- *lp = ((int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOLOWER) + 128);
+ __libc_tsd_CTYPE_B
+ = ((const uint16_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_CLASS)) + 128;
+ __libc_tsd_CTYPE_TOUPPER
+ = ((const int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOUPPER)) + 128;
+ __libc_tsd_CTYPE_TOLOWER =
+ ((const int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOLOWER)) + 128;
}
libc_hidden_def (__ctype_init)
@@ -41,10 +49,7 @@ libc_hidden_def (__ctype_init)
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
/* Defined in locale/C-ctype.c. */
-extern const char _nl_C_LC_CTYPE_class[] attribute_hidden;
extern const char _nl_C_LC_CTYPE_class32[] attribute_hidden;
-extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden;
-extern const char _nl_C_LC_CTYPE_tolower[] attribute_hidden;
extern const char _nl_C_LC_CTYPE_class_upper[] attribute_hidden;
extern const char _nl_C_LC_CTYPE_class_lower[] attribute_hidden;
extern const char _nl_C_LC_CTYPE_class_alpha[] attribute_hidden;
diff --git a/ctype/tst-ctype-tls-dlmopen.c b/ctype/tst-ctype-tls-dlmopen.c
new file mode 100644
index 0000000000..f7eeb65551
--- /dev/null
+++ b/ctype/tst-ctype-tls-dlmopen.c
@@ -0,0 +1,2 @@
+#define DO_STATIC_TEST 0
+#include "tst-ctype-tls-skeleton.c"
diff --git a/ctype/tst-ctype-tls-dlopen-static.c b/ctype/tst-ctype-tls-dlopen-static.c
new file mode 100644
index 0000000000..c2c09c362c
--- /dev/null
+++ b/ctype/tst-ctype-tls-dlopen-static.c
@@ -0,0 +1,2 @@
+#define DO_STATIC_TEST 1
+#include "tst-ctype-tls-skeleton.c"
diff --git a/sysdeps/powerpc/powerpc64/multiarch/memchr-power10.S b/ctype/tst-ctype-tls-mod.c
similarity index 66%
rename from sysdeps/powerpc/powerpc64/multiarch/memchr-power10.S
rename to ctype/tst-ctype-tls-mod.c
index 7d35ef28a9..52cbb9dcb6 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/memchr-power10.S
+++ b/ctype/tst-ctype-tls-mod.c
@@ -1,5 +1,5 @@
-/* Optimized memchr implementation for POWER10/PPC64.
- Copyright (C) 2016-2024 Free Software Foundation, Inc.
+/* Wrappers for macros in a secondary namespace.
+ Copyright (C) 2025 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -16,13 +16,22 @@
License along with the GNU C Library; if not, see
. */
-#if defined __LITTLE_ENDIAN__ && IS_IN (libc)
-#define MEMCHR __memchr_power10
+#include
-#undef libc_hidden_builtin_def
-#define libc_hidden_builtin_def(name)
-#undef weak_alias
-#define weak_alias(name,alias)
+int
+my_isalpha (int ch)
+{
+ return isalpha (ch);
+}
-#include
-#endif
+int
+my_toupper (int ch)
+{
+ return toupper (ch);
+}
+
+int
+my_tolower (int ch)
+{
+ return tolower (ch);
+}
diff --git a/ctype/tst-ctype-tls-skeleton.c b/ctype/tst-ctype-tls-skeleton.c
new file mode 100644
index 0000000000..8c53e35899
--- /dev/null
+++ b/ctype/tst-ctype-tls-skeleton.c
@@ -0,0 +1,67 @@
+/* Test that in a secondary namespace works.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+/* Before this file is included, define DO_STATIC_TEST to 0 or 1.
+ With 0, dlmopen is used for the test. With 1, dlopen is used. */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int (*my_isalpha) (int);
+static int (*my_toupper) (int);
+static int (*my_tolower) (int);
+
+static void *
+checks (void *ignore)
+{
+ TEST_VERIFY (my_isalpha ('a'));
+ TEST_VERIFY (!my_isalpha ('0'));
+ TEST_COMPARE (my_toupper ('a'), 'A');
+ TEST_COMPARE (my_toupper ('A'), 'A');
+ TEST_COMPARE (my_tolower ('a'), 'a');
+ TEST_COMPARE (my_tolower ('A'), 'a');
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ char *dso = xasprintf ("%s/ctype/tst-ctype-tls-mod.so", support_objdir_root);
+#if DO_STATIC_TEST
+ void *handle = xdlopen (dso, RTLD_LAZY);
+#else
+ void *handle = xdlmopen (LM_ID_NEWLM, dso, RTLD_LAZY);
+#endif
+ my_isalpha = xdlsym (handle, "my_isalpha");
+ my_toupper = xdlsym (handle, "my_toupper");
+ my_tolower = xdlsym (handle, "my_tolower");
+
+ checks (NULL);
+ xpthread_join (xpthread_create (NULL, checks, NULL));
+
+ xdlclose (handle);
+ free (dso);
+
+ return 0;
+}
+
+#include
diff --git a/debug/Makefile b/debug/Makefile
index 3903cc97a3..76c311d284 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -287,6 +287,7 @@ tests = \
tst-fortify-wide \
tst-longjmp_chk \
tst-longjmp_chk2 \
+ tst-longjmp_chk3 \
tst-realpath-chk \
tst-sprintf-fortify-rdonly \
tst-sprintf-fortify-unchecked \
diff --git a/debug/pcprofiledump.c b/debug/pcprofiledump.c
index 049a9c2744..94530f0cf9 100644
--- a/debug/pcprofiledump.c
+++ b/debug/pcprofiledump.c
@@ -75,6 +75,44 @@ static struct argp argp =
options, parse_opt, args_doc, doc, NULL, more_help
};
+/* Try to read SIZE bytes from FD and store them on BUF. Terminate
+ the process upon read error. Also terminate the process if less
+ than SIZE bytes are remaining in the file. If !IN_HEADER, do not
+ terminate the process if the end of the file is encountered
+ immediately, before any bytes are read.
+
+ Returns true if SIZE bytes have been read, and false if no bytes
+ have been read due to an end-of-file condition. */
+static bool
+read_exactly (int fd, void *buffer, size_t size, bool in_header)
+{
+ char *p = buffer;
+ char *end = p + size;
+ while (p < end)
+ {
+ ssize_t ret = TEMP_FAILURE_RETRY (read (fd, p, end - p));
+ if (ret < 0)
+ {
+ if (in_header)
+ error (EXIT_FAILURE, errno, _("cannot read header"));
+ else
+ error (EXIT_FAILURE, errno, _("cannot read pointer pair"));
+ }
+ if (ret == 0)
+ {
+ if (p == buffer && !in_header)
+ /* Nothing has been read. */
+ return false;
+ if (in_header)
+ error (EXIT_FAILURE, 0, _("unexpected end of file in header"));
+ else
+ error (EXIT_FAILURE, 0,
+ _("unexpected end of file in pointer pair"));
+ }
+ p += ret;
+ }
+ return true;
+}
int
main (int argc, char *argv[])
@@ -110,8 +148,7 @@ main (int argc, char *argv[])
/* Read the first 4-byte word. It contains the information about
the word size and the endianness. */
uint32_t word;
- if (TEMP_FAILURE_RETRY (read (fd, &word, 4)) != 4)
- error (EXIT_FAILURE, errno, _("cannot read header"));
+ read_exactly (fd, &word, sizeof (word), true);
/* Check whether we have to swap the byte order. */
int must_swap = (word & 0x0fffffff) == bswap_32 (0xdeb00000);
@@ -121,56 +158,30 @@ main (int argc, char *argv[])
/* We have two loops, one for 32 bit pointers, one for 64 bit pointers. */
if (word == 0xdeb00004)
{
- union
- {
- uint32_t ptrs[2];
- char bytes[8];
- } pair;
+ uint32_t ptrs[2];
while (1)
{
- size_t len = sizeof (pair);
- size_t n;
-
- while (len > 0
- && (n = TEMP_FAILURE_RETRY (read (fd, &pair.bytes[8 - len],
- len))) != 0)
- len -= n;
-
- if (len != 0)
- /* Nothing to read. */
+ if (!read_exactly (fd, ptrs, sizeof (ptrs), false))
break;
printf ("this = %#010" PRIx32 ", caller = %#010" PRIx32 "\n",
- must_swap ? bswap_32 (pair.ptrs[0]) : pair.ptrs[0],
- must_swap ? bswap_32 (pair.ptrs[1]) : pair.ptrs[1]);
+ must_swap ? bswap_32 (ptrs[0]) : ptrs[0],
+ must_swap ? bswap_32 (ptrs[1]) : ptrs[1]);
}
}
else if (word == 0xdeb00008)
{
- union
- {
- uint64_t ptrs[2];
- char bytes[16];
- } pair;
+ uint64_t ptrs[2];
while (1)
{
- size_t len = sizeof (pair);
- size_t n;
-
- while (len > 0
- && (n = TEMP_FAILURE_RETRY (read (fd, &pair.bytes[8 - len],
- len))) != 0)
- len -= n;
-
- if (len != 0)
- /* Nothing to read. */
+ if (!read_exactly (fd, ptrs, sizeof (ptrs), false))
break;
printf ("this = %#018" PRIx64 ", caller = %#018" PRIx64 "\n",
- must_swap ? bswap_64 (pair.ptrs[0]) : pair.ptrs[0],
- must_swap ? bswap_64 (pair.ptrs[1]) : pair.ptrs[1]);
+ must_swap ? bswap_64 (ptrs[0]) : ptrs[0],
+ must_swap ? bswap_64 (ptrs[1]) : ptrs[1]);
}
}
else
diff --git a/debug/tst-fortify-syslog.c b/debug/tst-fortify-syslog.c
index a7ddbf7c6b..2712acf689 100644
--- a/debug/tst-fortify-syslog.c
+++ b/debug/tst-fortify-syslog.c
@@ -22,7 +22,6 @@
#include
#include
#include
-#include
#include
#include
@@ -46,18 +45,13 @@ handler (int sig)
_exit (127);
}
-#define FAIL() \
- do { \
- printf ("Failure on line %d\n", __LINE__); \
- support_record_failure (); \
- } while (0)
#define CHK_FAIL_START \
chk_fail_ok = 1; \
if (! setjmp (chk_fail_buf)) \
{
#define CHK_FAIL_END \
chk_fail_ok = 0; \
- FAIL (); \
+ FAIL ("not supposed to reach here"); \
}
static void
diff --git a/debug/tst-longjmp_chk3.c b/debug/tst-longjmp_chk3.c
index 9ff9977207..9b9db3b9e9 100644
--- a/debug/tst-longjmp_chk3.c
+++ b/debug/tst-longjmp_chk3.c
@@ -18,9 +18,13 @@
#include
#include
+#include
#include
+#include
-static char buf[SIGSTKSZ * 4];
+#include
+
+static char *buf;
static jmp_buf jb;
static void
@@ -49,8 +53,10 @@ do_test (void)
set_fortify_handler (handler);
/* Create a valid signal stack and enable it. */
+ size_t bufsize = SIGSTKSZ * 4;
+ buf = xmalloc (bufsize);
ss.ss_sp = buf;
- ss.ss_size = sizeof (buf);
+ ss.ss_size = bufsize;
ss.ss_flags = 0;
if (sigaltstack (&ss, NULL) < 0)
{
@@ -65,8 +71,8 @@ do_test (void)
/* Shrink the signal stack so the jmpbuf is now invalid.
We adjust the start & end to handle stacks that grow up & down. */
- ss.ss_sp = buf + sizeof (buf) / 2;
- ss.ss_size = sizeof (buf) / 4;
+ ss.ss_sp = buf + bufsize / 2;
+ ss.ss_size = bufsize / 4;
if (sigaltstack (&ss, NULL) < 0)
{
printf ("second sigaltstack failed: %m\n");
diff --git a/elf/Makefile b/elf/Makefile
index a3475f3fb5..0303e08557 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -34,7 +34,6 @@ routines = \
dl-addr \
dl-addr-obj \
dl-early_allocate \
- dl-find_object \
dl-iteratephdr \
dl-libc \
dl-origin \
@@ -58,9 +57,11 @@ dl-routines = \
dl-close \
dl-debug \
dl-debug-symbols \
+ dl-debug_state \
dl-deps \
dl-exception \
dl-execstack \
+ dl-find_object \
dl-fini \
dl-init \
dl-load \
@@ -266,6 +267,7 @@ tests-static-normal := \
tst-array1-static \
tst-array5-static \
tst-dl-iter-static \
+ tst-dlopen-sgid \
tst-dst-static \
tst-env-setuid-static \
tst-getauxval-static \
@@ -378,6 +380,7 @@ tests += \
tst-align3 \
tst-audit-tlsdesc \
tst-audit-tlsdesc-dlopen \
+ tst-audit-tlsdesc-dlopen2 \
tst-audit1 \
tst-audit2 \
tst-audit8 \
@@ -414,8 +417,16 @@ tests += \
tst-dlmopen1 \
tst-dlmopen3 \
tst-dlmopen4 \
+ tst-dlmopen4-nonpic \
+ tst-dlmopen4-pic \
+ tst-dlopen-auditdup \
+ tst-dlopen-constructor-null \
tst-dlopen-self \
tst-dlopen-tlsmodid \
+ tst-dlopen-tlsreinit1 \
+ tst-dlopen-tlsreinit2 \
+ tst-dlopen-tlsreinit3 \
+ tst-dlopen-tlsreinit4 \
tst-dlopenfail \
tst-dlopenfail-2 \
tst-dlopenrpath \
@@ -448,6 +459,9 @@ tests += \
tst-recursive-tls \
tst-relsort1 \
tst-ro-dynamic \
+ tst-rtld-no-malloc \
+ tst-rtld-no-malloc-audit \
+ tst-rtld-no-malloc-preload \
tst-rtld-run-static \
tst-single_threaded \
tst-single_threaded-pthread \
@@ -472,6 +486,7 @@ tests += \
tst-tls19 \
tst-tls20 \
tst-tls21 \
+ tst-tls23 \
tst-tlsalign \
tst-tlsalign-extern \
tst-tlsgap \
@@ -479,6 +494,7 @@ tests += \
tst-unique2 \
tst-unwind-ctor \
tst-unwind-main \
+ tst-version-hash-zero \
unload3 \
unload4 \
unload5 \
@@ -509,6 +525,8 @@ tests-internal += \
tst-dl_find_object \
tst-dl_find_object-threads \
tst-dlmopen2 \
+ tst-link-map-contiguous-ldso \
+ tst-link-map-contiguous-libc \
tst-ptrguard1 \
tst-stackguard1 \
tst-tls-surplus \
@@ -520,6 +538,10 @@ tests-internal += \
unload2 \
# tests-internal
+ifeq ($(build-hardcoded-path-in-tests),yes)
+tests-internal += tst-link-map-contiguous-main
+endif
+
tests-container += \
tst-dlopen-self-container \
tst-dlopen-tlsmodid-container \
@@ -813,6 +835,7 @@ modules-names += \
tst-auditmanymod8 \
tst-auditmanymod9 \
tst-auditmod-tlsdesc \
+ tst-auditmod-tlsdesc2 \
tst-auditmod1 \
tst-auditmod11 \
tst-auditmod12 \
@@ -853,6 +876,14 @@ modules-names += \
tst-dlmopen-twice-mod1 \
tst-dlmopen-twice-mod2 \
tst-dlmopen1mod \
+ tst-dlopen-auditdup-auditmod \
+ tst-dlopen-auditdupmod \
+ tst-dlopen-constructor-null-mod1 \
+ tst-dlopen-constructor-null-mod2 \
+ tst-dlopen-sgid-mod \
+ tst-dlopen-tlsreinitmod1 \
+ tst-dlopen-tlsreinitmod2 \
+ tst-dlopen-tlsreinitmod3 \
tst-dlopenfaillinkmod \
tst-dlopenfailmod1 \
tst-dlopenfailmod2 \
@@ -934,6 +965,7 @@ modules-names += \
tst-tls19mod3 \
tst-tls20mod-bad \
tst-tls21mod \
+ tst-tls23-mod \
tst-tlsalign-lib \
tst-tlsgap-mod0 \
tst-tlsgap-mod1 \
@@ -964,6 +996,9 @@ modules-names += \
tst-unique2mod1 \
tst-unique2mod2 \
tst-unwind-ctor-lib \
+ tst-version-hash-zero-linkmod \
+ tst-version-hash-zero-mod \
+ tst-version-hash-zero-refmod \
unload2dep \
unload2mod \
unload3mod1 \
@@ -2050,6 +2085,13 @@ $(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
$(objpfx)tst-dlmopen4.out: $(objpfx)tst-dlmopen1mod.so
+CFLAGS-tst-dlmopen4-pic.c += -fPIC
+$(objpfx)tst-dlmopen4-pic.out: $(objpfx)tst-dlmopen1mod.so
+
+CFLAGS-tst-dlmopen4-nonpic.c += -fno-pie
+tst-dlmopen4-nonpic-no-pie = yes
+$(objpfx)tst-dlmopen4-nonpic.out: $(objpfx)tst-dlmopen1mod.so
+
$(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
@@ -3033,6 +3075,9 @@ $(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
+$(objpfx)tst-audit-tlsdesc-dlopen2.out: $(objpfx)tst-auditmod-tlsdesc2.so \
+ $(patsubst %, $(objpfx)%.so, $(tlsmod17a-modules))
+tst-audit-tlsdesc-dlopen2-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc2.so
$(objpfx)tst-dlmopen-twice.out: \
$(objpfx)tst-dlmopen-twice-mod1.so \
@@ -3118,3 +3163,85 @@ $(objpfx)tst-recursive-tls.out: \
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
$(objpfx)tst-recursive-tlsmod%.os: tst-recursive-tlsmodN.c
$(compile-command.c) -DVAR=thread_$* -DFUNC=get_threadvar_$*
+
+# Order matters here. The test needs the constructor for
+# tst-dlopen-tlsreinitmod2.so to be called first.
+LDFLAGS-tst-dlopen-tlsreinitmod1.so = -Wl,--no-as-needed
+$(objpfx)tst-dlopen-tlsreinitmod1.so: \
+ $(objpfx)tst-dlopen-tlsreinitmod3.so $(objpfx)tst-dlopen-tlsreinitmod2.so
+LDFLAGS-tst-dlopen-tlsreinit2 = -Wl,--no-as-needed
+$(objpfx)tst-dlopen-tlsreinit2: \
+ $(objpfx)tst-dlopen-tlsreinitmod3.so $(objpfx)tst-dlopen-tlsreinitmod2.so
+LDFLAGS-tst-dlopen-tlsreinit4 = -Wl,--no-as-needed
+$(objpfx)tst-dlopen-tlsreinit4: \
+ $(objpfx)tst-dlopen-tlsreinitmod3.so $(objpfx)tst-dlopen-tlsreinitmod2.so
+# tst-dlopen-tlsreinitmod2.so is underlinked and refers to
+# tst-dlopen-tlsreinitmod3.so. The dependency is provided via
+# $(objpfx)tst-dlopen-tlsreinitmod1.so.
+tst-dlopen-tlsreinitmod2.so-no-z-defs = yes
+$(objpfx)tst-dlopen-tlsreinit1.out: $(objpfx)tst-dlopen-tlsreinitmod1.so \
+ $(objpfx)tst-dlopen-tlsreinitmod2.so $(objpfx)tst-dlopen-tlsreinitmod3.so
+# Reuse an audit module which provides ample debug logging.
+$(objpfx)tst-dlopen-tlsreinit3.out: $(objpfx)tst-auditmod1.so
+tst-dlopen-tlsreinit3-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+$(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so
+tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+
+$(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
+
+tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so
+$(objpfx)tst-dlopen-auditdup.out: \
+ $(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so
+
+# Reuse an audit module which provides ample debug logging.
+tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+
+# Any shared object should do.
+tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
+
+$(objpfx)tst-tls23: $(shared-thread-library)
+$(objpfx)tst-tls23.out: $(objpfx)tst-tls23-mod.so
+
+ifneq (no,$(have-test-mtls-traditional))
+CFLAGS-tst-tls23-mod.c += -mtls-dialect=$(have-test-mtls-traditional)
+endif
+
+$(objpfx)tst-version-hash-zero.out: \
+ $(objpfx)tst-version-hash-zero-mod.so \
+ $(objpfx)tst-version-hash-zero-refmod.so
+LDFLAGS-tst-version-hash-zero-mod.so = \
+ -Wl,--version-script=tst-version-hash-zero-mod.map
+# The run-time test module tst-version-hash-zero-refmod.so is linked
+# to a stub module, tst-version-hash-zero-linkmod.so, to produce an
+# expected relocation error.
+$(objpfx)tst-version-hash-zero-refmod.so: \
+ $(objpfx)tst-version-hash-zero-linkmod.so
+LDFLAGS-tst-version-hash-zero-linkmod.so = \
+ -Wl,--version-script=tst-version-hash-zero-linkmod.map \
+ -Wl,--soname=tst-version-hash-zero-mod.so
+$(objpfx)tst-version-hash-zero-refmod.so: \
+ $(objpfx)tst-version-hash-zero-linkmod.so
+tst-version-hash-zero-refmod.so-no-z-defs = yes
+
+# These rules link and run the special elf/tst-nolink-libc-* tests if
+# a port adds them to the tests variables. Neither test variant is
+# linked against libc.so, but tst-nolink-libc-1 is linked against
+# ld.so. The test is always run directly, not under the dynamic
+# linker.
+CFLAGS-tst-nolink-libc.c += $(no-stack-protector)
+$(objpfx)tst-nolink-libc-1: $(objpfx)tst-nolink-libc.o $(objpfx)ld.so
+ $(LINK.o) -nostdlib -nostartfiles -o $@ $< \
+ -Wl,--dynamic-linker=$(objpfx)ld.so,--no-as-needed $(objpfx)ld.so
+$(objpfx)tst-nolink-libc-1.out: $(objpfx)tst-nolink-libc-1 $(objpfx)ld.so
+ $< > $@ 2>&1; $(evaluate-test)
+$(objpfx)tst-nolink-libc-2: $(objpfx)tst-nolink-libc.o
+ $(LINK.o) -nostdlib -nostartfiles -o $@ $< \
+ -Wl,--dynamic-linker=$(objpfx)ld.so
+$(objpfx)tst-nolink-libc-2.out: $(objpfx)tst-nolink-libc-2 $(objpfx)ld.so
+ $< > $@ 2>&1; $(evaluate-test)
+
+$(objpfx)tst-dlopen-constructor-null: \
+ $(objpfx)tst-dlopen-constructor-null-mod1.so \
+ $(objpfx)tst-dlopen-constructor-null-mod2.so
+$(objpfx)tst-dlopen-constructor-null-mod2.so: \
+ $(objpfx)tst-dlopen-constructor-null-mod1.so
diff --git a/elf/cache.c b/elf/cache.c
index 8a618e11fa..62d681df42 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -820,7 +820,7 @@ struct aux_cache_entry
struct aux_cache_entry *next;
};
-#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
+#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-2.0"
struct aux_cache_file_entry
{
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 88226245eb..fb27a1231c 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -264,6 +264,12 @@ _dl_close_worker (struct link_map *map, bool force)
_dl_catch_exception (NULL, _dl_call_fini, imap);
#ifdef SHARED
+ /* Auditing checkpoint: we will start deleting objects.
+ This is supposed to happen before la_objclose (see _dl_fini),
+ but only once per non-recursive dlclose call. */
+ if (!unload_any)
+ _dl_audit_activity_nsid (nsid, LA_ACT_DELETE);
+
/* Auditing checkpoint: we remove an object. */
_dl_audit_objclose (imap);
#endif
@@ -424,15 +430,10 @@ _dl_close_worker (struct link_map *map, bool force)
if (!unload_any)
goto out;
-#ifdef SHARED
- /* Auditing checkpoint: we will start deleting objects. */
- _dl_audit_activity_nsid (nsid, LA_ACT_DELETE);
-#endif
-
- /* Notify the debugger we are about to remove some loaded objects. */
+ /* Notify the debugger we are about to remove some loaded objects.
+ LA_ACT_DELETE has already been signalled above for !unload_any. */
struct r_debug *r = _dl_debug_update (nsid);
- r->r_state = RT_DELETE;
- _dl_debug_state ();
+ _dl_debug_change_state (r, RT_DELETE);
LIBC_PROBE (unmap_start, 2, nsid, r);
if (unload_global)
@@ -723,6 +724,10 @@ _dl_close_worker (struct link_map *map, bool force)
/* TLS is cleaned up for the unloaded modules. */
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+ /* Notify the debugger those objects are finalized and gone. */
+ _dl_debug_change_state (r, RT_CONSISTENT);
+ LIBC_PROBE (unmap_complete, 2, nsid, r);
+
#ifdef SHARED
/* Auditing checkpoint: we have deleted all objects. Also, do not notify
auditors of the cleanup of a failed audit module loading attempt. */
@@ -735,11 +740,6 @@ _dl_close_worker (struct link_map *map, bool force)
--GL(dl_nns);
while (GL(dl_ns)[GL(dl_nns) - 1]._ns_loaded == NULL);
- /* Notify the debugger those objects are finalized and gone. */
- r->r_state = RT_CONSISTENT;
- _dl_debug_state ();
- LIBC_PROBE (unmap_complete, 2, nsid, r);
-
/* Recheck if we need to retry, release the lock. */
out:
if (dl_close_state == rerun)
diff --git a/elf/dl-debug-symbols.S b/elf/dl-debug-symbols.S
index 4e35adef5d..33f0fc77de 100644
--- a/elf/dl-debug-symbols.S
+++ b/elf/dl-debug-symbols.S
@@ -38,3 +38,4 @@
_r_debug:
_r_debug_extended:
.zero R_DEBUG_EXTENDED_SIZE
+rtld_hidden_def (_r_debug)
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
index ef56de7a29..df36d61dcb 100644
--- a/elf/dl-debug.c
+++ b/elf/dl-debug.c
@@ -16,6 +16,7 @@
License along with the GNU C Library; if not, see
. */
+#include
#include
@@ -30,23 +31,86 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
&& VERIFY_MEMBER (l_prev))
? 1 : -1];
+#ifdef SHARED
+/* r_debug structs for secondary namespaces. The first namespace is
+ handled separately because its r_debug structure must overlap with
+ the public _r_debug symbol, so the first array element corresponds
+ to LM_ID_BASE + 1. See elf/dl-debug-symbols.S. */
+struct r_debug_extended _r_debug_array[DL_NNS - 1];
+
+/* If not null, pointer to the _r_debug in the main executable. */
+static struct r_debug *_r_debug_main;
+
+void
+_dl_debug_post_relocate (struct link_map *main_map)
+{
+ /* Perform a full symbol search in all objects, to maintain
+ compatibility if interposed _r_debug definitions. The lookup
+ cannot fail because there is a definition in ld.so, and this
+ function is only called if the ld.so search scope is not empty. */
+ const ElfW(Sym) *sym = NULL;
+ lookup_t result =_dl_lookup_symbol_x ("_r_debug", main_map, &sym,
+ main_map->l_scope, NULL, 0, 0, NULL);
+ if (sym->st_size >= sizeof (struct r_debug))
+ {
+ struct r_debug *main_r_debug = DL_SYMBOL_ADDRESS (result, sym);
+ if (main_r_debug != &_r_debug_extended.base)
+ {
+ /* The extended version of the struct is not available in
+ the main executable because a copy relocation has been
+ used. r_map etc. have already been copied as part of the
+ copy relocation processing. */
+ main_r_debug->r_version = 1;
+
+ /* Record that dual updates of the initial link map are
+ required. */
+ _r_debug_main = main_r_debug;
+ }
+ }
+}
+
+/* Return the r_debug object for the namespace NS. */
+static inline struct r_debug_extended *
+get_rdebug (Lmid_t ns)
+{
+ if (ns == LM_ID_BASE)
+ return &_r_debug_extended;
+ else
+ return &_r_debug_array[ns - 1];
+}
+#else /* !SHARED */
+static inline struct r_debug_extended *
+get_rdebug (Lmid_t ns)
+{
+ return &_r_debug_extended; /* There is just one namespace. */
+}
+#endif /* !SHARED */
+
/* Update the `r_map' member and return the address of `struct r_debug'
of the namespace NS. */
struct r_debug *
_dl_debug_update (Lmid_t ns)
{
- struct r_debug_extended *r;
- if (ns == LM_ID_BASE)
- r = &_r_debug_extended;
- else
- r = &GL(dl_ns)[ns]._ns_debug;
+ struct r_debug_extended *r = get_rdebug (ns);
if (r->base.r_map == NULL)
atomic_store_release (&r->base.r_map,
(void *) GL(dl_ns)[ns]._ns_loaded);
return &r->base;
}
+void
+_dl_debug_change_state (struct r_debug *r, int state)
+{
+ atomic_store_release (&r->r_state, state);
+#ifdef SHARED
+ if (r == &_r_debug_extended.base && _r_debug_main != NULL)
+ /* Update the copy-relocation of _r_debug. */
+ atomic_store_release (&_r_debug_main->r_state, state);
+#endif
+ _dl_debug_state ();
+}
+
/* Initialize _r_debug_extended for the namespace NS. LDBASE is the
run-time load address of the dynamic linker, to be put in
_r_debug_extended.r_ldbase. Return the address of _r_debug. */
@@ -54,34 +118,7 @@ _dl_debug_update (Lmid_t ns)
struct r_debug *
_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
{
- struct r_debug_extended *r, **pp = NULL;
-
- if (ns == LM_ID_BASE)
- {
- r = &_r_debug_extended;
- /* Initialize r_version to 1. */
- if (_r_debug_extended.base.r_version == 0)
- _r_debug_extended.base.r_version = 1;
- }
- else if (DL_NNS > 1)
- {
- r = &GL(dl_ns)[ns]._ns_debug;
- if (r->base.r_brk == 0)
- {
- /* Add the new namespace to the linked list. After a namespace
- is initialized, r_brk becomes non-zero. A namespace becomes
- empty (r_map == NULL) when it is unused. But it is never
- removed from the linked list. */
- struct r_debug_extended *p;
- for (pp = &_r_debug_extended.r_next;
- (p = *pp) != NULL;
- pp = &p->r_next)
- ;
-
- r->base.r_version = 2;
- }
- }
-
+ struct r_debug_extended *r = get_rdebug (ns);
if (r->base.r_brk == 0)
{
/* Tell the debugger where to find the map of loaded objects.
@@ -89,30 +126,44 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
only once. */
r->base.r_ldbase = ldbase ?: _r_debug_extended.base.r_ldbase;
r->base.r_brk = (ElfW(Addr)) &_dl_debug_state;
- r->r_next = NULL;
+
+#ifdef SHARED
+ /* Add the new namespace to the linked list. This assumes that
+ namespaces are allocated in increasing order. After a
+ namespace is initialized, r_brk becomes non-zero. A
+ namespace becomes empty (r_map == NULL) when it is unused.
+ But it is never removed from the linked list. */
+
+ if (ns != LM_ID_BASE)
+ {
+ r->base.r_version = 2;
+ if (ns - 1 == LM_ID_BASE)
+ {
+ atomic_store_release (&_r_debug_extended.r_next, r);
+ /* Now there are multiple namespaces. Note that this
+ deliberately does not update the copy in the main
+ executable (if it exists). */
+ atomic_store_release (&_r_debug_extended.base.r_version, 2);
+ }
+ else
+ /* Update r_debug_extended of the previous namespace. */
+ atomic_store_release (&_r_debug_array[ns - 2].r_next, r);
+ }
+ else
+#endif /* SHARED */
+ r->base.r_version = 1;
}
if (r->base.r_map == NULL)
- atomic_store_release (&r->base.r_map,
- (void *) GL(dl_ns)[ns]._ns_loaded);
-
- if (pp != NULL)
{
- atomic_store_release (pp, r);
- /* Bump r_version to 2 for the new namespace. */
- atomic_store_release (&_r_debug_extended.base.r_version, 2);
+ struct link_map_public *l = (void *) GL(dl_ns)[ns]._ns_loaded;
+ atomic_store_release (&r->base.r_map, l);
+#ifdef SHARED
+ if (ns == LM_ID_BASE && _r_debug_main != NULL)
+ /* Update the copy-relocation of _r_debug. */
+ atomic_store_release (&_r_debug_main->r_map, l);
+#endif
}
return &r->base;
}
-
-
-/* This function exists solely to have a breakpoint set on it by the
- debugger. The debugger is supposed to find this function's address by
- examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks
- for this particular symbol name in the PT_INTERP file. */
-void
-_dl_debug_state (void)
-{
-}
-rtld_hidden_def (_dl_debug_state)
diff --git a/elf/dl-debug_state.c b/elf/dl-debug_state.c
new file mode 100644
index 0000000000..40c134a49e
--- /dev/null
+++ b/elf/dl-debug_state.c
@@ -0,0 +1,30 @@
+/* Debugger hook called after dynamic linker updates.
+ Copyright (C) 1996-2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+
+/* This function exists solely to have a breakpoint set on it by the
+ debugger. The debugger is supposed to find this function's address by
+ examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks
+ for this particular symbol name in the PT_INTERP file. Therefore,
+ this function must not be inlined. */
+void
+_dl_debug_state (void)
+{
+}
+rtld_hidden_def (_dl_debug_state)
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
index 449302eda3..f258665a71 100644
--- a/elf/dl-find_object.c
+++ b/elf/dl-find_object.c
@@ -356,7 +356,7 @@ _dlfo_lookup (uintptr_t pc, struct dl_find_object_internal *first1, size_t size)
}
int
-__dl_find_object (void *pc1, struct dl_find_object *result)
+_dl_find_object (void *pc1, struct dl_find_object *result)
{
uintptr_t pc = (uintptr_t) pc1;
@@ -463,8 +463,38 @@ __dl_find_object (void *pc1, struct dl_find_object *result)
return -1;
} /* Transaction retry loop. */
}
-hidden_def (__dl_find_object)
-weak_alias (__dl_find_object, _dl_find_object)
+rtld_hidden_def (_dl_find_object)
+
+/* Subroutine of _dlfo_process_initial to split out noncontigous link
+ maps. NODELETE is the number of used _dlfo_nodelete_mappings
+ elements. It is incremented as needed, and the new NODELETE value
+ is returned. */
+static size_t
+_dlfo_process_initial_noncontiguous_map (struct link_map *map,
+ size_t nodelete)
+{
+ struct dl_find_object_internal dlfo;
+ _dl_find_object_from_map (map, &dlfo);
+
+ /* PT_LOAD segments for a non-contiguous link map are added to the
+ non-closeable mappings. */
+ const ElfW(Phdr) *ph = map->l_phdr;
+ const ElfW(Phdr) *ph_end = map->l_phdr + map->l_phnum;
+ for (; ph < ph_end; ++ph)
+ if (ph->p_type == PT_LOAD)
+ {
+ if (_dlfo_nodelete_mappings != NULL)
+ {
+ /* Second pass only. */
+ _dlfo_nodelete_mappings[nodelete] = dlfo;
+ ElfW(Addr) start = ph->p_vaddr + map->l_addr;
+ _dlfo_nodelete_mappings[nodelete].map_start = start;
+ _dlfo_nodelete_mappings[nodelete].map_end = start + ph->p_memsz;
+ }
+ ++nodelete;
+ }
+ return nodelete;
+}
/* _dlfo_process_initial is called twice. First to compute the array
sizes from the initial loaded mappings. Second to fill in the
@@ -477,29 +507,8 @@ _dlfo_process_initial (void)
size_t nodelete = 0;
if (!main_map->l_contiguous)
- {
- struct dl_find_object_internal dlfo;
- _dl_find_object_from_map (main_map, &dlfo);
-
- /* PT_LOAD segments for a non-contiguous are added to the
- non-closeable mappings. */
- for (const ElfW(Phdr) *ph = main_map->l_phdr,
- *ph_end = main_map->l_phdr + main_map->l_phnum;
- ph < ph_end; ++ph)
- if (ph->p_type == PT_LOAD)
- {
- if (_dlfo_nodelete_mappings != NULL)
- {
- /* Second pass only. */
- _dlfo_nodelete_mappings[nodelete] = dlfo;
- _dlfo_nodelete_mappings[nodelete].map_start
- = ph->p_vaddr + main_map->l_addr;
- _dlfo_nodelete_mappings[nodelete].map_end
- = _dlfo_nodelete_mappings[nodelete].map_start + ph->p_memsz;
- }
- ++nodelete;
- }
- }
+ /* Contiguous case already handled in _dl_find_object_init. */
+ nodelete = _dlfo_process_initial_noncontiguous_map (main_map, nodelete);
size_t loaded = 0;
for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
@@ -511,11 +520,22 @@ _dlfo_process_initial (void)
/* lt_library link maps are implicitly NODELETE. */
if (l->l_type == lt_library || l->l_nodelete_active)
{
- if (_dlfo_nodelete_mappings != NULL)
- /* Second pass only. */
- _dl_find_object_from_map
- (l, _dlfo_nodelete_mappings + nodelete);
- ++nodelete;
+ /* The kernel may have loaded ld.so with gaps. */
+ if (!l->l_contiguous
+#ifdef SHARED
+ && l == &GL(dl_rtld_map)
+#endif
+ )
+ nodelete
+ = _dlfo_process_initial_noncontiguous_map (l, nodelete);
+ else
+ {
+ if (_dlfo_nodelete_mappings != NULL)
+ /* Second pass only. */
+ _dl_find_object_from_map
+ (l, _dlfo_nodelete_mappings + nodelete);
+ ++nodelete;
+ }
}
else if (l->l_type == lt_loaded)
{
@@ -662,6 +682,14 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count)
= _dlfo_loaded_mappings[!active_idx];
size_t remaining_to_add = current_used + count;
+ /* remaining_to_add can be 0 if (current_used + count) wraps, but in practice
+ this is not possible as it represent counts of link maps. Link maps have
+ sizes larger than 1 byte, so the sum of any two link map counts will
+ always fit within a size_t without wrapping around. This check ensures
+ that target_seg is not erroneously considered potentially NULL by GCC. */
+ if (remaining_to_add == 0)
+ __builtin_unreachable ();
+
/* Ensure that the new segment chain has enough space. */
{
size_t new_allocated
@@ -757,7 +785,6 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count)
/* Prefer newly loaded link map. */
assert (loaded_index1 > 0);
_dl_find_object_from_map (loaded[loaded_index1 - 1], dlfo);
- loaded[loaded_index1 - 1]->l_find_object_processed = 1;
--loaded_index1;
}
diff --git a/elf/dl-find_object.h b/elf/dl-find_object.h
index 0915065be0..8894c6657c 100644
--- a/elf/dl-find_object.h
+++ b/elf/dl-find_object.h
@@ -87,7 +87,7 @@ _dl_find_object_to_external (struct dl_find_object_internal *internal,
}
/* Extract the object location data from a link map and writes it to
- *RESULT using relaxed MO stores. */
+ *RESULT using relaxed MO stores. Set L->l_find_object_processed. */
static void __attribute__ ((unused))
_dl_find_object_from_map (struct link_map *l,
struct dl_find_object_internal *result)
@@ -100,6 +100,8 @@ _dl_find_object_from_map (struct link_map *l,
atomic_store_relaxed (&result->eh_dbase, (void *) l->l_info[DT_PLTGOT]);
#endif
+ l->l_find_object_processed = 1;
+
for (const ElfW(Phdr) *ph = l->l_phdr, *ph_end = l->l_phdr + l->l_phnum;
ph < ph_end; ++ph)
if (ph->p_type == DLFO_EH_SEGMENT_TYPE)
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index db996270de..a1a4c25829 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -69,6 +69,7 @@ _dl_fini (void)
unsigned int i;
struct link_map *l;
+ struct link_map *proxy_link_map = NULL;
assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
/* Do not handle ld.so in secondary namespaces. */
@@ -84,6 +85,11 @@ _dl_fini (void)
are not dlclose()ed from underneath us. */
++l->l_direct_opencount;
}
+ else
+ /* Used below to call la_objclose for the ld.so proxy
+ link map. */
+ proxy_link_map = l;
+
assert (ns != LM_ID_BASE || i == nloaded);
assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
unsigned int nmaps = i;
@@ -122,6 +128,9 @@ _dl_fini (void)
--l->l_direct_opencount;
}
+ if (proxy_link_map != NULL)
+ _dl_audit_objclose (proxy_link_map);
+
#ifdef SHARED
_dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT);
#endif
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 8a89b71016..23b7e6a0c6 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -918,6 +918,36 @@ _dl_process_pt_gnu_property (struct link_map *l, int fd, const ElfW(Phdr) *ph)
}
}
+static void
+_dl_notify_new_object (int mode, Lmid_t nsid, struct link_map *l)
+{
+ /* Signal that we are going to add new objects. */
+ struct r_debug *r = _dl_debug_update (nsid);
+ if (r->r_state == RT_CONSISTENT)
+ {
+#ifdef SHARED
+ /* Auditing checkpoint: we are going to add new objects. Since this
+ is called after _dl_add_to_namespace_list the namespace is guaranteed
+ to not be empty. */
+ if ((mode & __RTLD_AUDIT) == 0)
+ _dl_audit_activity_nsid (nsid, LA_ACT_ADD);
+#endif
+
+ /* Notify the debugger we have added some objects. We need to
+ call _dl_debug_initialize in a static program in case dynamic
+ linking has not been used before. */
+ _dl_debug_change_state (r, RT_ADD);
+ LIBC_PROBE (map_start, 2, nsid, r);
+ }
+ else
+ assert (r->r_state == RT_ADD);
+
+#ifdef SHARED
+ /* Auditing checkpoint: we have a new object. */
+ if (!GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
+ _dl_audit_objopen (l, nsid);
+#endif
+}
/* Map in the shared object NAME, actually located in REALNAME, and already
opened on FD. */
@@ -1018,6 +1048,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
/* Add the map for the mirrored object to the object list. */
_dl_add_to_namespace_list (l, nsid);
+ _dl_notify_new_object (mode, nsid, l);
+
return l;
}
#endif
@@ -1442,33 +1474,7 @@ cannot enable executable stack as shared object requires");
if (mode & __RTLD_SPROF)
return l;
- /* Signal that we are going to add new objects. */
- struct r_debug *r = _dl_debug_update (nsid);
- if (r->r_state == RT_CONSISTENT)
- {
-#ifdef SHARED
- /* Auditing checkpoint: we are going to add new objects. Since this
- is called after _dl_add_to_namespace_list the namespace is guaranteed
- to not be empty. */
- if ((mode & __RTLD_AUDIT) == 0)
- _dl_audit_activity_nsid (nsid, LA_ACT_ADD);
-#endif
-
- /* Notify the debugger we have added some objects. We need to
- call _dl_debug_initialize in a static program in case dynamic
- linking has not been used before. */
- r->r_state = RT_ADD;
- _dl_debug_state ();
- LIBC_PROBE (map_start, 2, nsid, r);
- }
- else
- assert (r->r_state == RT_ADD);
-
-#ifdef SHARED
- /* Auditing checkpoint: we have a new object. */
- if (!GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
- _dl_audit_objopen (l, nsid);
-#endif
+ _dl_notify_new_object (mode, nsid, l);
return l;
}
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 19ad2a25c5..7a70f1df2d 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -113,12 +113,22 @@ check_match (const char *const undef_name,
/* We can match the version information or use the
default one if it is not hidden. */
ElfW(Half) ndx = verstab[symidx] & 0x7fff;
- if ((map->l_versions[ndx].hash != version->hash
- || strcmp (map->l_versions[ndx].name, version->name))
- && (version->hidden || map->l_versions[ndx].hash
- || (verstab[symidx] & 0x8000)))
- /* It's not the version we want. */
- return NULL;
+ if (map->l_versions[ndx].hash == version->hash
+ && strcmp (map->l_versions[ndx].name, version->name) == 0)
+ /* This is an exact version match. Return the symbol below. */
+ ;
+ else
+ {
+ if (!version->hidden
+ && map->l_versions[ndx].name[0] == '\0'
+ && (verstab[symidx] & 0x8000) == 0
+ && (*num_versions)++ == 0)
+ /* This is the global default version. Store it as a
+ fallback match. */
+ *versioned_sym = sym;
+
+ return NULL;
+ }
}
}
else
diff --git a/elf/dl-open.c b/elf/dl-open.c
index c378da16c0..6f6d3ddbf9 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -363,17 +363,8 @@ resize_tls_slotinfo (struct link_map *new)
{
bool any_tls = false;
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
- {
- struct link_map *imap = new->l_searchlist.r_list[i];
-
- /* Only add TLS memory if this object is loaded now and
- therefore is not yet initialized. */
- if (! imap->l_init_called && imap->l_tls_blocksize > 0)
- {
- _dl_add_to_slotinfo (imap, false);
- any_tls = true;
- }
- }
+ if (_dl_add_to_slotinfo (new->l_searchlist.r_list[i], false))
+ any_tls = true;
return any_tls;
}
@@ -383,22 +374,8 @@ resize_tls_slotinfo (struct link_map *new)
static void
update_tls_slotinfo (struct link_map *new)
{
- unsigned int first_static_tls = new->l_searchlist.r_nlist;
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
- {
- struct link_map *imap = new->l_searchlist.r_list[i];
-
- /* Only add TLS memory if this object is loaded now and
- therefore is not yet initialized. */
- if (! imap->l_init_called && imap->l_tls_blocksize > 0)
- {
- _dl_add_to_slotinfo (imap, true);
-
- if (imap->l_need_tls_init
- && first_static_tls == new->l_searchlist.r_nlist)
- first_static_tls = i;
- }
- }
+ _dl_add_to_slotinfo (new->l_searchlist.r_list[i], true);
size_t newgen = GL(dl_tls_generation) + 1;
if (__glibc_unlikely (newgen == 0))
@@ -410,13 +387,11 @@ TLS generation counter wrapped! Please report this."));
/* We need a second pass for static tls data, because
_dl_update_slotinfo must not be run while calls to
_dl_add_to_slotinfo are still pending. */
- for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i)
+ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
{
struct link_map *imap = new->l_searchlist.r_list[i];
- if (imap->l_need_tls_init
- && ! imap->l_init_called
- && imap->l_tls_blocksize > 0)
+ if (imap->l_need_tls_init && imap->l_tls_blocksize > 0)
{
/* For static TLS we have to allocate the memory here and
now, but we can delay updating the DTV. */
@@ -601,6 +576,14 @@ dl_open_worker_begin (void *a)
_dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
new->l_name, new->l_ns, new->l_direct_opencount);
+#ifdef SHARED
+ /* No relocation processing on this execution path. But
+ relocation has not been performed for static
+ position-dependent executables, so disable the assert for
+ static linking. */
+ assert (new->l_relocated);
+#endif
+
/* If the user requested the object to be in the global
namespace but it is not so far, prepare to add it now. This
can raise an exception to do a malloc failure. */
@@ -622,9 +605,15 @@ dl_open_worker_begin (void *a)
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
add_to_global_update (new);
- const int r_state __attribute__ ((unused))
- = _dl_debug_update (args->nsid)->r_state;
- assert (r_state == RT_CONSISTENT);
+ /* It is not possible to run the ELF constructor for the new
+ link map if it has not executed yet: If this dlopen call came
+ from an ELF constructor that has not put that object into a
+ consistent state, completing initialization for the entire
+ scope will expose objects that have this partially
+ constructed object among its dependencies to this
+ inconsistent state. This could happen even with a benign
+ dlopen (NULL, RTLD_LAZY) call from a constructor of an
+ initially loaded shared object. */
return;
}
@@ -656,17 +645,6 @@ dl_open_worker_begin (void *a)
#endif
}
-#ifdef SHARED
- /* Auditing checkpoint: we have added all objects. */
- _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT);
-#endif
-
- /* Notify the debugger all new objects are now ready to go. */
- struct r_debug *r = _dl_debug_update (args->nsid);
- r->r_state = RT_CONSISTENT;
- _dl_debug_state ();
- LIBC_PROBE (map_complete, 3, args->nsid, r, new);
-
_dl_open_check (new);
/* Print scope information. */
@@ -713,6 +691,7 @@ dl_open_worker_begin (void *a)
created dlmopen namespaces. Do not do this for static dlopen
because libc has relocations against ld.so, which may not have
been relocated at this point. */
+ struct r_debug *r = _dl_debug_update (args->nsid);
#ifdef SHARED
if (GL(dl_ns)[args->nsid].libc_map != NULL)
_dl_open_relocate_one_object (args, r, GL(dl_ns)[args->nsid].libc_map,
@@ -804,6 +783,25 @@ dl_open_worker (void *a)
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+ /* Auditing checkpoint and debugger signalling. Do this even on
+ error, so that dlopen exists with consistent state. */
+ if (args->nsid >= 0 || args->map != NULL)
+ {
+ Lmid_t nsid = args->map != NULL ? args->map->l_ns : args->nsid;
+ struct r_debug *r = _dl_debug_update (nsid);
+#ifdef SHARED
+ bool was_not_consistent = r->r_state != RT_CONSISTENT;
+#endif
+ _dl_debug_change_state (r, RT_CONSISTENT);
+ LIBC_PROBE (map_complete, 3, nsid, r, args->map);
+
+#ifdef SHARED
+ if (was_not_consistent)
+ /* Avoid redudant/recursive signalling. */
+ _dl_audit_activity_nsid (nsid, LA_ACT_CONSISTENT);
+#endif
+ }
+
if (__glibc_unlikely (ex.errstring != NULL))
/* Reraise the error. */
_dl_signal_exception (err, &ex, NULL);
@@ -872,7 +870,7 @@ no more namespaces available for dlmopen()"));
}
GL(dl_ns)[nsid].libc_map = NULL;
- _dl_debug_update (nsid)->r_state = RT_CONSISTENT;
+ _dl_debug_change_state (_dl_debug_update (nsid), RT_CONSISTENT);
}
/* Never allow loading a DSO in a namespace which is empty. Such
direct placements is only causing problems. Also don't allow
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 4bf7aec88b..76d14830dd 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -202,12 +202,9 @@ resolve_map (lookup_t l, struct r_scope_elem *scope[], const ElfW(Sym) **ref,
#include "dynamic-link.h"
void
-_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
- int reloc_mode, int consider_profiling)
+_dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
+ int reloc_mode, int consider_profiling)
{
- if (l->l_relocated)
- return;
-
struct textrels
{
caddr_t start;
@@ -220,8 +217,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
int lazy = reloc_mode & RTLD_LAZY;
int skip_ifunc = reloc_mode & __RTLD_NOIFUNC;
-#ifdef SHARED
bool consider_symbind = false;
+#ifdef SHARED
/* If we are auditing, install the same handlers we need for profiling. */
if ((reloc_mode & __RTLD_AUDIT) == 0)
{
@@ -240,9 +237,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
}
#elif defined PROF
/* Never use dynamic linker profiling for gprof profiling code. */
-# define consider_profiling 0
-#else
-# define consider_symbind 0
+ consider_profiling = 0;
#endif
/* If DT_BIND_NOW is set relocate all references in this object. We
@@ -300,7 +295,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
ELF_DYNAMIC_RELOCATE (l, scope, lazy, consider_profiling, skip_ifunc);
-#ifndef PROF
if ((consider_profiling || consider_symbind)
&& l->l_info[DT_PLTRELSZ] != NULL)
{
@@ -321,7 +315,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
_dl_fatal_printf (errstring, RTLD_PROGNAME, l->l_name);
}
}
-#endif
}
/* Mark the object so we know this work has been done. */
@@ -342,17 +335,24 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
textrels = textrels->next;
}
-
- /* In case we can protect the data now that the relocations are
- done, do it. */
- if (l->l_relro_size != 0)
- _dl_protect_relro (l);
}
+void
+_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+ int reloc_mode, int consider_profiling)
+{
+ if (l->l_relocated)
+ return;
+ _dl_relocate_object_no_relro (l, scope, reloc_mode, consider_profiling);
+ _dl_protect_relro (l);
+}
void
_dl_protect_relro (struct link_map *l)
{
+ if (l->l_relro_size == 0)
+ return;
+
ElfW(Addr) start = ALIGN_DOWN((l->l_addr
+ l->l_relro_addr),
GLRO(dl_pagesize));
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 451932dd03..ee590edf93 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -338,8 +338,7 @@ _dl_non_dynamic_init (void)
call_function_static_weak (_dl_find_object_init);
/* Setup relro on the binary itself. */
- if (_dl_main_map.l_relro_size != 0)
- _dl_protect_relro (&_dl_main_map);
+ _dl_protect_relro (&_dl_main_map);
}
#ifdef DL_SYSINFO_IMPLEMENTATION
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 3d221273f1..b13e752358 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -528,6 +528,13 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
if (newp == NULL)
oom ();
memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
+#ifdef SHARED
+ /* Auditors can trigger a DTV resize event while the full malloc
+ is not yet in use. Mark the new DTV allocation as the
+ initial allocation. */
+ if (!__rtld_malloc_is_complete ())
+ GL(dl_initial_dtv) = &newp[1];
+#endif
}
else
{
@@ -552,9 +559,14 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
/* Allocate initial TLS. RESULT should be a non-NULL pointer to storage
for the TLS space. The DTV may be resized, and so this function may
call malloc to allocate that space. The loader's GL(dl_load_tls_lock)
- is taken when manipulating global TLS-related data in the loader. */
+ is taken when manipulating global TLS-related data in the loader.
+
+ If MAIN_THREAD, this is the first call during process
+ initialization. In this case, TLS initialization for secondary
+ (audit) namespaces is skipped because that has already been handled
+ by dlopen. */
void *
-_dl_allocate_tls_init (void *result, bool init_tls)
+_dl_allocate_tls_init (void *result, bool main_thread)
{
if (result == NULL)
/* The memory allocation failed. */
@@ -627,17 +639,21 @@ _dl_allocate_tls_init (void *result, bool init_tls)
some platforms use in static programs requires it. */
dtv[map->l_tls_modid].pointer.val = dest;
- /* Copy the initialization image and clear the BSS part. For
- audit modules or dependencies with initial-exec TLS, we can not
- set the initial TLS image on default loader initialization
- because it would already be set by the audit setup. However,
- subsequent thread creation would need to follow the default
- behaviour. */
- if (map->l_ns != LM_ID_BASE && !init_tls)
+ /* Copy the initialization image and clear the BSS part.
+ For audit modules or dependencies with initial-exec TLS,
+ we can not set the initial TLS image on default loader
+ initialization because it would already be set by the
+ audit setup, which uses the dlopen code and already
+ clears l_need_tls_init. Calls with !main_thread from
+ pthread_create need to initialze TLS for the current
+ thread regardless of namespace. */
+ if (map->l_ns != LM_ID_BASE && main_thread)
continue;
memset (__mempcpy (dest, map->l_tls_initimage,
map->l_tls_initimage_size), '\0',
map->l_tls_blocksize - map->l_tls_initimage_size);
+ if (main_thread)
+ map->l_need_tls_init = 0;
}
total += cnt;
@@ -661,7 +677,7 @@ _dl_allocate_tls (void *mem)
{
return _dl_allocate_tls_init (mem == NULL
? _dl_allocate_tls_storage ()
- : allocate_dtv (mem), true);
+ : allocate_dtv (mem), false);
}
rtld_hidden_def (_dl_allocate_tls)
@@ -1094,9 +1110,32 @@ _dl_tls_initial_modid_limit_setup (void)
}
-void
+/* Add module to slot information data. If DO_ADD is false, only the
+ required memory is allocated. Must be called with
+ GL (dl_load_tls_lock) acquired. If the function has already been
+ called for the link map L with !DO_ADD, then this function will not
+ raise an exception, otherwise it is possible that it encounters a
+ memory allocation failure.
+
+ Return false if L has already been added to the slotinfo data, or
+ if L has no TLS data. If the returned value is true, L has been
+ added with this call (DO_ADD), or has been added in a previous call
+ (!DO_ADD).
+
+ The expected usage is as follows: Call _dl_add_to_slotinfo for
+ several link maps with DO_ADD set to false, and record if any calls
+ result in a true result. If there was a true result, call
+ _dl_add_to_slotinfo again, this time with DO_ADD set to true. (For
+ simplicity, it's possible to call the function for link maps where
+ the previous result was false.) The return value from the second
+ round of calls can be ignored. If there was true result initially,
+ call _dl_update_slotinfo to update the TLS generation counter. */
+bool
_dl_add_to_slotinfo (struct link_map *l, bool do_add)
{
+ if (l->l_tls_blocksize == 0 || l->l_tls_in_slotinfo)
+ return false;
+
/* Now that we know the object is loaded successfully add
modules containing TLS data to the dtv info table. We
might have to increase its size. */
@@ -1152,7 +1191,10 @@ cannot create TLS data structures"));
atomic_store_relaxed (&listp->slotinfo[idx].map, l);
atomic_store_relaxed (&listp->slotinfo[idx].gen,
GL(dl_tls_generation) + 1);
+ l->l_tls_in_slotinfo = true;
}
+
+ return true;
}
#if PTHREAD_IN_LIBC
diff --git a/elf/dl-version.c b/elf/dl-version.c
index 8966d612cc..708b1c94ea 100644
--- a/elf/dl-version.c
+++ b/elf/dl-version.c
@@ -357,6 +357,13 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
}
}
+
+ /* The empty string has ELF hash zero. This avoids a NULL check
+ before the version string comparison in check_match in
+ dl-lookup.c. */
+ for (unsigned int i = 0; i < map->l_nversions; ++i)
+ if (map->l_versions[i].name == NULL)
+ map->l_versions[i].name = "";
}
/* When there is a DT_VERNEED entry with libc.so on DT_NEEDED, issue
diff --git a/elf/endswith.h b/elf/endswith.h
index c6430c48be..3954e57f8e 100644
--- a/elf/endswith.h
+++ b/elf/endswith.h
@@ -17,6 +17,7 @@
#ifndef _ENDSWITH_H
#define _ENDSWITH_H
+#include
#include
/* Return true if the N bytes at NAME end with with the characters in
@@ -30,4 +31,11 @@ endswithn (const char *name, size_t n, const char *suffix)
strlen (suffix)) == 0);
}
+/* Same as endswithn, but uses the entire SUBJECT for matching. */
+static inline bool
+endswith (const char *subject, const char *suffix)
+{
+ return endswithn (subject, strlen (subject), suffix);
+}
+
#endif /* _ENDSWITH_H */
diff --git a/elf/rtld.c b/elf/rtld.c
index bfdf632e77..dc65b6e404 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1284,6 +1284,60 @@ rtld_setup_main_map (struct link_map *main_map)
return has_interp;
}
+/* Set up the program header information for the dynamic linker
+ itself. It can be accessed via _r_debug and dl_iterate_phdr
+ callbacks, and it is used by _dl_find_object. */
+static void
+rtld_setup_phdr (void)
+{
+ /* Starting from binutils-2.23, the linker will define the magic
+ symbol __ehdr_start to point to our own ELF header if it is
+ visible in a segment that also includes the phdrs. */
+
+ const ElfW(Ehdr) *rtld_ehdr = &__ehdr_start;
+ assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
+ assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
+
+ const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
+
+ GL(dl_rtld_map).l_phdr = rtld_phdr;
+ GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
+
+
+ GL(dl_rtld_map).l_contiguous = 1;
+ /* The linker may not have produced a contiguous object. The kernel
+ will load the object with actual gaps (unlike the glibc loader
+ for shared objects, which always produces a contiguous mapping).
+ See similar logic in rtld_setup_main_map above. */
+ {
+ ElfW(Addr) expected_load_address = 0;
+ for (const ElfW(Phdr) *ph = rtld_phdr; ph < &rtld_phdr[rtld_ehdr->e_phnum];
+ ++ph)
+ if (ph->p_type == PT_LOAD)
+ {
+ ElfW(Addr) mapstart = ph->p_vaddr & ~(GLRO(dl_pagesize) - 1);
+ if (GL(dl_rtld_map).l_contiguous && expected_load_address != 0
+ && expected_load_address != mapstart)
+ GL(dl_rtld_map).l_contiguous = 0;
+ ElfW(Addr) allocend = ph->p_vaddr + ph->p_memsz;
+ /* The next expected address is the page following this load
+ segment. */
+ expected_load_address = ((allocend + GLRO(dl_pagesize) - 1)
+ & ~(GLRO(dl_pagesize) - 1));
+ }
+ }
+
+ /* PT_GNU_RELRO is usually the last phdr. */
+ size_t cnt = rtld_ehdr->e_phnum;
+ while (cnt-- > 0)
+ if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
+ {
+ GL(dl_rtld_map).l_relro_addr = rtld_phdr[cnt].p_vaddr;
+ GL(dl_rtld_map).l_relro_size = rtld_phdr[cnt].p_memsz;
+ break;
+ }
+}
+
/* Adjusts the contents of the stack and related globals for the user
entry point. The ld.so processed skip_args arguments and bumped
_dl_argv and _dl_argc accordingly. Those arguments are removed from
@@ -1750,33 +1804,7 @@ dl_main (const ElfW(Phdr) *phdr,
++GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
++GL(dl_load_adds);
- /* Starting from binutils-2.23, the linker will define the magic symbol
- __ehdr_start to point to our own ELF header if it is visible in a
- segment that also includes the phdrs. If that's not available, we use
- the old method that assumes the beginning of the file is part of the
- lowest-addressed PT_LOAD segment. */
-
- /* Set up the program header information for the dynamic linker
- itself. It is needed in the dl_iterate_phdr callbacks. */
- const ElfW(Ehdr) *rtld_ehdr = &__ehdr_start;
- assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
- assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
-
- const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
-
- GL(dl_rtld_map).l_phdr = rtld_phdr;
- GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
-
-
- /* PT_GNU_RELRO is usually the last phdr. */
- size_t cnt = rtld_ehdr->e_phnum;
- while (cnt-- > 0)
- if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
- {
- GL(dl_rtld_map).l_relro_addr = rtld_phdr[cnt].p_vaddr;
- GL(dl_rtld_map).l_relro_size = rtld_phdr[cnt].p_memsz;
- break;
- }
+ rtld_setup_phdr ();
/* Add the dynamic linker to the TLS list if it also uses TLS. */
if (GL(dl_rtld_map).l_tls_blocksize != 0)
@@ -1823,8 +1851,7 @@ dl_main (const ElfW(Phdr) *phdr,
elf_setup_debug_entry (main_map, r);
/* We start adding objects. */
- r->r_state = RT_ADD;
- _dl_debug_state ();
+ _dl_debug_change_state (r, RT_ADD);
LIBC_PROBE (init_start, 2, LM_ID_BASE, r);
/* Auditing checkpoint: we are ready to signal that the initial map
@@ -1983,43 +2010,37 @@ dl_main (const ElfW(Phdr) *phdr,
if (main_map->l_searchlist.r_list[i] == &GL(dl_rtld_map))
break;
- bool rtld_multiple_ref = false;
- if (__glibc_likely (i < main_map->l_searchlist.r_nlist))
- {
- /* Some DT_NEEDED entry referred to the interpreter object itself, so
- put it back in the list of visible objects. We insert it into the
- chain in symbol search order because gdb uses the chain's order as
- its symbol search order. */
- rtld_multiple_ref = true;
+ /* Insert the link map for the dynamic loader into the chain in
+ symbol search order because gdb uses the chain's order as its
+ symbol search order. */
- GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
- if (__glibc_likely (state.mode == rtld_mode_normal))
- {
- GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist
- ? main_map->l_searchlist.r_list[i + 1]
- : NULL);
+ GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
+ if (__glibc_likely (state.mode == rtld_mode_normal))
+ {
+ GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist
+ ? main_map->l_searchlist.r_list[i + 1]
+ : NULL);
#ifdef NEED_DL_SYSINFO_DSO
- if (GLRO(dl_sysinfo_map) != NULL
- && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map)
- && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map))
- GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map);
+ if (GLRO(dl_sysinfo_map) != NULL
+ && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map)
+ && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map))
+ GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map);
#endif
- }
- else
- /* In trace mode there might be an invisible object (which we
- could not find) after the previous one in the search list.
- In this case it doesn't matter much where we put the
- interpreter object, so we just initialize the list pointer so
- that the assertion below holds. */
- GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next;
-
- assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next);
- GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map);
- if (GL(dl_rtld_map).l_next != NULL)
- {
- assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev);
- GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map);
- }
+ }
+ else
+ /* In trace mode there might be an invisible object (which we
+ could not find) after the previous one in the search list.
+ In this case it doesn't matter much where we put the
+ interpreter object, so we just initialize the list pointer so
+ that the assertion below holds. */
+ GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next;
+
+ assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next);
+ GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map);
+ if (GL(dl_rtld_map).l_next != NULL)
+ {
+ assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev);
+ GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map);
}
/* Now let us see whether all libraries are available in the
@@ -2269,25 +2290,25 @@ dl_main (const ElfW(Phdr) *phdr,
_rtld_main_check (main_map, _dl_argv[0]);
- /* Now we have all the objects loaded. Relocate them all except for
- the dynamic linker itself. We do this in reverse order so that copy
- relocs of earlier objects overwrite the data written by later
- objects. We do not re-relocate the dynamic linker itself in this
- loop because that could result in the GOT entries for functions we
- call being changed, and that would break us. It is safe to relocate
- the dynamic linker out of order because it has no copy relocations.
- Likewise for libc, which is relocated early to ensure that IFUNC
- resolvers in libc work. */
+ /* Now we have all the objects loaded. */
int consider_profiling = GLRO(dl_profile) != NULL;
/* If we are profiling we also must do lazy reloaction. */
GLRO(dl_lazy) |= consider_profiling;
+ /* If libc.so has been loaded, relocate it early, after the dynamic
+ loader itself. The initial self-relocation of ld.so should be
+ sufficient for IFUNC resolvers in libc.so. */
if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL)
- _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map,
- GL(dl_ns)[LM_ID_BASE].libc_map->l_scope,
- GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling);
+ {
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
+ _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map,
+ GL(dl_ns)[LM_ID_BASE].libc_map->l_scope,
+ GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling);
+ rtld_timer_accum (&relocate_time, start);
+ }
RTLD_TIMING_VAR (start);
rtld_timer_start (&start);
@@ -2310,9 +2331,8 @@ dl_main (const ElfW(Phdr) *phdr,
/* Also allocated with the fake malloc(). */
l->l_free_initfini = 0;
- if (l != &GL(dl_rtld_map))
- _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0,
- consider_profiling);
+ _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0,
+ consider_profiling);
/* Add object to slot information data if necessasy. */
if (l->l_tls_blocksize != 0 && __rtld_tls_init_tp_called)
@@ -2338,7 +2358,7 @@ dl_main (const ElfW(Phdr) *phdr,
into the main thread's TLS area, which we allocated above.
Note: thread-local variables must only be accessed after completing
the next step. */
- _dl_allocate_tls_init (tcbp, false);
+ _dl_allocate_tls_init (tcbp, true);
/* And finally install it for the main thread. */
if (! __rtld_tls_init_tp_called)
@@ -2347,36 +2367,29 @@ dl_main (const ElfW(Phdr) *phdr,
/* Make sure no new search directories have been added. */
assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs));
- if (rtld_multiple_ref)
- {
- /* There was an explicit ref to the dynamic linker as a shared lib.
- Re-relocate ourselves with user-controlled symbol definitions.
-
- We must do this after TLS initialization in case after this
- re-relocation, we might call a user-supplied function
- (e.g. calloc from _dl_relocate_object) that uses TLS data. */
-
- /* Set up the object lookup structures. */
- _dl_find_object_init ();
-
- /* The malloc implementation has been relocated, so resolving
- its symbols (and potentially calling IFUNC resolvers) is safe
- at this point. */
- __rtld_malloc_init_real (main_map);
-
- /* Likewise for the locking implementation. */
- __rtld_mutex_init ();
+ /* Set up the object lookup structures. */
+ _dl_find_object_init ();
+ /* If libc.so was loaded, relocate ld.so against it. Complete ld.so
+ initialization with mutex symbols from libc.so and malloc symbols
+ from the global scope. */
+ if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL)
+ {
RTLD_TIMING_VAR (start);
rtld_timer_start (&start);
+ _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
+ rtld_timer_accum (&relocate_time, start);
- /* Mark the link map as not yet relocated again. */
- GL(dl_rtld_map).l_relocated = 0;
- _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
+ __rtld_mutex_init ();
+ __rtld_malloc_init_real (main_map);
- rtld_timer_accum (&relocate_time, start);
+ /* Update copy-relocated _r_debug if necessary. */
+ _dl_debug_post_relocate (main_map);
}
+ /* All ld.so initialization is complete. Apply RELRO. */
+ _dl_protect_relro (&GL(dl_rtld_map));
+
/* Relocation is complete. Perform early libc initialization. This
is the initial libc, even if audit modules have been loaded with
other libcs. */
@@ -2389,16 +2402,15 @@ dl_main (const ElfW(Phdr) *phdr,
_dl_relocate_object might need to call `mprotect' for DT_TEXTREL. */
_dl_sysdep_start_cleanup ();
- /* Auditing checkpoint: we have added all objects. */
- _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT);
-
/* Notify the debugger all new objects are now ready to go. We must re-get
the address since by now the variable might be in another object. */
r = _dl_debug_update (LM_ID_BASE);
- r->r_state = RT_CONSISTENT;
- _dl_debug_state ();
+ _dl_debug_change_state (r, RT_CONSISTENT);
LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
+ /* Auditing checkpoint: we have added all objects. */
+ _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT);
+
#if defined USE_LDCONFIG && !defined MAP_COPY
/* We must munmap() the cache file. */
_dl_unload_cache ();
diff --git a/elf/sprof.c b/elf/sprof.c
index b19aca3292..1f5ab25ac3 100644
--- a/elf/sprof.c
+++ b/elf/sprof.c
@@ -38,6 +38,7 @@
#include
#include
#include
+#include
/* Get libc version number. */
#include "../version.h"
@@ -410,6 +411,7 @@ load_shobj (const char *name)
int fd;
ElfW(Shdr) *shdr;
size_t pagesize = getpagesize ();
+ struct stat st;
/* Since we use dlopen() we must be prepared to work around the sometimes
strange lookup rules for the shared objects. If we have a file foo.so
@@ -553,14 +555,39 @@ load_shobj (const char *name)
error (EXIT_FAILURE, errno, _("Reopening shared object `%s' failed"),
map->l_name);
+ if (fstat (fd, &st) < 0)
+ error (EXIT_FAILURE, errno, _("stat(%s) failure"), map->l_name);
+
+ /* We're depending on data that's being read from the file, so be a
+ bit paranoid here and make sure the requests are reasonable -
+ i.e. both size and offset are nonnegative and smaller than the
+ file size, as well as the offset of the end of the data. PREAD
+ would have failed anyway, but this is more robust and explains
+ what happened better. Note that SZ must be unsigned and OFF may
+ be signed or unsigned. */
+#define PCHECK(sz1,off1) { \
+ size_t sz = sz1, end_off; \
+ off_t off = off1; \
+ if (sz > st.st_size \
+ || off < 0 || off > st.st_size \
+ || INT_ADD_WRAPV (sz, off, &end_off) \
+ || end_off > st.st_size) \
+ error (EXIT_FAILURE, ERANGE, \
+ _("read outside of file extents %zu + %jd > %jd"), \
+ sz, (intmax_t) off, (intmax_t) st.st_size); \
+ }
+
/* Map the section header. */
size_t size = ehdr->e_shnum * sizeof (ElfW(Shdr));
shdr = (ElfW(Shdr) *) alloca (size);
+ PCHECK (size, ehdr->e_shoff);
if (pread (fd, shdr, size, ehdr->e_shoff) != size)
error (EXIT_FAILURE, errno, _("reading of section headers failed"));
/* Get the section header string table. */
char *shstrtab = (char *) alloca (shdr[ehdr->e_shstrndx].sh_size);
+ PCHECK (shdr[ehdr->e_shstrndx].sh_size,
+ shdr[ehdr->e_shstrndx].sh_offset);
if (pread (fd, shstrtab, shdr[ehdr->e_shstrndx].sh_size,
shdr[ehdr->e_shstrndx].sh_offset)
!= shdr[ehdr->e_shstrndx].sh_size)
@@ -588,6 +615,7 @@ load_shobj (const char *name)
size_t size = debuglink_entry->sh_size;
char *debuginfo_fname = (char *) alloca (size + 1);
debuginfo_fname[size] = '\0';
+ PCHECK (size, debuglink_entry->sh_offset);
if (pread (fd, debuginfo_fname, size, debuglink_entry->sh_offset)
!= size)
{
@@ -641,21 +669,32 @@ load_shobj (const char *name)
if (fd2 != -1)
{
ElfW(Ehdr) ehdr2;
+ struct stat st;
+
+ if (fstat (fd2, &st) < 0)
+ error (EXIT_FAILURE, errno, _("stat(%s) failure"), workbuf);
/* Read the ELF header. */
+ PCHECK (sizeof (ehdr2), 0);
if (pread (fd2, &ehdr2, sizeof (ehdr2), 0) != sizeof (ehdr2))
error (EXIT_FAILURE, errno,
_("reading of ELF header failed"));
/* Map the section header. */
- size_t size = ehdr2.e_shnum * sizeof (ElfW(Shdr));
+ size_t size;
+ if (INT_MULTIPLY_WRAPV (ehdr2.e_shnum, sizeof (ElfW(Shdr)), &size))
+ error (EXIT_FAILURE, errno, _("too many section headers"));
+
ElfW(Shdr) *shdr2 = (ElfW(Shdr) *) alloca (size);
+ PCHECK (size, ehdr2.e_shoff);
if (pread (fd2, shdr2, size, ehdr2.e_shoff) != size)
error (EXIT_FAILURE, errno,
_("reading of section headers failed"));
/* Get the section header string table. */
shstrtab = (char *) alloca (shdr2[ehdr2.e_shstrndx].sh_size);
+ PCHECK (shdr2[ehdr2.e_shstrndx].sh_size,
+ shdr2[ehdr2.e_shstrndx].sh_offset);
if (pread (fd2, shstrtab, shdr2[ehdr2.e_shstrndx].sh_size,
shdr2[ehdr2.e_shstrndx].sh_offset)
!= shdr2[ehdr2.e_shstrndx].sh_size)
diff --git a/elf/tst-audit-tlsdesc-dlopen2.c b/elf/tst-audit-tlsdesc-dlopen2.c
new file mode 100644
index 0000000000..7ba2c4129a
--- /dev/null
+++ b/elf/tst-audit-tlsdesc-dlopen2.c
@@ -0,0 +1,46 @@
+/* Loading TLS-using modules from auditors (bug 32412). Main program.
+ Copyright (C) 2021-2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+
+static int
+do_test (void)
+{
+ puts ("info: start of main program");
+
+ /* Load TLS-using modules, to trigger DTV resizing. The dynamic
+ linker will load them again (requiring their own TLS) because the
+ dlopen calls from the auditor were in the auditing namespace. */
+ for (int i = 1; i <= 19; ++i)
+ {
+ char dso[30];
+ snprintf (dso, sizeof (dso), "tst-tlsmod17a%d.so", i);
+ char sym[30];
+ snprintf (sym, sizeof(sym), "tlsmod17a%d", i);
+
+ void *handle = xdlopen (dso, RTLD_LAZY);
+ int (*func) (void) = xdlsym (handle, sym);
+ /* Trigger TLS allocation. */
+ func ();
+ }
+
+ return 0;
+}
+
+#include
diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
index d2640fe8b2..7786a74e64 100644
--- a/elf/tst-audit23.c
+++ b/elf/tst-audit23.c
@@ -17,6 +17,7 @@
. */
#include
+#include
#include
#include
#include
@@ -30,16 +31,21 @@
#include
#include
#include
+#include
static int restart;
+static int do_dlclose;
#define CMDLINE_OPTIONS \
- { "restart", no_argument, &restart, 1 },
+ { "restart", no_argument, &restart, 1 }, \
+ { "dlclose", no_argument, &do_dlclose, 1 }, \
static int
handle_restart (void)
{
xdlopen ("tst-audit23mod.so", RTLD_NOW);
- xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
+ void *handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
+ if (do_dlclose)
+ xdlclose (handle);
return 0;
}
@@ -59,8 +65,8 @@ is_vdso (const char *str)
|| startswith (str, "linux-vdso");
}
-static int
-do_test (int argc, char *argv[])
+static void
+do_one_test (int argc, char *argv[], bool pass_dlclose_flag)
{
/* We must have either:
- One or four parameters left if called initially:
@@ -68,16 +74,15 @@ do_test (int argc, char *argv[])
+ "--library-path" optional
+ the library path optional
+ the application name */
- if (restart)
- return handle_restart ();
-
- char *spargv[9];
+ char *spargv[10];
TEST_VERIFY_EXIT (((argc - 1) + 3) < array_length (spargv));
int i = 0;
for (; i < argc - 1; i++)
spargv[i] = argv[i + 1];
spargv[i++] = (char *) "--direct";
spargv[i++] = (char *) "--restart";
+ if (pass_dlclose_flag)
+ spargv[i++] = (char *) "--dlclose";
spargv[i] = NULL;
setenv ("LD_AUDIT", "tst-auditmod23.so", 0);
@@ -85,14 +90,30 @@ do_test (int argc, char *argv[])
= support_capture_subprogram (spargv[0], spargv, NULL);
support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr);
+ {
+ FILE *fp = fmemopen (result.err.buffer, result.err.length, "r");
+ TEST_VERIFY (fp != NULL);
+ unsigned int line = 0;
+ char *buffer = NULL;
+ size_t buffer_length = 0;
+ puts ("info: *** audit log start ***");
+ while (xgetline (&buffer, &buffer_length, fp))
+ printf ("%6u\t%s", ++line, buffer);
+ puts ("info: *** audit log end ***");
+ free (buffer);
+ xfclose (fp);
+ }
+
/* The expected la_objopen/la_objclose:
1. executable
2. loader
3. libc.so
- 4. tst-audit23mod.so
- 5. libc.so (LM_ID_NEWLM).
- 6. vdso (optional and ignored). */
- enum { max_objs = 6 };
+ 4. libgcc_s.so (one some architectures, for libsupport)
+ 5. tst-audit23mod.so
+ 6. libc.so (LM_ID_NEWLM).
+ 7. loader (proxy link map in new namespace)
+ vdso (optional and ignored). */
+ enum { max_objs = 7 };
struct la_obj_t
{
char *lname;
@@ -115,8 +136,10 @@ do_test (int argc, char *argv[])
TEST_VERIFY (out != NULL);
char *buffer = NULL;
size_t buffer_length = 0;
+ unsigned int line = 0;
while (xgetline (&buffer, &buffer_length, out))
{
+ ++line;
if (startswith (buffer, "la_activity: "))
{
uintptr_t cookie;
@@ -127,8 +150,14 @@ do_test (int argc, char *argv[])
/* The cookie identifies the object at the head of the link map,
so we only add a new namespace if it changes from the previous
- one. This works since dlmopen is the last in the test body. */
- if (cookie != last_act_cookie && last_act_cookie != -1)
+ one. This works since dlmopen is the last in the test body.
+
+ Currently, this does not work as expected because there
+ is no head link map if a namespace is completely deleted.
+ No LA_ACT_CONSISTENT event is generated in that case.
+ See the comment in _dl_audit_activity_nsid and bug 32068. */
+ if (cookie != last_act_cookie && last_act_cookie != -1
+ && !pass_dlclose_flag)
TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
if (this_act == LA_ACT_ADD && acts[nacts] != cookie)
@@ -174,8 +203,8 @@ do_test (int argc, char *argv[])
if (is_vdso (lname))
continue;
if (nobjs == max_objs)
- FAIL_EXIT1 ("non expected la_objopen: %s %"PRIxPTR" %ld",
- lname, laddr, lmid);
+ FAIL_EXIT1 ("(line %u) non expected la_objopen: %s %"PRIxPTR" %ld",
+ line, lname, laddr, lmid);
objs[nobjs].lname = lname;
objs[nobjs].laddr = laddr;
objs[nobjs].lmid = lmid;
@@ -217,11 +246,26 @@ do_test (int argc, char *argv[])
}
}
+ Lmid_t lmid_other = LM_ID_NEWLM;
+ unsigned int other_namespace_count = 0;
for (size_t i = 0; i < nobjs; i++)
{
+ if (objs[i].lmid != LM_ID_BASE)
+ {
+ if (lmid_other == LM_ID_NEWLM)
+ lmid_other = objs[i].lmid;
+ TEST_COMPARE (objs[i].lmid, lmid_other);
+ ++other_namespace_count;
+ if (!(endswith (objs[i].lname, "/" LIBC_SO)
+ || endswith (objs[i].lname, "/" LD_SO)))
+ FAIL ("unexpected object in secondary namespace: %s",
+ objs[i].lname);
+ }
TEST_COMPARE (objs[i].closed, true);
free (objs[i].lname);
}
+ /* Both libc.so and ld.so should be present. */
+ TEST_COMPARE (other_namespace_count, 2);
/* la_activity(LA_ACT_CONSISTENT) should be the last callback received.
Since only one link map may be not-CONSISTENT at a time, this also
@@ -231,7 +275,16 @@ do_test (int argc, char *argv[])
free (buffer);
xfclose (out);
+}
+
+static int
+do_test (int argc, char *argv[])
+{
+ if (restart)
+ return handle_restart ();
+ do_one_test (argc, argv, false);
+ do_one_test (argc, argv, true);
return 0;
}
diff --git a/elf/tst-auditmod-tlsdesc2.c b/elf/tst-auditmod-tlsdesc2.c
new file mode 100644
index 0000000000..50275cd34d
--- /dev/null
+++ b/elf/tst-auditmod-tlsdesc2.c
@@ -0,0 +1,59 @@
+/* Loading TLS-using modules from auditors (bug 32412). Audit module.
+ Copyright (C) 2021-2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+#include
+
+unsigned int
+la_version (unsigned int version)
+{
+ /* Open some modules, to trigger DTV resizing before the switch to
+ the main malloc. */
+ for (int i = 1; i <= 19; ++i)
+ {
+ char dso[30];
+ snprintf (dso, sizeof (dso), "tst-tlsmod17a%d.so", i);
+ char sym[30];
+ snprintf (sym, sizeof(sym), "tlsmod17a%d", i);
+
+ void *handle = dlopen (dso, RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("error: dlmopen from auditor: %s\n", dlerror ());
+ fflush (stdout);
+ _exit (1);
+ }
+ int (*func) (void) = dlsym (handle, sym);
+ if (func == NULL)
+ {
+ printf ("error: dlsym from auditor: %s\n", dlerror ());
+ fflush (stdout);
+ _exit (1);
+ }
+ /* Trigger TLS allocation. */
+ func ();
+ }
+
+ puts ("info: TLS-using modules loaded from auditor");
+ fflush (stdout);
+
+ return LAV_CURRENT;
+}
diff --git a/elf/tst-dlmopen4-nonpic.c b/elf/tst-dlmopen4-nonpic.c
new file mode 100644
index 0000000000..ad4e409953
--- /dev/null
+++ b/elf/tst-dlmopen4-nonpic.c
@@ -0,0 +1,2 @@
+#define BUILD_FOR_NONPIC
+#include "tst-dlmopen4.c"
diff --git a/elf/tst-dlmopen4-pic.c b/elf/tst-dlmopen4-pic.c
new file mode 100644
index 0000000000..919fa85c25
--- /dev/null
+++ b/elf/tst-dlmopen4-pic.c
@@ -0,0 +1,2 @@
+#define BUILD_FOR_PIC
+#include "tst-dlmopen4.c"
diff --git a/elf/tst-dlmopen4.c b/elf/tst-dlmopen4.c
index b1c5502621..9e053fbc59 100644
--- a/elf/tst-dlmopen4.c
+++ b/elf/tst-dlmopen4.c
@@ -46,6 +46,15 @@ do_test (void)
TEST_COMPARE (debug->base.r_version, 1);
TEST_VERIFY_EXIT (debug->r_next == NULL);
+#ifdef BUILD_FOR_PIC
+ /* In a PIC build, using _r_debug directly should give us the same
+ object. */
+ TEST_VERIFY (&_r_debug == &debug->base);
+#endif
+#ifdef BUILD_FOR_NONPIC
+ TEST_COMPARE (_r_debug.r_version, 1);
+#endif
+
void *h = xdlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so",
RTLD_LAZY);
@@ -57,6 +66,19 @@ do_test (void)
const char *name = basename (debug->r_next->base.r_map->l_name);
TEST_COMPARE_STRING (name, "tst-dlmopen1mod.so");
+#ifdef BUILD_FOR_NONPIC
+ /* If a copy relocation is used, it must be at version 1. */
+ if (&_r_debug != &debug->base)
+ {
+ TEST_COMPARE (_r_debug.r_version, 1);
+ TEST_COMPARE ((uintptr_t) _r_debug.r_map,
+ (uintptr_t) debug->base.r_map);
+ TEST_COMPARE (_r_debug.r_brk, debug->base.r_brk);
+ TEST_COMPARE (_r_debug.r_state, debug->base.r_state);
+ TEST_COMPARE (_r_debug.r_ldbase, debug->base.r_ldbase);
+ }
+#endif
+
xdlclose (h);
return 0;
diff --git a/elf/tst-dlopen-auditdup-auditmod.c b/elf/tst-dlopen-auditdup-auditmod.c
new file mode 100644
index 0000000000..270a595ec4
--- /dev/null
+++ b/elf/tst-dlopen-auditdup-auditmod.c
@@ -0,0 +1,104 @@
+/* Auditor that opens again an object that just has been opened.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+unsigned int
+la_version (unsigned int v)
+{
+ return LAV_CURRENT;
+}
+
+static bool trigger_on_la_activity;
+
+unsigned int
+la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
+{
+ printf ("info: la_objopen: \"%s\"\n", map->l_name);
+ if (strstr (map->l_name, "/tst-dlopen-auditdupmod.so") != NULL)
+ trigger_on_la_activity = true;
+ return 0;
+}
+
+void
+la_activity (uintptr_t *cookie, unsigned int flag)
+{
+ static unsigned int calls;
+ ++calls;
+ printf ("info: la_activity: call %u (flag %u)\n", calls, flag);
+ fflush (stdout);
+ if (trigger_on_la_activity)
+ {
+ /* Avoid triggering on the dlmopen call below. */
+ static bool recursion;
+ if (recursion)
+ return;
+ recursion = true;
+
+ puts ("info: about to dlmopen tst-dlopen-auditdupmod.so");
+ fflush (stdout);
+ void *handle = dlmopen (LM_ID_BASE, "tst-dlopen-auditdupmod.so",
+ RTLD_NOW);
+ if (handle == NULL)
+ {
+ printf ("error: dlmopen: %s\n", dlerror ());
+ fflush (stdout);
+ _exit (1);
+ }
+
+ /* Check that the constructor has not run. Running the
+ constructor would require constructing its dependencies, but
+ the constructor call that triggered this auditing activity
+ has not completed, and constructors among the dependencies
+ may not be able to deal with that. */
+ int *status = dlsym (handle, "auditdupmod_status");
+ if (status == NULL)
+ {
+ printf ("error: dlsym: %s\n", dlerror ());
+ fflush (stdout);
+ _exit (1);
+ }
+ printf ("info: auditdupmod_status == %d\n", *status);
+ if (*status != 0)
+ {
+ puts ("error: auditdupmod_status == 0 expected");
+ fflush (stdout);
+ _exit (1);
+ }
+ /* Checked in the destructor and the main program. */
+ ++*status;
+ printf ("info: auditdupmod_status == %d\n", *status);
+
+ /* Check that the module has been relocated. */
+ int **status_address = dlsym (handle, "auditdupmod_status_address");
+ if (status_address == NULL || *status_address != status)
+ {
+ puts ("error: invalid auditdupmod_status address in"
+ " tst-dlopen-auditdupmod.so");
+ fflush (stdout);
+ _exit (1);
+ }
+
+ fflush (stdout);
+ }
+}
diff --git a/elf/tst-dlopen-auditdup.c b/elf/tst-dlopen-auditdup.c
new file mode 100644
index 0000000000..d022c58ae3
--- /dev/null
+++ b/elf/tst-dlopen-auditdup.c
@@ -0,0 +1,36 @@
+/* Test that recursive dlopen from auditor works (bug 31986).
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+
+static int
+do_test (void)
+{
+ puts ("info: about to dlopen tst-dlopen-auditdupmod.so");
+ fflush (stdout);
+ void *handle = xdlopen ("tst-dlopen-auditdupmod.so", RTLD_NOW);
+ int *status = xdlsym (handle, "auditdupmod_status");
+ printf ("info: auditdupmod_status == %d (from main)\n", *status);
+ TEST_COMPARE (*status, 2);
+ xdlclose (handle);
+ return 0;
+}
+
+#include
diff --git a/elf/tst-dlopen-auditdupmod.c b/elf/tst-dlopen-auditdupmod.c
new file mode 100644
index 0000000000..59b7e21daa
--- /dev/null
+++ b/elf/tst-dlopen-auditdupmod.c
@@ -0,0 +1,48 @@
+/* Directly opened test module that gets reopened from the auditor.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+
+int auditdupmod_status;
+
+/* Used to check for successful relocation processing. */
+int *auditdupmod_status_address = &auditdupmod_status;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+ ++auditdupmod_status;
+ printf ("info: tst-dlopen-auditdupmod.so constructor called (status %d)\n",
+ auditdupmod_status);
+}
+
+static void __attribute__ ((destructor))
+fini (void)
+{
+ /* The tst-dlopen-auditdup-auditmod.so auditor incremented
+ auditdupmod_status. */
+ printf ("info: tst-dlopen-auditdupmod.so destructor called (status %d)\n",
+ auditdupmod_status);
+ if (auditdupmod_status != 2)
+ {
+ puts ("error: auditdupmod_status == 2 expected");
+ exit (1);
+ }
+}
diff --git a/elf/tst-dlopen-constructor-null-mod1.c b/elf/tst-dlopen-constructor-null-mod1.c
new file mode 100644
index 0000000000..70a7a0ad46
--- /dev/null
+++ b/elf/tst-dlopen-constructor-null-mod1.c
@@ -0,0 +1,55 @@
+/* Module calling dlopen (NULL, RTLD_LAZY) to obtain the global scope.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+
+int mod1_status;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+ puts ("info: tst-dlopen-constructor-null-mod1.so constructor");
+
+ void *handle = dlopen (NULL, RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("error: %s\n", dlerror ());
+ exit (1);
+ }
+ puts ("info: dlopen returned");
+ if (dlsym (handle, "malloc") != malloc)
+ {
+ puts ("error: dlsym did not produce expected result");
+ exit (1);
+ }
+ dlclose (handle);
+
+ /* Check that the second module's constructor has not executed. */
+ if (getenv ("mod2_status") != NULL)
+ {
+ printf ("error: mod2_status environment variable set: %s\n",
+ getenv ("mod2_status"));
+ exit (1);
+ }
+
+ /* Communicate to the second module that the constructor executed. */
+ mod1_status = 1;
+}
diff --git a/elf/tst-dlopen-constructor-null-mod2.c b/elf/tst-dlopen-constructor-null-mod2.c
new file mode 100644
index 0000000000..d6e945beae
--- /dev/null
+++ b/elf/tst-dlopen-constructor-null-mod2.c
@@ -0,0 +1,37 @@
+/* Module whose constructor should not be invoked by dlopen (NULL, RTLD_LAZY).
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+
+extern int mod1_status;
+int mod2_status;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+ printf ("info: tst-dlopen-constructor-null-mod2.so constructor"
+ " (mod1_status=%d)", mod1_status);
+ if (!(mod1_status == 1 && mod2_status == 0))
+ {
+ puts ("error: mod1_status == 1 && mod2_status == 0 expected");
+ exit (1);
+ }
+ setenv ("mod2_status", "constructed", 1);
+ mod2_status = 1;
+}
diff --git a/sysdeps/x86_64/dl-trampoline-save.h b/elf/tst-dlopen-constructor-null.c
similarity index 55%
rename from sysdeps/x86_64/dl-trampoline-save.h
rename to elf/tst-dlopen-constructor-null.c
index 84eac4a8ac..db90643325 100644
--- a/sysdeps/x86_64/dl-trampoline-save.h
+++ b/elf/tst-dlopen-constructor-null.c
@@ -1,4 +1,4 @@
-/* x86-64 PLT trampoline register save macros.
+/* Verify that dlopen (NULL, RTLD_LAZY) does not complete initialization.
Copyright (C) 2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -16,19 +16,23 @@
License along with the GNU C Library; if not, see
. */
-#ifndef DL_STACK_ALIGNMENT
-/* Due to GCC bug:
+/* This test mimics what the glvndSetupPthreads function in libglvnd
+ does. */
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
+#include
+#include
- __tls_get_addr may be called with 8-byte stack alignment. Although
- this bug has been fixed in GCC 4.9.4, 5.3 and 6, we can't assume
- that stack will be always aligned at 16 bytes. */
-# define DL_STACK_ALIGNMENT 8
-#endif
+/* Defined and initialized in the shared objects. */
+extern int mod1_status;
+extern int mod2_status;
-/* True if _dl_runtime_resolve should align stack for STATE_SAVE or align
- stack to 16 bytes before calling _dl_fixup. */
-#define DL_RUNTIME_RESOLVE_REALIGN_STACK \
- (STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \
- || 16 > DL_STACK_ALIGNMENT)
+static int
+do_test (void)
+{
+ TEST_COMPARE (mod1_status, 1);
+ TEST_COMPARE (mod2_status, 1);
+ TEST_COMPARE_STRING (getenv ("mod2_status"), "constructed");
+ return 0;
+}
+
+#include
diff --git a/elf/tst-dlopen-sgid-mod.c b/elf/tst-dlopen-sgid-mod.c
new file mode 100644
index 0000000000..5eb79eef48
--- /dev/null
+++ b/elf/tst-dlopen-sgid-mod.c
@@ -0,0 +1 @@
+/* Opening this object should not succeed. */
diff --git a/elf/tst-dlopen-sgid.c b/elf/tst-dlopen-sgid.c
new file mode 100644
index 0000000000..8aec52e19f
--- /dev/null
+++ b/elf/tst-dlopen-sgid.c
@@ -0,0 +1,106 @@
+/* Test case for ignored LD_LIBRARY_PATH in static startug (bug 32976).
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* This is the name of our test object. Use a custom module for
+ testing, so that this object does not get picked up from the system
+ path. */
+static const char dso_name[] = "tst-dlopen-sgid-mod.so";
+
+/* Used to mark the recursive invocation. */
+static const char magic_argument[] = "run-actual-test";
+
+static int
+do_test (void)
+{
+/* Pathname of the directory that receives the shared objects this
+ test attempts to load. */
+ char *libdir = support_create_temp_directory ("tst-dlopen-sgid-");
+
+ /* This is supposed to be ignored and stripped. */
+ TEST_COMPARE (setenv ("LD_LIBRARY_PATH", libdir, 1), 0);
+
+ /* Copy of libc.so.6. */
+ {
+ char *from = xasprintf ("%s/%s", support_objdir_root, LIBC_SO);
+ char *to = xasprintf ("%s/%s", libdir, LIBC_SO);
+ add_temp_file (to);
+ support_copy_file (from, to);
+ free (to);
+ free (from);
+ }
+
+ /* Copy of the test object. */
+ {
+ char *from = xasprintf ("%s/elf/%s", support_objdir_root, dso_name);
+ char *to = xasprintf ("%s/%s", libdir, dso_name);
+ add_temp_file (to);
+ support_copy_file (from, to);
+ free (to);
+ free (from);
+ }
+
+ free (libdir);
+
+ support_capture_subprogram_self_sgid (magic_argument);
+
+ return 0;
+}
+
+static void
+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. */
+ FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
+ (intmax_t) getgid ());
+
+ /* Should be removed due to SGID. */
+ TEST_COMPARE_STRING (getenv ("LD_LIBRARY_PATH"), NULL);
+
+ TEST_VERIFY (dlopen (dso_name, RTLD_NOW) == NULL);
+ {
+ const char *message = dlerror ();
+ TEST_COMPARE_STRING (message,
+ "tst-dlopen-sgid-mod.so:"
+ " cannot open shared object file:"
+ " No such file or directory");
+ }
+
+ support_record_failure_barrier ();
+ exit (EXIT_SUCCESS);
+ }
+}
+
+#define PREPARE alternative_main
+#include
diff --git a/elf/tst-dlopen-tlsreinit1.c b/elf/tst-dlopen-tlsreinit1.c
new file mode 100644
index 0000000000..2016b9b0c6
--- /dev/null
+++ b/elf/tst-dlopen-tlsreinit1.c
@@ -0,0 +1,40 @@
+/* Test that dlopen preserves already accessed TLS (bug 31717).
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+
+static int
+do_test (void)
+{
+ void *handle = xdlopen ("tst-dlopen-tlsreinitmod1.so", RTLD_NOW);
+
+ bool *tlsreinitmod3_tested = xdlsym (handle, "tlsreinitmod3_tested");
+ TEST_VERIFY (*tlsreinitmod3_tested);
+
+ xdlclose (handle);
+
+ /* This crashes if the libc.so.6 TLS image has been reverted. */
+ TEST_VERIFY (!isupper ('@'));
+
+ return 0;
+}
+
+#include
diff --git a/elf/tst-dlopen-tlsreinit2.c b/elf/tst-dlopen-tlsreinit2.c
new file mode 100644
index 0000000000..90ad2c7713
--- /dev/null
+++ b/elf/tst-dlopen-tlsreinit2.c
@@ -0,0 +1,39 @@
+/* Test that dlopen preserves already accessed TLS (bug 31717).
+ Variant with initially-linked modules.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+
+
+static int
+do_test (void)
+{
+ /* Defined in tst-dlopen-tlsreinitmod3.so. */
+ extern bool tlsreinitmod3_tested;
+ TEST_VERIFY (tlsreinitmod3_tested);
+
+ /* This crashes if the libc.so.6 TLS image has been reverted. */
+ TEST_VERIFY (!isupper ('@'));
+
+ return 0;
+}
+
+#include
diff --git a/elf/tst-dlopen-tlsreinit3.c b/elf/tst-dlopen-tlsreinit3.c
new file mode 100644
index 0000000000..79bd585aff
--- /dev/null
+++ b/elf/tst-dlopen-tlsreinit3.c
@@ -0,0 +1,2 @@
+/* Same code, but run with LD_AUDIT=tst-auditmod1.so. */
+#include "tst-dlopen-tlsreinit1.c"
diff --git a/elf/tst-dlopen-tlsreinit4.c b/elf/tst-dlopen-tlsreinit4.c
new file mode 100644
index 0000000000..344c9211ab
--- /dev/null
+++ b/elf/tst-dlopen-tlsreinit4.c
@@ -0,0 +1,2 @@
+/* Same code, but run with LD_AUDIT=tst-auditmod1.so. */
+#include "tst-dlopen-tlsreinit2.c"
diff --git a/elf/tst-dlopen-tlsreinitmod1.c b/elf/tst-dlopen-tlsreinitmod1.c
new file mode 100644
index 0000000000..354cc3de51
--- /dev/null
+++ b/elf/tst-dlopen-tlsreinitmod1.c
@@ -0,0 +1,20 @@
+/* Test that dlopen preserves already accessed TLS (bug 31717), module 1.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+/* This module triggers loading of tst-dlopen-tlsreinitmod2.so and
+ tst-dlopen-tlsreinitmod3.so. */
diff --git a/elf/tst-dlopen-tlsreinitmod2.c b/elf/tst-dlopen-tlsreinitmod2.c
new file mode 100644
index 0000000000..677e69bd35
--- /dev/null
+++ b/elf/tst-dlopen-tlsreinitmod2.c
@@ -0,0 +1,30 @@
+/* Test that dlopen preserves already accessed TLS (bug 31717), module 2.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+
+/* Defined in tst-dlopen-tlsreinitmod3.so. This an underlinked symbol
+ dependency. */
+extern void call_tlsreinitmod3 (void);
+
+static void __attribute__ ((constructor))
+tlsreinitmod2_init (void)
+{
+ puts ("info: constructor of tst-dlopen-tlsreinitmod2.so invoked");
+ call_tlsreinitmod3 ();
+}
diff --git a/elf/tst-dlopen-tlsreinitmod3.c b/elf/tst-dlopen-tlsreinitmod3.c
new file mode 100644
index 0000000000..ef769c5131
--- /dev/null
+++ b/elf/tst-dlopen-tlsreinitmod3.c
@@ -0,0 +1,102 @@
+/* Test that dlopen preserves already accessed TLS (bug 31717), module 3.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+
+/* Used to verify from the main program that the test ran. */
+bool tlsreinitmod3_tested;
+
+/* This TLS variable must not revert back to the initial state after
+ dlopen. */
+static __thread int tlsreinitmod3_state = 1;
+
+/* Set from the ELF constructor during dlopen. */
+static bool tlsreinitmod3_constructed;
+
+/* Second half of test, behind a compiler barrier. The compiler
+ barrier is necessary to prevent carrying over TLS address
+ information from call_tlsreinitmod3 to call_tlsreinitmod3_tail. */
+void call_tlsreinitmod3_tail (void *self) __attribute__ ((weak));
+
+/* Called from tst-dlopen-tlsreinitmod2.so. */
+void
+call_tlsreinitmod3 (void)
+{
+ printf ("info: call_tlsreinitmod3 invoked (state=%d)\n",
+ tlsreinitmod3_state);
+
+ if (tlsreinitmod3_constructed)
+ {
+ puts ("error: call_tlsreinitmod3 called after ELF constructor");
+ fflush (stdout);
+ /* Cannot rely on test harness due to dynamic linking. */
+ _exit (1);
+ }
+
+ tlsreinitmod3_state = 2;
+
+ /* Self-dlopen. This will run the ELF constructor. */
+ void *self = dlopen ("tst-dlopen-tlsreinitmod3.so", RTLD_NOW);
+ if (self == NULL)
+ {
+ printf ("error: dlopen: %s\n", dlerror ());
+ fflush (stdout);
+ /* Cannot rely on test harness due to dynamic linking. */
+ _exit (1);
+ }
+
+ call_tlsreinitmod3_tail (self);
+}
+
+void
+call_tlsreinitmod3_tail (void *self)
+{
+ printf ("info: dlopen returned in tlsreinitmod3 (state=%d)\n",
+ tlsreinitmod3_state);
+
+ if (!tlsreinitmod3_constructed)
+ {
+ puts ("error: dlopen did not call tlsreinitmod3 ELF constructor");
+ fflush (stdout);
+ /* Cannot rely on test harness due to dynamic linking. */
+ _exit (1);
+ }
+
+ if (tlsreinitmod3_state != 2)
+ {
+ puts ("error: TLS state reverted in tlsreinitmod3");
+ fflush (stdout);
+ /* Cannot rely on test harness due to dynamic linking. */
+ _exit (1);
+ }
+
+ dlclose (self);
+
+ /* Signal test completion to the main program. */
+ tlsreinitmod3_tested = true;
+}
+
+static void __attribute__ ((constructor))
+tlsreinitmod3_init (void)
+{
+ puts ("info: constructor of tst-dlopen-tlsreinitmod3.so invoked");
+ tlsreinitmod3_constructed = true;
+}
diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c
index a47219047f..233eec7631 100644
--- a/elf/tst-env-setuid-tunables.c
+++ b/elf/tst-env-setuid-tunables.c
@@ -105,10 +105,7 @@ do_test (int argc, char **argv)
if (ret != 0)
exit (1);
-
- /* Special return code to make sure that the child executed all the way
- through. */
- exit (42);
+ return 0;
}
else
{
@@ -127,18 +124,7 @@ do_test (int argc, char **argv)
continue;
}
- int status = support_capture_subprogram_self_sgid (buf);
-
- /* Bail out early if unsupported. */
- if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
- return EXIT_UNSUPPORTED;
-
- if (WEXITSTATUS (status) != 42)
- {
- printf (" [%d] child failed with status %d\n", i,
- WEXITSTATUS (status));
- support_record_failure ();
- }
+ support_capture_subprogram_self_sgid (buf);
}
return 0;
}
diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c
index 59f2ffeb88..ee3f058468 100644
--- a/elf/tst-env-setuid.c
+++ b/elf/tst-env-setuid.c
@@ -147,10 +147,7 @@ do_test (int argc, char **argv)
if (ret != 0)
exit (1);
-
- /* Special return code to make sure that the child executed all the way
- through. */
- exit (42);
+ return 0;
}
else
{
@@ -174,17 +171,7 @@ do_test (int argc, char **argv)
free (profilepath);
}
- int status = support_capture_subprogram_self_sgid (SETGID_CHILD);
-
- if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
- exit (EXIT_UNSUPPORTED);
-
- if (WEXITSTATUS (status) != 42)
- {
- printf (" child failed with status %d\n",
- WEXITSTATUS (status));
- support_record_failure ();
- }
+ support_capture_subprogram_self_sgid (SETGID_CHILD);
return 0;
}
diff --git a/elf/tst-link-map-contiguous-ldso.c b/elf/tst-link-map-contiguous-ldso.c
new file mode 100644
index 0000000000..04de808bb2
--- /dev/null
+++ b/elf/tst-link-map-contiguous-ldso.c
@@ -0,0 +1,98 @@
+/* Check that _dl_find_object behavior matches up with gaps.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int
+do_test (void)
+{
+ struct link_map *l = xdlopen (LD_SO, RTLD_NOW);
+ if (!l->l_contiguous)
+ {
+ puts ("info: ld.so link map is not contiguous");
+
+ /* Try to find holes by probing with mmap. */
+ int pagesize = getpagesize ();
+ bool gap_found = false;
+ ElfW(Addr) addr = l->l_map_start;
+ TEST_COMPARE (addr % pagesize, 0);
+ while (addr < l->l_map_end)
+ {
+ void *expected = (void *) addr;
+ void *ptr = xmmap (expected, 1, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
+ struct dl_find_object dlfo;
+ int dlfo_ret = _dl_find_object (expected, &dlfo);
+ if (ptr == expected)
+ {
+ if (dlfo_ret < 0)
+ {
+ TEST_COMPARE (dlfo_ret, -1);
+ printf ("info: hole without mapping data found at %p\n", ptr);
+ }
+ else
+ FAIL ("object \"%s\" found in gap at %p",
+ dlfo.dlfo_link_map->l_name, ptr);
+ gap_found = true;
+ }
+ else if (dlfo_ret == 0)
+ {
+ if ((void *) dlfo.dlfo_link_map != (void *) l)
+ {
+ printf ("info: object \"%s\" found at %p\n",
+ dlfo.dlfo_link_map->l_name, ptr);
+ gap_found = true;
+ }
+ }
+ else
+ TEST_COMPARE (dlfo_ret, -1);
+ xmunmap (ptr, 1);
+ addr += pagesize;
+ }
+ if (!gap_found)
+ FAIL ("no ld.so gap found");
+ }
+ else
+ {
+ puts ("info: ld.so link map is contiguous");
+
+ /* Assert that ld.so is truly contiguous in memory. */
+ volatile long int *p = (volatile long int *) l->l_map_start;
+ volatile long int *end = (volatile long int *) l->l_map_end;
+ while (p < end)
+ {
+ *p;
+ ++p;
+ }
+ }
+
+ xdlclose (l);
+
+ return 0;
+}
+
+#include
diff --git a/elf/tst-link-map-contiguous-libc.c b/elf/tst-link-map-contiguous-libc.c
new file mode 100644
index 0000000000..eb5728c765
--- /dev/null
+++ b/elf/tst-link-map-contiguous-libc.c
@@ -0,0 +1,57 @@
+/* Check that the entire libc.so program image is readable if contiguous.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int
+do_test (void)
+{
+ struct link_map *l = xdlopen (LIBC_SO, RTLD_NOW);
+
+ /* The dynamic loader fills holes with PROT_NONE mappings. */
+ if (!l->l_contiguous)
+ FAIL_EXIT1 ("libc.so link map is not contiguous");
+
+ /* Direct probing does not work because not everything is readable
+ due to PROT_NONE mappings. */
+ int pagesize = getpagesize ();
+ ElfW(Addr) addr = l->l_map_start;
+ TEST_COMPARE (addr % pagesize, 0);
+ while (addr < l->l_map_end)
+ {
+ void *expected = (void *) addr;
+ void *ptr = xmmap (expected, 1, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
+ if (ptr == expected)
+ FAIL ("hole in libc.so memory image after %lu bytes",
+ (unsigned long int) (addr - l->l_map_start));
+ xmunmap (ptr, 1);
+ addr += pagesize;
+ }
+
+ xdlclose (l);
+
+ return 0;
+}
+#include
diff --git a/elf/tst-link-map-contiguous-main.c b/elf/tst-link-map-contiguous-main.c
new file mode 100644
index 0000000000..2d1a054f0f
--- /dev/null
+++ b/elf/tst-link-map-contiguous-main.c
@@ -0,0 +1,45 @@
+/* Check that the entire main program image is readable if contiguous.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+
+static int
+do_test (void)
+{
+ struct link_map *l = xdlopen ("", RTLD_NOW);
+ if (!l->l_contiguous)
+ FAIL_UNSUPPORTED ("main link map is not contiguous");
+
+ /* This check only works if the kernel loaded the main program. The
+ dynamic loader replaces gaps with PROT_NONE mappings, resulting
+ in faults. */
+ volatile long int *p = (volatile long int *) l->l_map_start;
+ volatile long int *end = (volatile long int *) l->l_map_end;
+ while (p < end)
+ {
+ *p;
+ ++p;
+ }
+
+ xdlclose (l);
+
+ return 0;
+}
+#include
diff --git a/elf/tst-rtld-no-malloc-audit.c b/elf/tst-rtld-no-malloc-audit.c
new file mode 100644
index 0000000000..a028377ad1
--- /dev/null
+++ b/elf/tst-rtld-no-malloc-audit.c
@@ -0,0 +1 @@
+#include "tst-rtld-no-malloc.c"
diff --git a/elf/tst-rtld-no-malloc-preload.c b/elf/tst-rtld-no-malloc-preload.c
new file mode 100644
index 0000000000..a028377ad1
--- /dev/null
+++ b/elf/tst-rtld-no-malloc-preload.c
@@ -0,0 +1 @@
+#include "tst-rtld-no-malloc.c"
diff --git a/elf/tst-rtld-no-malloc.c b/elf/tst-rtld-no-malloc.c
new file mode 100644
index 0000000000..5f24d4bd72
--- /dev/null
+++ b/elf/tst-rtld-no-malloc.c
@@ -0,0 +1,76 @@
+/* Test that program loading does not call malloc.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+
+#include
+#include
+
+static void
+print (const char *s)
+{
+ const char *end = s + strlen (s);
+ while (s < end)
+ {
+ ssize_t ret = write (STDOUT_FILENO, s, end - s);
+ if (ret <= 0)
+ _exit (2);
+ s += ret;
+ }
+}
+
+static void __attribute__ ((noreturn))
+unexpected_call (const char *function)
+{
+ print ("error: unexpected call to ");
+ print (function);
+ print ("\n");
+ _exit (1);
+}
+
+/* These are the malloc functions implement in elf/dl-minimal.c. */
+
+void
+free (void *ignored)
+{
+ unexpected_call ("free");
+}
+
+void *
+calloc (size_t ignored1, size_t ignored2)
+{
+ unexpected_call ("calloc");
+}
+
+void *
+malloc (size_t ignored)
+{
+ unexpected_call ("malloc");
+}
+
+void *
+realloc (void *ignored1, size_t ignored2)
+{
+ unexpected_call ("realloc");
+}
+
+int
+main (void)
+{
+ /* Do not use the test wrapper, to avoid spurious malloc calls from it. */
+ return 0;
+}
diff --git a/elf/tst-tls23-mod.c b/elf/tst-tls23-mod.c
new file mode 100644
index 0000000000..3ee4c70e40
--- /dev/null
+++ b/elf/tst-tls23-mod.c
@@ -0,0 +1,32 @@
+/* DSO used by tst-tls23.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+
+__thread struct tls tls_var0 __attribute__ ((visibility ("hidden")));
+
+struct tls *
+apply_tls (struct tls *p)
+{
+ INIT_TLS_CALL ();
+ BEFORE_TLS_CALL ();
+ tls_var0 = *p;
+ struct tls *ret = &tls_var0;
+ AFTER_TLS_CALL ();
+ return ret;
+}
diff --git a/elf/tst-tls23.c b/elf/tst-tls23.c
new file mode 100644
index 0000000000..afe594c067
--- /dev/null
+++ b/elf/tst-tls23.c
@@ -0,0 +1,106 @@
+/* Test that __tls_get_addr preserves caller-saved registers.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef IS_SUPPORTED
+# define IS_SUPPORTED() true
+#endif
+
+/* An architecture can define it to clobber caller-saved registers in
+ malloc below to verify that __tls_get_addr won't change caller-saved
+ registers. */
+#ifndef PREPARE_MALLOC
+# define PREPARE_MALLOC()
+#endif
+
+extern void * __libc_malloc (size_t);
+
+size_t malloc_counter = 0;
+
+void *
+malloc (size_t n)
+{
+ PREPARE_MALLOC ();
+ malloc_counter++;
+ return __libc_malloc (n);
+}
+
+static void *mod;
+static const char *modname = "tst-tls23-mod.so";
+
+static void
+open_mod (void)
+{
+ mod = xdlopen (modname, RTLD_LAZY);
+ printf ("open %s\n", modname);
+}
+
+static void
+close_mod (void)
+{
+ xdlclose (mod);
+ mod = NULL;
+ printf ("close %s\n", modname);
+}
+
+static void
+access_mod (const char *sym)
+{
+ struct tls var = { -4, -4, -4, -4 };
+ struct tls *(*f) (struct tls *) = xdlsym (mod, sym);
+ /* Check that our malloc is called. */
+ malloc_counter = 0;
+ struct tls *p = f (&var);
+ TEST_VERIFY (malloc_counter != 0);
+ printf ("access %s: %s() = %p\n", modname, sym, p);
+ TEST_VERIFY_EXIT (memcmp (p, &var, sizeof (var)) == 0);
+ ++(p->a);
+}
+
+static void *
+start (void *arg)
+{
+ access_mod ("apply_tls");
+ return arg;
+}
+
+static int
+do_test (void)
+{
+ if (!IS_SUPPORTED ())
+ return EXIT_UNSUPPORTED;
+
+ open_mod ();
+ pthread_t t = xpthread_create (NULL, start, NULL);
+ xpthread_join (t);
+ close_mod ();
+
+ return 0;
+}
+
+#include
diff --git a/elf/tst-tls23.h b/elf/tst-tls23.h
new file mode 100644
index 0000000000..d0e734569c
--- /dev/null
+++ b/elf/tst-tls23.h
@@ -0,0 +1,40 @@
+/* Test that __tls_get_addr preserves caller-saved registers.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+
+struct tls
+{
+ int64_t a, b, c, d;
+};
+
+extern struct tls *apply_tls (struct tls *);
+
+/* An architecture can define them to verify that caller-saved registers
+ aren't changed by __tls_get_addr. */
+#ifndef INIT_TLS_CALL
+# define INIT_TLS_CALL()
+#endif
+
+#ifndef BEFORE_TLS_CALL
+# define BEFORE_TLS_CALL()
+#endif
+
+#ifndef AFTER_TLS_CALL
+# define AFTER_TLS_CALL()
+#endif
diff --git a/elf/tst-version-hash-zero-linkmod.c b/elf/tst-version-hash-zero-linkmod.c
new file mode 100644
index 0000000000..15e2506d01
--- /dev/null
+++ b/elf/tst-version-hash-zero-linkmod.c
@@ -0,0 +1,22 @@
+/* Stub module for linking tst-version-hash-zero-refmod.so.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, see . */
+
+/* The version script assigns a different symbol version for the stub
+ module. Loading the module with the incorrect version is expected
+ to fail. */
+#include "tst-version-hash-zero-mod.c"
diff --git a/elf/tst-version-hash-zero-linkmod.map b/elf/tst-version-hash-zero-linkmod.map
new file mode 100644
index 0000000000..2dba7c22d7
--- /dev/null
+++ b/elf/tst-version-hash-zero-linkmod.map
@@ -0,0 +1,7 @@
+Base {
+ local: *;
+};
+
+OTHER_VERSION {
+ global: global_variable;
+} Base;
diff --git a/elf/tst-version-hash-zero-mod.c b/elf/tst-version-hash-zero-mod.c
new file mode 100644
index 0000000000..ac6b0dc4a5
--- /dev/null
+++ b/elf/tst-version-hash-zero-mod.c
@@ -0,0 +1,20 @@
+/* Test module with a zero version symbol hash.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, see . */
+
+/* The symbol version is assigned by version script. */
+int global_variable;
diff --git a/elf/tst-version-hash-zero-mod.map b/elf/tst-version-hash-zero-mod.map
new file mode 100644
index 0000000000..41eaff7914
--- /dev/null
+++ b/elf/tst-version-hash-zero-mod.map
@@ -0,0 +1,13 @@
+Base {
+ local: *;
+};
+
+/* Define the version so that tst-version-hash-zero-refmod.so passes
+ the initial symbol version check. */
+OTHER_VERSION {
+} Base;
+
+/* This version string hashes to zero. */
+PPPPPPPPPPPP {
+ global: global_variable;
+} Base;
diff --git a/elf/tst-version-hash-zero-refmod.c b/elf/tst-version-hash-zero-refmod.c
new file mode 100644
index 0000000000..cd8b3dcef5
--- /dev/null
+++ b/elf/tst-version-hash-zero-refmod.c
@@ -0,0 +1,23 @@
+/* Test module that triggers a relocation failure in tst-version-hash-zero.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, see . */
+
+/* This is bound to global_variable@@OTHER_VERSION via
+ tst-version-hash-zero-linkmod.so, but at run time, only
+ global_variable@PPPPPPPPPPPP exists. */
+extern int global_variable;
+int *pointer_variable = &global_variable;
diff --git a/elf/tst-version-hash-zero.c b/elf/tst-version-hash-zero.c
new file mode 100644
index 0000000000..66a0db4f51
--- /dev/null
+++ b/elf/tst-version-hash-zero.c
@@ -0,0 +1,56 @@
+/* Symbols with version hash zero should not match any version (bug 29190).
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, see . */
+
+#include
+#include
+#include
+#include
+
+static int
+do_test (void)
+{
+ void *handle = xdlopen ("tst-version-hash-zero-mod.so", RTLD_NOW);
+
+ /* This used to crash because some struct r_found_version entries
+ with hash zero did not have valid version strings. */
+ TEST_VERIFY (xdlvsym (handle, "global_variable", "PPPPPPPPPPPP") != NULL);
+
+ /* Consistency check. */
+ TEST_VERIFY (xdlsym (handle, "global_variable")
+ == xdlvsym (handle, "global_variable", "PPPPPPPPPPPP"));
+
+ /* This symbol version is supposed to be missing. */
+ TEST_VERIFY (dlvsym (handle, "global_variable", "OTHER_VERSION") == NULL);
+
+ /* tst-version-hash-zero-refmod.so references
+ global_variable@@OTHER_VERSION and is expected to fail to load.
+ dlvsym sets the hidden flag during lookup. Relocation does not,
+ so this exercises a different failure case. */
+ TEST_VERIFY_EXIT (dlopen ("tst-version-hash-zero-refmod.so", RTLD_NOW)
+ == NULL);
+ const char *message = dlerror ();
+ if (strstr (message,
+ ": undefined symbol: global_variable, version OTHER_VERSION")
+ == NULL)
+ FAIL_EXIT1 ("unexpected dlopen failure: %s", message);
+
+ xdlclose (handle);
+ return 0;
+}
+
+#include
diff --git a/include/ctype.h b/include/ctype.h
index 493a6f80ce..a15e5b6678 100644
--- a/include/ctype.h
+++ b/include/ctype.h
@@ -24,33 +24,35 @@ libc_hidden_proto (toupper)
NL_CURRENT_INDIRECT. */
# include "../locale/localeinfo.h"
-# include
# ifndef CTYPE_EXTERN_INLINE /* Used by ctype/ctype-info.c, which see. */
# define CTYPE_EXTERN_INLINE extern inline
# endif
-__libc_tsd_define (extern, const uint16_t *, CTYPE_B)
-__libc_tsd_define (extern, const int32_t *, CTYPE_TOUPPER)
-__libc_tsd_define (extern, const int32_t *, CTYPE_TOLOWER)
+extern __thread const uint16_t * __libc_tsd_CTYPE_B
+ attribute_hidden attribute_tls_model_ie;
+extern __thread const int32_t * __libc_tsd_CTYPE_TOUPPER
+ attribute_hidden attribute_tls_model_ie;
+extern __thread const int32_t * __libc_tsd_CTYPE_TOLOWER
+ attribute_hidden attribute_tls_model_ie;
CTYPE_EXTERN_INLINE const uint16_t ** __attribute__ ((const))
__ctype_b_loc (void)
{
- return __libc_tsd_address (const uint16_t *, CTYPE_B);
+ return &__libc_tsd_CTYPE_B;
}
CTYPE_EXTERN_INLINE const int32_t ** __attribute__ ((const))
__ctype_toupper_loc (void)
{
- return __libc_tsd_address (const int32_t *, CTYPE_TOUPPER);
+ return &__libc_tsd_CTYPE_TOUPPER;
}
CTYPE_EXTERN_INLINE const int32_t ** __attribute__ ((const))
__ctype_tolower_loc (void)
{
- return __libc_tsd_address (const int32_t *, CTYPE_TOLOWER);
+ return &__libc_tsd_CTYPE_TOLOWER;
}
# ifndef __NO_CTYPE
@@ -64,6 +66,11 @@ __ctype_tolower_loc (void)
# define __isdigit_l(c, l) ({ int __c = (c); __c >= '0' && __c <= '9'; })
# endif /* Not __NO_CTYPE. */
+/* For use in initializers. */
+extern const char _nl_C_LC_CTYPE_class[] attribute_hidden;
+extern const uint32_t _nl_C_LC_CTYPE_toupper[] attribute_hidden;
+extern const uint32_t _nl_C_LC_CTYPE_tolower[] attribute_hidden;
+
# endif /* IS_IN (libc). */
#endif /* Not _ISOMAC. */
diff --git a/include/dlfcn.h b/include/dlfcn.h
index f49ee1b0c9..a44420fa37 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -4,8 +4,7 @@
#include /* For ElfW. */
#include
-extern __typeof (_dl_find_object) __dl_find_object;
-hidden_proto (__dl_find_object)
+rtld_hidden_proto (_dl_find_object)
/* Internally used flag. */
#define __RTLD_DLOPEN 0x80000000
diff --git a/include/libc-internal.h b/include/libc-internal.h
index 87ac591835..1ef43ffe67 100644
--- a/include/libc-internal.h
+++ b/include/libc-internal.h
@@ -53,6 +53,9 @@ extern __typeof (__profile_frequency) __profile_frequency attribute_hidden;
is not for an audit module, not loaded via dlmopen, and not loaded
via static dlopen either). */
extern _Bool __libc_initial attribute_hidden;
+#else
+/* The static libc is always the initial namespace. */
+# define __libc_initial ((_Bool) 1)
#endif
#endif /* _LIBC_INTERNAL */
diff --git a/include/link.h b/include/link.h
index cb0d7d8e2f..7ca305f780 100644
--- a/include/link.h
+++ b/include/link.h
@@ -212,6 +212,7 @@ struct link_map
unsigned int l_find_object_processed:1; /* Zero if _dl_find_object_update
needs to process this
lt_library map. */
+ unsigned int l_tls_in_slotinfo:1; /* TLS slotinfo updated in dlopen. */
/* NODELETE status of the map. Only valid for maps of type
lt_loaded. Lazy binding sets l_nodelete_active directly,
@@ -364,6 +365,8 @@ struct auditstate
dynamic linker. */
extern struct r_debug_extended _r_debug_extended attribute_hidden;
+rtld_hidden_proto (_r_debug)
+
#if __ELF_NATIVE_CLASS == 32
# define symbind symbind32
# define LA_SYMBIND "la_symbind32"
diff --git a/include/math.h b/include/math.h
index fa11a710a6..035fd160ff 100644
--- a/include/math.h
+++ b/include/math.h
@@ -130,7 +130,10 @@ fabsf128 (_Float128 x)
}
# endif
-# if !(defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ > 0)
+
+/* NB: Internal tests don't have access to internal symbols. */
+# if !IS_IN (testsuite_internal) \
+ && !(defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ > 0)
# ifndef NO_MATH_REDIRECT
/* Declare some functions for use within GLIBC. Compilers typically
inline those functions as a single instruction. Use an asm to
diff --git a/include/rpc/rpc.h b/include/rpc/rpc.h
index f5cee6caef..ba967833ad 100644
--- a/include/rpc/rpc.h
+++ b/include/rpc/rpc.h
@@ -3,8 +3,6 @@
# ifndef _ISOMAC
-#include
-
/* Now define the internal interfaces. */
extern unsigned long _create_xid (void);
@@ -47,7 +45,8 @@ extern void __rpc_thread_key_cleanup (void) attribute_hidden;
extern void __rpc_thread_destroy (void) attribute_hidden;
-__libc_tsd_define (extern, struct rpc_thread_variables *, RPC_VARS)
+extern __thread struct rpc_thread_variables *__libc_tsd_RPC_VARS
+ attribute_hidden attribute_tls_model_ie;
#define RPC_THREAD_VARIABLE(x) (__rpc_thread_variables()->x)
diff --git a/libio/Makefile b/libio/Makefile
index 6a507b67ea..f2e98f96eb 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -117,6 +117,7 @@ tests = \
tst-mmap-offend \
tst-mmap-setvbuf \
tst-mmap2-eofsync \
+ tst-popen-fork \
tst-popen1 \
tst-setvbuf1 \
tst-sprintf-chk-ub \
@@ -141,6 +142,8 @@ tests = \
tst_wscanf \
# tests
+$(objpfx)tst-popen-fork: $(shared-thread-library)
+
tests-internal = tst-vtables tst-vtables-interposed
ifeq (yes,$(build-shared))
@@ -286,11 +289,18 @@ endif
ifeq ($(build-shared),yes)
aux += oldfileops oldstdfiles
tests += \
+ tst-fopen-compat \
tst-stderr-compat \
# tests
tests-2.0 += \
+ tst-fopen-compat \
tst-stderr-compat \
# tests-2.0
+
+tst-fopen-compat-ARGS = tst-fopen-compat.c
+# Disable PIE to trigger copy relocation.
+CFLAGS-tst-fopen-compat.c += -fno-pie
+tst-fopen-compat-no-pie = yes
endif
shared-only-routines = oldiofopen oldiofdopen oldiofclose oldfileops \
diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
index 91a80dd7c6..4b8bc35bdf 100644
--- a/libio/bits/stdio2.h
+++ b/libio/bits/stdio2.h
@@ -308,14 +308,14 @@ fgets (__fortify_clang_overload_arg (char *, __restrict, __s), int __n,
"fgets called with bigger size than length of "
"destination buffer")
{
- size_t sz = __glibc_objsize (__s);
- if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
+ size_t __sz = __glibc_objsize (__s);
+ if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
return __fgets_alias (__s, __n, __stream);
#if !__fortify_use_clang
- if (__glibc_unsafe_len (__n, sizeof (char), sz))
- return __fgets_chk_warn (__s, sz, __n, __stream);
+ if (__glibc_unsafe_len (__n, sizeof (char), __sz))
+ return __fgets_chk_warn (__s, __sz, __n, __stream);
#endif
- return __fgets_chk (__s, sz, __n, __stream);
+ return __fgets_chk (__s, __sz, __n, __stream);
}
__fortify_function __wur __nonnull ((4)) __attribute_overloadable__ size_t
@@ -326,14 +326,14 @@ fread (__fortify_clang_overload_arg (void *, __restrict, __ptr),
"fread called with bigger size * n than length "
"of destination buffer")
{
- size_t sz = __glibc_objsize0 (__ptr);
- if (__glibc_safe_or_unknown_len (__n, __size, sz))
+ size_t __sz = __glibc_objsize0 (__ptr);
+ if (__glibc_safe_or_unknown_len (__n, __size, __sz))
return __fread_alias (__ptr, __size, __n, __stream);
#if !__fortify_use_clang
- if (__glibc_unsafe_len (__n, __size, sz))
- return __fread_chk_warn (__ptr, sz, __size, __n, __stream);
+ if (__glibc_unsafe_len (__n, __size, __sz))
+ return __fread_chk_warn (__ptr, __sz, __size, __n, __stream);
#endif
- return __fread_chk (__ptr, sz, __size, __n, __stream);
+ return __fread_chk (__ptr, __sz, __size, __n, __stream);
}
#ifdef __USE_GNU
@@ -345,14 +345,14 @@ fgets_unlocked (__fortify_clang_overload_arg (char *, __restrict, __s),
"fgets called with bigger size than length of "
"destination buffer")
{
- size_t sz = __glibc_objsize (__s);
- if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
+ size_t __sz = __glibc_objsize (__s);
+ if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
return __fgets_unlocked_alias (__s, __n, __stream);
#if !__fortify_use_clang
- if (__glibc_unsafe_len (__n, sizeof (char), sz))
- return __fgets_unlocked_chk_warn (__s, sz, __n, __stream);
+ if (__glibc_unsafe_len (__n, sizeof (char), __sz))
+ return __fgets_unlocked_chk_warn (__s, __sz, __n, __stream);
#endif
- return __fgets_unlocked_chk (__s, sz, __n, __stream);
+ return __fgets_unlocked_chk (__s, __sz, __n, __stream);
}
#endif
@@ -366,8 +366,8 @@ fread_unlocked (__fortify_clang_overload_arg0 (void *, __restrict, __ptr),
"fread_unlocked called with bigger size * n than "
"length of destination buffer")
{
- size_t sz = __glibc_objsize0 (__ptr);
- if (__glibc_safe_or_unknown_len (__n, __size, sz))
+ size_t __sz = __glibc_objsize0 (__ptr);
+ if (__glibc_safe_or_unknown_len (__n, __size, __sz))
{
# ifdef __USE_EXTERN_INLINES
if (__builtin_constant_p (__size)
@@ -393,10 +393,10 @@ fread_unlocked (__fortify_clang_overload_arg0 (void *, __restrict, __ptr),
return __fread_unlocked_alias (__ptr, __size, __n, __stream);
}
# if !__fortify_use_clang
- if (__glibc_unsafe_len (__n, __size, sz))
- return __fread_unlocked_chk_warn (__ptr, sz, __size, __n, __stream);
+ if (__glibc_unsafe_len (__n, __size, __sz))
+ return __fread_unlocked_chk_warn (__ptr, __sz, __size, __n, __stream);
# endif
- return __fread_unlocked_chk (__ptr, sz, __size, __n, __stream);
+ return __fread_unlocked_chk (__ptr, __sz, __size, __n, __stream);
}
#endif
diff --git a/libio/genops.c b/libio/genops.c
index 99f5e80f20..6f20d49669 100644
--- a/libio/genops.c
+++ b/libio/genops.c
@@ -662,7 +662,7 @@ _IO_sputbackc (FILE *fp, int c)
{
int result;
- if (fp->_IO_read_ptr > fp->_IO_read_base
+ if (fp->_IO_read_ptr > fp->_IO_read_base && !_IO_in_backup (fp)
&& (unsigned char)fp->_IO_read_ptr[-1] == (unsigned char)c)
{
fp->_IO_read_ptr--;
@@ -816,6 +816,12 @@ _IO_unbuffer_all (void)
legacy = 1;
#endif
+ /* Free up the backup area if it was ever allocated. */
+ if (_IO_have_backup (fp))
+ _IO_free_backup_area (fp);
+ if (!legacy && fp->_mode > 0 && _IO_have_wbackup (fp))
+ _IO_free_wbackup_area (fp);
+
if (! (fp->_flags & _IO_UNBUFFERED)
/* Iff stream is un-orientated, it wasn't used. */
&& (legacy || fp->_mode != 0))
diff --git a/libio/iopopen.c b/libio/iopopen.c
index d01cb0648e..352513a291 100644
--- a/libio/iopopen.c
+++ b/libio/iopopen.c
@@ -57,6 +57,26 @@ unlock (void *not_used)
}
#endif
+/* These lock/unlock/resetlock functions are used during fork. */
+
+void
+_IO_proc_file_chain_lock (void)
+{
+ _IO_lock_lock (proc_file_chain_lock);
+}
+
+void
+_IO_proc_file_chain_unlock (void)
+{
+ _IO_lock_unlock (proc_file_chain_lock);
+}
+
+void
+_IO_proc_file_chain_resetlock (void)
+{
+ _IO_lock_init (proc_file_chain_lock);
+}
+
/* POSIX states popen shall ensure that any streams from previous popen()
calls that remain open in the parent process should be closed in the new
child process.
diff --git a/libio/libioP.h b/libio/libioP.h
index 1af287b19f..a83a411fdf 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -429,6 +429,12 @@ libc_hidden_proto (_IO_list_resetlock)
extern void _IO_enable_locks (void) __THROW;
libc_hidden_proto (_IO_enable_locks)
+/* Functions for operating popen's proc_file_chain_lock during fork. */
+
+extern void _IO_proc_file_chain_lock (void) __THROW attribute_hidden;
+extern void _IO_proc_file_chain_unlock (void) __THROW attribute_hidden;
+extern void _IO_proc_file_chain_resetlock (void) __THROW attribute_hidden;
+
/* Default jumptable functions. */
extern int _IO_default_underflow (FILE *) __THROW;
@@ -577,8 +583,8 @@ extern void _IO_old_init (FILE *fp, int flags) __THROW;
((__fp)->_wide_data->_IO_write_base \
= (__fp)->_wide_data->_IO_write_ptr = __p, \
(__fp)->_wide_data->_IO_write_end = (__ep))
-#define _IO_have_backup(fp) ((fp)->_IO_save_base != NULL)
-#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_save_base != NULL)
+#define _IO_have_backup(fp) ((fp)->_IO_backup_base != NULL)
+#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_backup_base != NULL)
#define _IO_in_backup(fp) ((fp)->_flags & _IO_IN_BACKUP)
#define _IO_have_markers(fp) ((fp)->_markers != NULL)
#define _IO_blen(fp) ((fp)->_IO_buf_end - (fp)->_IO_buf_base)
diff --git a/libio/oldfileops.c b/libio/oldfileops.c
index 97148dba9b..8f775c9094 100644
--- a/libio/oldfileops.c
+++ b/libio/oldfileops.c
@@ -103,9 +103,11 @@ _IO_old_file_init_internal (struct _IO_FILE_plus *fp)
fp->file._old_offset = _IO_pos_BAD;
fp->file._flags |= CLOSED_FILEBUF_FLAGS;
- _IO_link_in (fp);
+ /* NB: _vtable_offset must be set before calling _IO_link_in since
+ _IO_vtable_offset is used to detect the old binaries. */
fp->file._vtable_offset = ((int) sizeof (struct _IO_FILE)
- (int) sizeof (struct _IO_FILE_complete));
+ _IO_link_in (fp);
fp->file._fileno = -1;
if (&_IO_stdin_used != NULL || !_IO_legacy_file ((FILE *) fp))
diff --git a/libio/tst-fopen-compat.c b/libio/tst-fopen-compat.c
new file mode 100644
index 0000000000..f241b61043
--- /dev/null
+++ b/libio/tst-fopen-compat.c
@@ -0,0 +1,85 @@
+/* Verify that fopen works with copy relocation on _IO_stderr_ in binaries
+ linked with glibc 2.0.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
+# define _LIBC
+# define _IO_USE_OLD_IO_FILE
+# include
+# include
+# include
+# include
+# include
+# include
+
+struct _IO_jump_t;
+
+struct _IO_FILE_plus
+{
+ FILE file;
+ const struct _IO_jump_t *vtable;
+};
+
+extern struct _IO_FILE_plus _IO_stderr_;
+compat_symbol_reference (libc, _IO_stderr_, _IO_stderr_, GLIBC_2_0);
+compat_symbol_reference (libc, fopen, fopen, GLIBC_2_0);
+compat_symbol_reference (libc, fclose, fclose, GLIBC_2_0);
+
+static int
+do_test (int argc, char *argv[])
+{
+ static char filename[PATH_MAX + 1];
+ struct stat st;
+ char *name = NULL;
+ int i;
+
+ /* Try to trigger copy relocation. */
+ TEST_VERIFY_EXIT (_IO_stderr_.file._fileno == STDERR_FILENO);
+
+ for (i = 1; i < argc; i++)
+ {
+ name = argv[i];
+ if (stat (name, &st) == 0)
+ {
+ TEST_VERIFY_EXIT (strlen (name) <= PATH_MAX);
+ break;
+ }
+ }
+ TEST_VERIFY_EXIT (name != NULL);
+
+ strcpy (filename, name);
+ FILE *fp = fopen (filename, "r");
+ TEST_VERIFY_EXIT (strcmp (filename, name) == 0);
+ TEST_VERIFY_EXIT (fp != NULL);
+ TEST_VERIFY_EXIT (fclose (fp) == 0);
+ return 0;
+}
+#else
+# include
+
+static int
+do_test (int argc, char *argv[])
+{
+ return EXIT_UNSUPPORTED;
+}
+#endif
+
+#define TEST_FUNCTION_ARGV do_test
+#include
diff --git a/libio/tst-popen-fork.c b/libio/tst-popen-fork.c
new file mode 100644
index 0000000000..1df30fc6c0
--- /dev/null
+++ b/libio/tst-popen-fork.c
@@ -0,0 +1,80 @@
+/* Test concurrent popen and fork.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+static void
+popen_and_pclose (void)
+{
+ FILE *f = popen ("true", "r");
+ TEST_VERIFY_EXIT (f != NULL);
+ pclose (f);
+ return;
+}
+
+static atomic_bool done = ATOMIC_VAR_INIT (0);
+
+static void *
+popen_and_pclose_forever (__attribute__ ((unused))
+ void *arg)
+{
+ while (!atomic_load_explicit (&done, memory_order_acquire))
+ popen_and_pclose ();
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+
+ /* Repeatedly call popen in a loop during the entire test. */
+ pthread_t t = xpthread_create (NULL, popen_and_pclose_forever, NULL);
+
+ /* Repeatedly fork off and reap child processes one-by-one.
+ Each child calls popen once, then exits, leading to the possibility
+ that a child forks *during* our own popen call, thus inheriting any
+ intermediate popen state, possibly including lock state(s). */
+ for (int i = 0; i < 100; i++)
+ {
+ int cpid = xfork ();
+
+ if (cpid == 0)
+ {
+ popen_and_pclose ();
+ _exit (0);
+ }
+ else
+ xwaitpid (cpid, NULL, 0);
+ }
+
+ /* Stop calling popen. */
+ atomic_store_explicit (&done, 1, memory_order_release);
+ xpthread_join (t);
+
+ return 0;
+}
+
+#include
diff --git a/locale/lc-ctype.c b/locale/lc-ctype.c
index c77ec51cb8..70556acaf0 100644
--- a/locale/lc-ctype.c
+++ b/locale/lc-ctype.c
@@ -64,12 +64,9 @@ _nl_postload_ctype (void)
in fact using the global locale. */
if (_NL_CURRENT_LOCALE == &_nl_global_locale)
{
- __libc_tsd_set (const uint16_t *, CTYPE_B,
- (void *) _nl_global_locale.__ctype_b);
- __libc_tsd_set (const int32_t *, CTYPE_TOUPPER,
- (void *) _nl_global_locale.__ctype_toupper);
- __libc_tsd_set (const int32_t *, CTYPE_TOLOWER,
- (void *) _nl_global_locale.__ctype_tolower);
+ __libc_tsd_CTYPE_B = _nl_global_locale.__ctype_b;
+ __libc_tsd_CTYPE_TOUPPER = _nl_global_locale.__ctype_toupper;
+ __libc_tsd_CTYPE_TOLOWER = _nl_global_locale.__ctype_tolower;
}
#include
diff --git a/locale/localeinfo.h b/locale/localeinfo.h
index ed698faef1..c3249d3715 100644
--- a/locale/localeinfo.h
+++ b/locale/localeinfo.h
@@ -236,10 +236,9 @@ extern struct __locale_struct _nl_global_locale attribute_hidden;
/* This fetches the thread-local locale_t pointer, either one set with
uselocale or &_nl_global_locale. */
-#define _NL_CURRENT_LOCALE (__libc_tsd_get (locale_t, LOCALE))
-#include
-__libc_tsd_define (extern, locale_t, LOCALE)
-
+#define _NL_CURRENT_LOCALE __libc_tsd_LOCALE
+extern __thread locale_t __libc_tsd_LOCALE
+ attribute_hidden attribute_tls_model_ie;
/* For static linking it is desireable to avoid always linking in the code
and data for every category when we can tell at link time that they are
diff --git a/locale/uselocale.c b/locale/uselocale.c
index 8136caf61b..0b247a77d5 100644
--- a/locale/uselocale.c
+++ b/locale/uselocale.c
@@ -34,7 +34,7 @@ __uselocale (locale_t newloc)
{
const locale_t locobj
= newloc == LC_GLOBAL_LOCALE ? &_nl_global_locale : newloc;
- __libc_tsd_set (locale_t, LOCALE, locobj);
+ __libc_tsd_LOCALE = locobj;
#ifdef NL_CURRENT_INDIRECT
/* Now we must update all the per-category thread-local variables to
@@ -62,11 +62,9 @@ __uselocale (locale_t newloc)
#endif
/* Update the special tsd cache of some locale data. */
- __libc_tsd_set (const uint16_t *, CTYPE_B, (void *) locobj->__ctype_b);
- __libc_tsd_set (const int32_t *, CTYPE_TOLOWER,
- (void *) locobj->__ctype_tolower);
- __libc_tsd_set (const int32_t *, CTYPE_TOUPPER,
- (void *) locobj->__ctype_toupper);
+ __libc_tsd_CTYPE_B = locobj->__ctype_b;
+ __libc_tsd_CTYPE_TOLOWER = locobj->__ctype_tolower;
+ __libc_tsd_CTYPE_TOUPPER = locobj->__ctype_toupper;
}
return oldloc == &_nl_global_locale ? LC_GLOBAL_LOCALE : oldloc;
diff --git a/locale/xlocale.c b/locale/xlocale.c
index f2b9d03303..d11c1cbf8c 100644
--- a/locale/xlocale.c
+++ b/locale/xlocale.c
@@ -18,18 +18,13 @@
#include
#include "localeinfo.h"
+#include
#define DEFINE_CATEGORY(category, category_name, items, a) \
extern struct __locale_data _nl_C_##category;
#include "categories.def"
#undef DEFINE_CATEGORY
-/* Defined in locale/C-ctype.c. */
-extern const char _nl_C_LC_CTYPE_class[] attribute_hidden;
-extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden;
-extern const char _nl_C_LC_CTYPE_tolower[] attribute_hidden;
-
-
const struct __locale_struct _nl_C_locobj attribute_hidden =
{
.__locales =
diff --git a/localedata/tst-ctype.c b/localedata/tst-ctype.c
index 9de979a2d7..a23689719c 100644
--- a/localedata/tst-ctype.c
+++ b/localedata/tst-ctype.c
@@ -21,6 +21,8 @@
#include
#include
+#include
+
static const char lower[] = "abcdefghijklmnopqrstuvwxyz";
static const char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -53,19 +55,11 @@ static struct classes
#define nclasses (sizeof (classes) / sizeof (classes[0]))
-#define FAIL(str, args...) \
- { \
- printf (" " str "\n", ##args); \
- ++errors; \
- }
-
-
static int
do_test (void)
{
const char *cp;
const char *cp2;
- int errors = 0;
char *inpline = NULL;
size_t inplinelen = 0;
char *resline = NULL;
@@ -394,11 +388,8 @@ punct = %04x alnum = %04x\n",
{
if (((__ctype_b[(unsigned int) *inp] & classes[n].mask) != 0)
!= (*resp != '0'))
- {
- printf (" is%s('%c' = '\\x%02x') %s true\n", inpline,
- *inp, *inp, *resp == '1' ? "not" : "is");
- ++errors;
- }
+ FAIL (" is%s('%c' = '\\x%02x') %s true\n", inpline,
+ *inp, *inp, *resp == '1' ? "not" : "is");
++inp;
++resp;
}
@@ -408,11 +399,8 @@ punct = %04x alnum = %04x\n",
while (*inp != '\0')
{
if (tolower (*inp) != *resp)
- {
- printf (" tolower('%c' = '\\x%02x') != '%c'\n",
- *inp, *inp, *resp);
- ++errors;
- }
+ FAIL (" tolower('%c' = '\\x%02x') != '%c'\n",
+ *inp, *inp, *resp);
++inp;
++resp;
}
@@ -422,11 +410,8 @@ punct = %04x alnum = %04x\n",
while (*inp != '\0')
{
if (toupper (*inp) != *resp)
- {
- printf (" toupper('%c' = '\\x%02x') != '%c'\n",
- *inp, *inp, *resp);
- ++errors;
- }
+ FAIL (" toupper('%c' = '\\x%02x') != '%c'\n",
+ *inp, *inp, *resp);
++inp;
++resp;
}
@@ -436,14 +421,7 @@ punct = %04x alnum = %04x\n",
}
- if (errors != 0)
- {
- printf (" %d error%s for `%s' locale\n\n\n", errors,
- errors == 1 ? "" : "s", setlocale (LC_ALL, NULL));
- return 1;
- }
-
- printf (" No errors for `%s' locale\n\n\n", setlocale (LC_ALL, NULL));
+ printf ("Completed testing for `%s' locale\n\n\n", setlocale (LC_ALL, NULL));
return 0;
}
diff --git a/malloc/Makefile b/malloc/Makefile
index 02aff1bd1d..98d507a6eb 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -28,6 +28,8 @@ tests := \
mallocbug \
tst-aligned-alloc \
tst-aligned-alloc-random \
+ tst-aligned-alloc-random-thread \
+ tst-aligned-alloc-random-thread-cross \
tst-alloc_buffer \
tst-calloc \
tst-free-errno \
@@ -151,6 +153,8 @@ ifeq ($(have-GLIBC_2.23)$(build-shared),yesyes)
# the tests expect specific internal behavior that is changed due to linking to
# libmcheck.a.
tests-exclude-mcheck = \
+ tst-aligned-alloc-random-thread \
+ tst-aligned-alloc-random-thread-cross \
tst-compathooks-off \
tst-compathooks-on \
tst-malloc-backtrace \
@@ -415,7 +419,11 @@ $(objpfx)tst-mallocstate: $(objpfx)libc_malloc_debug.so
$(objpfx)tst-mallocstate-malloc-check: $(objpfx)libc_malloc_debug.so
$(objpfx)tst-aligned-alloc-random.out: $(objpfx)tst-aligned_alloc-lib.so
+$(objpfx)tst-aligned-alloc-random-thread.out: $(objpfx)tst-aligned_alloc-lib.so
+$(objpfx)tst-aligned-alloc-random-thread-cross.out: $(objpfx)tst-aligned_alloc-lib.so
$(objpfx)tst-malloc-random.out: $(objpfx)tst-aligned_alloc-lib.so
tst-aligned-alloc-random-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
+tst-aligned-alloc-random-thread-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
+tst-aligned-alloc-random-thread-cross-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
tst-malloc-random-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
diff --git a/malloc/tst-aligned-alloc-random-thread-cross.c b/malloc/tst-aligned-alloc-random-thread-cross.c
new file mode 100644
index 0000000000..360ecc56ee
--- /dev/null
+++ b/malloc/tst-aligned-alloc-random-thread-cross.c
@@ -0,0 +1,19 @@
+/* multi-threaded memory allocation and cross-thread deallocation test.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, see . */
+#define CROSS_THREAD_DEALLOC
+#include "tst-aligned-alloc-random-thread.c"
diff --git a/malloc/tst-aligned-alloc-random-thread.c b/malloc/tst-aligned-alloc-random-thread.c
new file mode 100644
index 0000000000..e95f79250a
--- /dev/null
+++ b/malloc/tst-aligned-alloc-random-thread.c
@@ -0,0 +1,145 @@
+/* multi-threaded memory allocation/deallocation test.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, see . */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef ITERATIONS
+# define ITERATIONS 16
+#endif
+
+#ifndef NUM_THREADS
+# define NUM_THREADS 8
+#endif
+
+#ifndef NUM_ALLOCATIONS
+# define NUM_ALLOCATIONS 2048
+#endif
+
+static pthread_barrier_t barrier;
+
+__thread unsigned int seed;
+
+typedef struct
+{
+ int id;
+ pthread_t thread;
+} thread;
+
+thread threads[NUM_THREADS];
+
+void *allocations[NUM_THREADS][NUM_ALLOCATIONS];
+
+void
+run_thread_dealloc (int id)
+{
+ for (int i = 0; i < NUM_ALLOCATIONS; i++)
+ {
+ free (allocations[id][i]);
+ allocations[id][i] = NULL;
+ }
+}
+
+void
+run_thread_alloc (int id)
+{
+ size_t msb, size;
+ for (int i = 0; i < NUM_ALLOCATIONS; i++)
+ {
+ msb = 1 << rand_r (&seed) % 16;
+ size = msb + rand_r (&seed) % msb;
+ allocations[id][i] = malloc (size);
+ TEST_VERIFY_EXIT (allocations[id][i] != NULL);
+ }
+}
+
+void *
+run_allocations (void *arg)
+{
+ int id = *((int *) arg);
+ seed = time (NULL) + id;
+
+ /* Stage 1: First half o the threads allocating memory and the second
+ * half waiting for them to finish
+ */
+ if (id < NUM_THREADS / 2)
+ run_thread_alloc (id);
+
+ xpthread_barrier_wait (&barrier);
+
+ /* Stage 2: Half of the threads allocationg memory and the other
+ * half deallocating:
+ * - In the non cross-thread dealloc scenario the first half will be
+ * deallocating the memory allocated by themselves in stage 1 and the
+ * second half will be allocating memory.
+ * - In the cross-thread dealloc scenario the first half will continue
+ * to allocate memory and the second half will deallocate the memory
+ * allocated by the first half in stage 1.
+ */
+ if (id < NUM_THREADS / 2)
+#ifndef CROSS_THREAD_DEALLOC
+ run_thread_dealloc (id);
+#else
+ run_thread_alloc (id + NUM_THREADS / 2);
+#endif
+ else
+#ifndef CROSS_THREAD_DEALLOC
+ run_thread_alloc (id);
+#else
+ run_thread_dealloc (id - NUM_THREADS / 2);
+#endif
+
+ xpthread_barrier_wait (&barrier);
+
+ // Stage 3: Second half of the threads deallocating and the first half
+ // waiting for them to finish.
+ if (id >= NUM_THREADS / 2)
+ run_thread_dealloc (id);
+
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
+
+ for (int i = 0; i < ITERATIONS; i++)
+ {
+ for (int t = 0; t < NUM_THREADS; t++)
+ {
+ threads[t].id = t;
+ threads[t].thread
+ = xpthread_create (NULL, run_allocations, &threads[t].id);
+ }
+
+ for (int t = 0; t < NUM_THREADS; t++)
+ xpthread_join (threads[t].thread);
+ }
+
+ return 0;
+}
+
+#include
diff --git a/malloc/tst-aligned-alloc.c b/malloc/tst-aligned-alloc.c
index 91167d1392..b0f05a8fec 100644
--- a/malloc/tst-aligned-alloc.c
+++ b/malloc/tst-aligned-alloc.c
@@ -25,6 +25,8 @@
#include
#include
+#include "tst-malloc-aux.h"
+
static int
do_test (void)
{
diff --git a/malloc/tst-aligned_alloc-lib.c b/malloc/tst-aligned_alloc-lib.c
index 0205df5acf..9ef1f839c1 100644
--- a/malloc/tst-aligned_alloc-lib.c
+++ b/malloc/tst-aligned_alloc-lib.c
@@ -17,37 +17,38 @@
License along with the GNU C Library; see the file COPYING.LIB. If
not, see . */
-#include
#include
#include
+#include
extern void *__libc_malloc (size_t size);
extern void *__libc_calloc (size_t n, size_t size);
+__thread unsigned int seed = 0;
+
int aligned_alloc_count = 0;
int libc_malloc_count = 0;
int libc_calloc_count = 0;
-/* Get a random alignment value. Biased towards the smaller values. Must be
- a power of 2. */
-static size_t get_random_alignment (void)
-{
- size_t aligns[] = {
- 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384
- };
-
- return aligns[random () % array_length (aligns)];
-}
-
-static void *get_random_alloc (size_t size)
+static void *
+get_random_alloc (size_t size)
{
void *retval;
size_t align;
+ struct timespec tp;
+
+ if (seed == 0)
+ {
+ clock_gettime (CLOCK_REALTIME, &tp);
+ seed = tp.tv_nsec;
+ }
- switch (random() % 3)
- {
+ switch (rand_r (&seed) % 3)
+ {
case 1:
- align = get_random_alignment ();
+ /* Get a random alignment value. Biased towards the smaller
+ * values up to 16384. Must be a power of 2. */
+ align = 1 << rand_r (&seed) % 15;
retval = aligned_alloc (align, size);
aligned_alloc_count++;
break;
@@ -59,13 +60,13 @@ static void *get_random_alloc (size_t size)
retval = __libc_malloc (size);
libc_malloc_count++;
break;
- }
+ }
return retval;
}
-
-void * __random_malloc (size_t size)
+void *
+__random_malloc (size_t size)
{
return get_random_alloc (size);
}
diff --git a/malloc/tst-calloc.c b/malloc/tst-calloc.c
index 01f17f9e65..5a8c7ab121 100644
--- a/malloc/tst-calloc.c
+++ b/malloc/tst-calloc.c
@@ -23,6 +23,7 @@
#include
#include
+#include "tst-malloc-aux.h"
/* Number of samples per size. */
#define N 50000
@@ -94,16 +95,19 @@ random_test (void)
static void
null_test (void)
{
+ /* Obscure allocation size from the compiler. */
+ volatile size_t max_size = UINT_MAX;
+ volatile size_t zero_size = 0;
/* If the size is 0 the result is implementation defined. Just make
sure the program doesn't crash. The result of calloc is
deliberately ignored, so do not warn about that. */
DIAG_PUSH_NEEDS_COMMENT;
DIAG_IGNORE_NEEDS_COMMENT (10, "-Wunused-result");
calloc (0, 0);
- calloc (0, UINT_MAX);
- calloc (UINT_MAX, 0);
- calloc (0, ~((size_t) 0));
- calloc (~((size_t) 0), 0);
+ calloc (0, max_size);
+ calloc (max_size, 0);
+ calloc (0, ~((size_t) zero_size));
+ calloc (~((size_t) zero_size), 0);
DIAG_POP_NEEDS_COMMENT;
}
diff --git a/malloc/tst-compathooks-off.c b/malloc/tst-compathooks-off.c
index d0106f3fb7..4cce6e5a80 100644
--- a/malloc/tst-compathooks-off.c
+++ b/malloc/tst-compathooks-off.c
@@ -25,6 +25,8 @@
#include
#include
+#include "tst-malloc-aux.h"
+
extern void (*volatile __free_hook) (void *, const void *);
extern void *(*volatile __malloc_hook)(size_t, const void *);
extern void *(*volatile __realloc_hook)(void *, size_t, const void *);
diff --git a/malloc/tst-mallinfo2.c b/malloc/tst-mallinfo2.c
index 2c02f5f700..f072b9f24b 100644
--- a/malloc/tst-mallinfo2.c
+++ b/malloc/tst-mallinfo2.c
@@ -23,6 +23,8 @@
#include
#include
+#include "tst-malloc-aux.h"
+
/* This is not specifically needed for the test, but (1) does
something to the data so gcc doesn't optimize it away, and (2) may
help when developing future tests. */
diff --git a/malloc/tst-malloc-aux.h b/malloc/tst-malloc-aux.h
new file mode 100644
index 0000000000..3e1b61ce34
--- /dev/null
+++ b/malloc/tst-malloc-aux.h
@@ -0,0 +1,56 @@
+/* Wrappers for malloc-like functions to allow testing the implementation
+ without optimization.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, see . */
+
+#ifndef TST_MALLOC_AUX_H
+#define TST_MALLOC_AUX_H
+
+#include
+#include
+#include
+
+static __typeof (aligned_alloc) * volatile aligned_alloc_indirect
+ = aligned_alloc;
+static __typeof (calloc) * volatile calloc_indirect = calloc;
+static __typeof (malloc) * volatile malloc_indirect = malloc;
+static __typeof (memalign) * volatile memalign_indirect = memalign;
+static __typeof (posix_memalign) * volatile posix_memalign_indirect
+ = posix_memalign;
+static __typeof (pvalloc) * volatile pvalloc_indirect = pvalloc;
+static __typeof (realloc) * volatile realloc_indirect = realloc;
+static __typeof (valloc) * volatile valloc_indirect = valloc;
+
+#undef aligned_alloc
+#undef calloc
+#undef malloc
+#undef memalign
+#undef posix_memalign
+#undef pvalloc
+#undef realloc
+#undef valloc
+
+#define aligned_alloc aligned_alloc_indirect
+#define calloc calloc_indirect
+#define malloc malloc_indirect
+#define memalign memalign_indirect
+#define posix_memalign posix_memalign_indirect
+#define pvalloc pvalloc_indirect
+#define realloc realloc_indirect
+#define valloc valloc_indirect
+
+#endif /* TST_MALLOC_AUX_H */
diff --git a/malloc/tst-malloc-backtrace.c b/malloc/tst-malloc-backtrace.c
index c7b1d65e5c..65fa91f6fd 100644
--- a/malloc/tst-malloc-backtrace.c
+++ b/malloc/tst-malloc-backtrace.c
@@ -22,6 +22,8 @@
#include
#include
+#include "tst-malloc-aux.h"
+
#define SIZE 4096
/* Wrap free with a function to prevent gcc from optimizing it out. */
diff --git a/malloc/tst-malloc-check.c b/malloc/tst-malloc-check.c
index fde8863ad7..cc88bff3b3 100644
--- a/malloc/tst-malloc-check.c
+++ b/malloc/tst-malloc-check.c
@@ -20,6 +20,8 @@
#include
#include
+#include "tst-malloc-aux.h"
+
static int errors = 0;
static void
diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c
index 8e9e0d5fa2..2b91377e54 100644
--- a/malloc/tst-malloc-too-large.c
+++ b/malloc/tst-malloc-too-large.c
@@ -43,6 +43,7 @@
#include
#include
+#include "tst-malloc-aux.h"
/* This function prepares for each 'too-large memory allocation' test by
performing a small successful malloc/free and resetting errno prior to
diff --git a/malloc/tst-malloc.c b/malloc/tst-malloc.c
index f7a6e4654c..68af399022 100644
--- a/malloc/tst-malloc.c
+++ b/malloc/tst-malloc.c
@@ -22,6 +22,8 @@
#include
#include
+#include "tst-malloc-aux.h"
+
static int errors = 0;
static void
diff --git a/malloc/tst-memalign.c b/malloc/tst-memalign.c
index 563f6413d2..ac9770d3f9 100644
--- a/malloc/tst-memalign.c
+++ b/malloc/tst-memalign.c
@@ -23,6 +23,8 @@
#include
#include
+#include "tst-malloc-aux.h"
+
static int errors = 0;
static void
diff --git a/malloc/tst-realloc.c b/malloc/tst-realloc.c
index f50499ecb1..74a28fb45e 100644
--- a/malloc/tst-realloc.c
+++ b/malloc/tst-realloc.c
@@ -23,6 +23,8 @@
#include
#include
+#include "tst-malloc-aux.h"
+
static int
do_test (void)
{
diff --git a/malloc/tst-safe-linking.c b/malloc/tst-safe-linking.c
index 01dd07004d..63a7e2bc8e 100644
--- a/malloc/tst-safe-linking.c
+++ b/malloc/tst-safe-linking.c
@@ -26,6 +26,8 @@
#include
#include
+#include "tst-malloc-aux.h"
+
/* Run CALLBACK and check that the data on standard error equals
EXPECTED. */
static void
diff --git a/malloc/tst-valloc.c b/malloc/tst-valloc.c
index 9bab8c6470..0243d3dfd4 100644
--- a/malloc/tst-valloc.c
+++ b/malloc/tst-valloc.c
@@ -23,6 +23,8 @@
#include
#include
+#include "tst-malloc-aux.h"
+
static int errors = 0;
static void
diff --git a/manual/dynlink.texi b/manual/dynlink.texi
index 03565d4fb0..1500a53de6 100644
--- a/manual/dynlink.texi
+++ b/manual/dynlink.texi
@@ -993,21 +993,21 @@ The dynamic segment should also mention @code{BIND_NOW} on the
enough).
@item
-For shared objects (not main programs), if the program header has a
-@code{PT_TLS} segment, the dynamic segment (as shown by @samp{readelf
--dW}) should contain the @code{STATIC_TLS} flag on the @code{FLAGS}
-line.
-
-If @code{STATIC_TLS} is missing in shared objects, ensure that the
-appropriate relocations for GNU2 TLS descriptors are used (for example,
+Ensure that only static TLS relocations (thread-pointer relative offset
+locations) are used, for example @code{R_AARCH64_TLS_TPREL} and
+@code{X86_64_TPOFF64}. As the second-best option, and only if
+compatibility with non-hardened applications using @code{dlopen} is
+needed, GNU2 TLS descriptor relocations can be used (for example,
@code{R_AARCH64_TLSDESC} or @code{R_X86_64_TLSDESC}).
@item
-There should not be a reference to the symbols @code{__tls_get_addr},
-@code{__tls_get_offset}, @code{__tls_get_addr_opt} in the dynamic symbol
-table (in the @samp{readelf -sDW} output). Thread-local storage must be
-accessed using the initial-exec (static) model, or using GNU2 TLS
-descriptors.
+There should not be references to the traditional TLS function symbols
+@code{__tls_get_addr}, @code{__tls_get_offset},
+@code{__tls_get_addr_opt} in the dynamic symbol table (in the
+@samp{readelf -sDW} output). Supporting global dynamic TLS relocations
+(such as @code{R_AARCH64_TLS_DTPMOD}, @code{R_AARCH64_TLS_DTPREL},
+@code{R_X86_64_DTPMOD64}, @code{R_X86_64_DTPOFF64}) should not be used,
+either.
@item
Likewise, the functions @code{dlopen}, @code{dlmopen}, @code{dlclose}
diff --git a/manual/llio.texi b/manual/llio.texi
index 6f0a48609b..ea84196abd 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -1892,7 +1892,7 @@ There is no existing mapping in at least part of the given region.
@end deftypefun
-@deftypefun {void *} mremap (void *@var{address}, size_t @var{length}, size_t @var{new_length}, int @var{flag})
+@deftypefun {void *} mremap (void *@var{address}, size_t @var{length}, size_t @var{new_length}, int @var{flag}, ... /* void *@var{new_address} */)
@standards{GNU, sys/mman.h}
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
@@ -1901,12 +1901,40 @@ area. @var{address} and @var{length} must cover a region entirely mapped
in the same @code{mmap} statement. A new mapping with the same
characteristics will be returned with the length @var{new_length}.
-One option is possible, @code{MREMAP_MAYMOVE}. If it is given in
-@var{flags}, the system may remove the existing mapping and create a new
-one of the desired length in another location.
+Possible flags are
-The address of the resulting mapping is returned, or @math{-1}. Possible
-error codes include:
+@table @code
+
+@item MREMAP_MAYMOVE
+If it is given in @var{flags}, the system may remove the existing mapping
+and create a new one of the desired length in another location.
+
+@item MREMAP_FIXED
+If it is given in @var{flags}, @code{mremap} accepts a fifth argument,
+@code{void *new_address}, which specifies a page-aligned address to
+which the mapping must be moved. Any previous mapping at the address
+range specified by @var{new_address} and @var{new_size} is unmapped.
+
+@code{MREMAP_FIXED} must be used together with @code{MREMAP_MAYMOVE}.
+
+@item MREMAP_DONTUNMAP
+If it is given in @var{flags}, @code{mremap} accepts a fifth argument,
+@code{void *new_address}, which specifies a page-aligned address. Any
+previous mapping at the address range specified by @var{new_address} and
+@var{new_size} is unmapped. If @var{new_address} is @code{NULL}, the
+kernel chooses the page-aligned address at which to create the mapping.
+Otherwise, the kernel takes it as a hint about where to place the mapping.
+The mapping at the address range specified by @var{old_address} and
+@var{old_size} isn't unmapped.
+
+@code{MREMAP_DONTUNMAP} must be used together with @code{MREMAP_MAYMOVE}.
+@var{old_size} must be the same as @var{new_size}. This flag bit is
+Linux-specific.
+
+@end table
+
+The address of the resulting mapping is returned, or @code{MAP_FAILED}.
+Possible error codes include:
@table @code
@@ -1915,7 +1943,7 @@ There is no existing mapping in at least part of the original region, or
the region covers two or more distinct mappings.
@item EINVAL
-The address given is misaligned or inappropriate.
+Any arguments are inappropriate, including unknown @var{flags} values.
@item EAGAIN
The region has pages locked, and if extended it would exceed the
diff --git a/manual/resource.texi b/manual/resource.texi
index c9b21dedeb..25966bcb64 100644
--- a/manual/resource.texi
+++ b/manual/resource.texi
@@ -192,8 +192,8 @@ If the sources are compiled with @code{_FILE_OFFSET_BITS == 64} on a
@standards{BSD, sys/resource.h}
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
@c Direct syscall on most systems; lock-taking critical section on HURD.
-Store the current and maximum limits for the resource @var{resource}
-in @code{*@var{rlp}}.
+Change the current and maximum limits of the process for the resource
+@var{resource} to the values provided in @code{*@var{rlp}}.
The return value is @code{0} on success and @code{-1} on failure. The
following @code{errno} error condition is possible:
diff --git a/manual/stdio.texi b/manual/stdio.texi
index f5e289d58a..92614775fa 100644
--- a/manual/stdio.texi
+++ b/manual/stdio.texi
@@ -903,21 +903,17 @@ This function is a GNU extension.
@deftypefun int putc (int @var{c}, FILE *@var{stream})
@standards{ISO, stdio.h}
@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{} @aculock{}}}
-This is just like @code{fputc}, except that most systems implement it as
-a macro, making it faster. One consequence is that it may evaluate the
-@var{stream} argument more than once, which is an exception to the
-general rule for macros. @code{putc} is usually the best function to
-use for writing a single character.
+This is just like @code{fputc}, except that it may be implemented as
+a macro and may evaluate the @var{stream} argument more than once.
+Therefore, @var{stream} should never be an expression with side-effects.
@end deftypefun
@deftypefun wint_t putwc (wchar_t @var{wc}, FILE *@var{stream})
@standards{ISO, wchar.h}
@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{} @aculock{}}}
-This is just like @code{fputwc}, except that it can be implement as
-a macro, making it faster. One consequence is that it may evaluate the
-@var{stream} argument more than once, which is an exception to the
-general rule for macros. @code{putwc} is usually the best function to
-use for writing a single wide character.
+This is just like @code{fputwc}, except that it may be implemented as
+a macro and may evaluate the @var{stream} argument more than once.
+Therefore, @var{stream} should never be an expression with side-effects.
@end deftypefun
@deftypefun int putc_unlocked (int @var{c}, FILE *@var{stream})
@@ -1110,20 +1106,17 @@ This function is a GNU extension.
@deftypefun int getc (FILE *@var{stream})
@standards{ISO, stdio.h}
@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@aculock{} @acucorrupt{}}}
-This is just like @code{fgetc}, except that it is permissible (and
-typical) for it to be implemented as a macro that evaluates the
-@var{stream} argument more than once. @code{getc} is often highly
-optimized, so it is usually the best function to use to read a single
-character.
+This is just like @code{fgetc}, except that it may be implemented as
+a macro and may evaluate the @var{stream} argument more than once.
+Therefore, @var{stream} should never be an expression with side-effects.
@end deftypefun
@deftypefun wint_t getwc (FILE *@var{stream})
@standards{ISO, wchar.h}
@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@aculock{} @acucorrupt{}}}
-This is just like @code{fgetwc}, except that it is permissible for it to
-be implemented as a macro that evaluates the @var{stream} argument more
-than once. @code{getwc} can be highly optimized, so it is usually the
-best function to use to read a single wide character.
+This is just like @code{fgetwc}, except that it may be implemented as
+a macro and may evaluate the @var{stream} argument more than once.
+Therefore, @var{stream} should never be an expression with side-effects.
@end deftypefun
@deftypefun int getc_unlocked (FILE *@var{stream})
@@ -1474,11 +1467,9 @@ program; usually @code{ungetc} is used only to unread a character that
was just read from the same stream. @Theglibc{} supports this
even on files opened in binary mode, but other systems might not.
-@Theglibc{} only supports one character of pushback---in other
-words, it does not work to call @code{ungetc} twice without doing input
-in between. Other systems might let you push back multiple characters;
-then reading from the stream retrieves the characters in the reverse
-order that they were pushed.
+@Theglibc{} supports pushing back multiple characters; subsequently
+reading from the stream retrieves the characters in the reverse order
+that they were pushed.
Pushing back characters doesn't alter the file; only the internal
buffering for the stream is affected. If a file positioning function
diff --git a/math/Makefile b/math/Makefile
index f06d370383..b64c3eedd5 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -1077,6 +1077,7 @@ CFLAGS-test-flt-eval-method.c += -fexcess-precision=standard
CFLAGS-test-fe-snans-always-signal.c += $(config-cflags-signaling-nans)
CFLAGS-test-nan-const.c += -fno-builtin
+CFLAGS-test-nan-payload.c += -fno-builtin
CFLAGS-test-ceil-except-2.c += -fno-builtin
CFLAGS-test-floor-except-2.c += -fno-builtin
diff --git a/math/auto-libm-test-in b/math/auto-libm-test-in
index 8f0c3d87bb..7100171346 100644
--- a/math/auto-libm-test-in
+++ b/math/auto-libm-test-in
@@ -5555,7 +5555,7 @@ exp2m1 -0x1p-1021
exp2m1 -0x1p-16381
expm1 0
-expm1 -0 no-mathvec
+expm1 -0
expm1 1
expm1 0.75
expm1 2
@@ -5620,7 +5620,7 @@ expm1 -0x1p-100
expm1 0x1p-600
expm1 -0x1p-600
expm1 0x1p-10000
-expm1 -0x1p-10000 no-mathvec
+expm1 -0x1p-10000
expm1 0xe.4152ac57cd1ea7ap-60
expm1 0x6.660247486aed8p-4
expm1 0x6.289a78p-4
@@ -6835,7 +6835,7 @@ log10p1 -0x6.3fef3067427e43dfcde9e48f74bcp-4
log10p1 0x6.af53d00fd2845d4772260ef5adc4p-4
log1p 0
-log1p -0 no-mathvec
+log1p -0
log1p e-1
log1p -0.25
log1p -0.875
@@ -7627,7 +7627,7 @@ pow 0x1.7ac7cp+5 23
pow -0x1.7ac7cp+5 23
sin 0
-sin -0 no-mathvec
+sin -0
sin pi/6
sin -pi/6
sin pi/2
@@ -7964,7 +7964,7 @@ sqrt min
sqrt min_subnorm
tan 0
-tan -0 no-mathvec
+tan -0
tan pi/4
tan pi/2
tan -pi/2
@@ -8056,7 +8056,7 @@ tan min_subnorm
tan -min_subnorm
tanh 0
-tanh -0 no-mathvec
+tanh -0
tanh 0.75
tanh -0.75
tanh 1.0
diff --git a/math/auto-libm-test-out-expm1 b/math/auto-libm-test-out-expm1
index 91da41b7f6..8483455801 100644
--- a/math/auto-libm-test-out-expm1
+++ b/math/auto-libm-test-out-expm1
@@ -23,31 +23,31 @@ expm1 0
= expm1 tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= expm1 towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= expm1 upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok
-expm1 -0 no-mathvec
-= expm1 downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
+expm1 -0
+= expm1 downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
expm1 1
= expm1 downward binary32 0x1p+0 : 0x1.b7e15p+0 : inexact-ok
= expm1 tonearest binary32 0x1p+0 : 0x1.b7e152p+0 : inexact-ok
@@ -1880,87 +1880,87 @@ expm1 0x1p-10000
= expm1 tonearest binary128 0x1p-10000 : 0x1p-10000 : inexact-ok
= expm1 towardzero binary128 0x1p-10000 : 0x1p-10000 : inexact-ok
= expm1 upward binary128 0x1p-10000 : 0x1.0000000000000000000000000001p-10000 : inexact-ok
-expm1 -0x1p-10000 no-mathvec
-= expm1 downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= expm1 downward binary32 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 tonearest binary32 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 towardzero binary32 -0x8p-152 : -0x0p+0 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 upward binary32 -0x8p-152 : -0x0p+0 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 downward binary64 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 tonearest binary64 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 towardzero binary64 -0x8p-152 : -0x7.ffffffffffffcp-152 : no-mathvec inexact-ok
-= expm1 upward binary64 -0x8p-152 : -0x7.ffffffffffffcp-152 : no-mathvec inexact-ok
-= expm1 downward intel96 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 tonearest intel96 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 towardzero intel96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : no-mathvec inexact-ok
-= expm1 upward intel96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : no-mathvec inexact-ok
-= expm1 downward m68k96 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 tonearest m68k96 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 towardzero m68k96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : no-mathvec inexact-ok
-= expm1 upward m68k96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : no-mathvec inexact-ok
-= expm1 downward binary128 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 tonearest binary128 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 towardzero binary128 -0x8p-152 : -0x7.fffffffffffffffffffffffffffcp-152 : no-mathvec inexact-ok
-= expm1 upward binary128 -0x8p-152 : -0x7.fffffffffffffffffffffffffffcp-152 : no-mathvec inexact-ok
-= expm1 downward ibm128 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 tonearest ibm128 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok
-= expm1 towardzero ibm128 -0x8p-152 : -0x7.fffffffffffffffffffffffffep-152 : no-mathvec inexact-ok
-= expm1 upward ibm128 -0x8p-152 : -0x7.fffffffffffffffffffffffffep-152 : no-mathvec inexact-ok
-= expm1 downward binary64 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 tonearest binary64 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 towardzero binary64 -0x4p-1076 : -0x0p+0 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 upward binary64 -0x4p-1076 : -0x0p+0 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 downward intel96 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok
-= expm1 tonearest intel96 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok
-= expm1 towardzero intel96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : no-mathvec inexact-ok
-= expm1 upward intel96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : no-mathvec inexact-ok
-= expm1 downward m68k96 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok
-= expm1 tonearest m68k96 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok
-= expm1 towardzero m68k96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : no-mathvec inexact-ok
-= expm1 upward m68k96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : no-mathvec inexact-ok
-= expm1 downward binary128 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok
-= expm1 tonearest binary128 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok
-= expm1 towardzero binary128 -0x4p-1076 : -0x3.fffffffffffffffffffffffffffep-1076 : no-mathvec inexact-ok
-= expm1 upward binary128 -0x4p-1076 : -0x3.fffffffffffffffffffffffffffep-1076 : no-mathvec inexact-ok
-= expm1 downward ibm128 -0x4p-1076 : -0x4p-1076 : no-mathvec xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok
-= expm1 tonearest ibm128 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok underflow errno-erange-ok
-= expm1 towardzero ibm128 -0x4p-1076 : -0x0p+0 : no-mathvec xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok
-= expm1 upward ibm128 -0x4p-1076 : -0x0p+0 : no-mathvec xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok
-= expm1 downward intel96 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok
-= expm1 tonearest intel96 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok
-= expm1 towardzero intel96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : no-mathvec inexact-ok
-= expm1 upward intel96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : no-mathvec inexact-ok
-= expm1 downward m68k96 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok
-= expm1 tonearest m68k96 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok
-= expm1 towardzero m68k96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : no-mathvec inexact-ok
-= expm1 upward m68k96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : no-mathvec inexact-ok
-= expm1 downward binary128 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok
-= expm1 tonearest binary128 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok
-= expm1 towardzero binary128 -0x1p-10000 : -0xf.fffffffffffffffffffffffffff8p-10004 : no-mathvec inexact-ok
-= expm1 upward binary128 -0x1p-10000 : -0xf.fffffffffffffffffffffffffff8p-10004 : no-mathvec inexact-ok
+expm1 -0x1p-10000
+= expm1 downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= expm1 downward binary32 -0x8p-152 : -0x8p-152 : inexact-ok underflow errno-erange-ok
+= expm1 tonearest binary32 -0x8p-152 : -0x8p-152 : inexact-ok underflow errno-erange-ok
+= expm1 towardzero binary32 -0x8p-152 : -0x0p+0 : inexact-ok underflow errno-erange-ok
+= expm1 upward binary32 -0x8p-152 : -0x0p+0 : inexact-ok underflow errno-erange-ok
+= expm1 downward binary64 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 tonearest binary64 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 towardzero binary64 -0x8p-152 : -0x7.ffffffffffffcp-152 : inexact-ok
+= expm1 upward binary64 -0x8p-152 : -0x7.ffffffffffffcp-152 : inexact-ok
+= expm1 downward intel96 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 tonearest intel96 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 towardzero intel96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : inexact-ok
+= expm1 upward intel96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : inexact-ok
+= expm1 downward m68k96 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 tonearest m68k96 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 towardzero m68k96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : inexact-ok
+= expm1 upward m68k96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : inexact-ok
+= expm1 downward binary128 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 tonearest binary128 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 towardzero binary128 -0x8p-152 : -0x7.fffffffffffffffffffffffffffcp-152 : inexact-ok
+= expm1 upward binary128 -0x8p-152 : -0x7.fffffffffffffffffffffffffffcp-152 : inexact-ok
+= expm1 downward ibm128 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 tonearest ibm128 -0x8p-152 : -0x8p-152 : inexact-ok
+= expm1 towardzero ibm128 -0x8p-152 : -0x7.fffffffffffffffffffffffffep-152 : inexact-ok
+= expm1 upward ibm128 -0x8p-152 : -0x7.fffffffffffffffffffffffffep-152 : inexact-ok
+= expm1 downward binary64 -0x4p-1076 : -0x4p-1076 : inexact-ok underflow errno-erange-ok
+= expm1 tonearest binary64 -0x4p-1076 : -0x4p-1076 : inexact-ok underflow errno-erange-ok
+= expm1 towardzero binary64 -0x4p-1076 : -0x0p+0 : inexact-ok underflow errno-erange-ok
+= expm1 upward binary64 -0x4p-1076 : -0x0p+0 : inexact-ok underflow errno-erange-ok
+= expm1 downward intel96 -0x4p-1076 : -0x4p-1076 : inexact-ok
+= expm1 tonearest intel96 -0x4p-1076 : -0x4p-1076 : inexact-ok
+= expm1 towardzero intel96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : inexact-ok
+= expm1 upward intel96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : inexact-ok
+= expm1 downward m68k96 -0x4p-1076 : -0x4p-1076 : inexact-ok
+= expm1 tonearest m68k96 -0x4p-1076 : -0x4p-1076 : inexact-ok
+= expm1 towardzero m68k96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : inexact-ok
+= expm1 upward m68k96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : inexact-ok
+= expm1 downward binary128 -0x4p-1076 : -0x4p-1076 : inexact-ok
+= expm1 tonearest binary128 -0x4p-1076 : -0x4p-1076 : inexact-ok
+= expm1 towardzero binary128 -0x4p-1076 : -0x3.fffffffffffffffffffffffffffep-1076 : inexact-ok
+= expm1 upward binary128 -0x4p-1076 : -0x3.fffffffffffffffffffffffffffep-1076 : inexact-ok
+= expm1 downward ibm128 -0x4p-1076 : -0x4p-1076 : xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok
+= expm1 tonearest ibm128 -0x4p-1076 : -0x4p-1076 : inexact-ok underflow errno-erange-ok
+= expm1 towardzero ibm128 -0x4p-1076 : -0x0p+0 : xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok
+= expm1 upward ibm128 -0x4p-1076 : -0x0p+0 : xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok
+= expm1 downward intel96 -0x1p-10000 : -0x1p-10000 : inexact-ok
+= expm1 tonearest intel96 -0x1p-10000 : -0x1p-10000 : inexact-ok
+= expm1 towardzero intel96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : inexact-ok
+= expm1 upward intel96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : inexact-ok
+= expm1 downward m68k96 -0x1p-10000 : -0x1p-10000 : inexact-ok
+= expm1 tonearest m68k96 -0x1p-10000 : -0x1p-10000 : inexact-ok
+= expm1 towardzero m68k96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : inexact-ok
+= expm1 upward m68k96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : inexact-ok
+= expm1 downward binary128 -0x1p-10000 : -0x1p-10000 : inexact-ok
+= expm1 tonearest binary128 -0x1p-10000 : -0x1p-10000 : inexact-ok
+= expm1 towardzero binary128 -0x1p-10000 : -0xf.fffffffffffffffffffffffffff8p-10004 : inexact-ok
+= expm1 upward binary128 -0x1p-10000 : -0xf.fffffffffffffffffffffffffff8p-10004 : inexact-ok
expm1 0xe.4152ac57cd1ea7ap-60
= expm1 downward binary32 0xe.4152bp-60 : 0xe.4152bp-60 : inexact-ok
= expm1 tonearest binary32 0xe.4152bp-60 : 0xe.4152bp-60 : inexact-ok
diff --git a/math/auto-libm-test-out-log1p b/math/auto-libm-test-out-log1p
index f83241f51a..f7d3b35e6d 100644
--- a/math/auto-libm-test-out-log1p
+++ b/math/auto-libm-test-out-log1p
@@ -23,31 +23,31 @@ log1p 0
= log1p tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= log1p towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= log1p upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok
-log1p -0 no-mathvec
-= log1p downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= log1p upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
+log1p -0
+= log1p downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= log1p upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
log1p e-1
= log1p downward binary32 0x1.b7e152p+0 : 0x1p+0 : inexact-ok
= log1p tonearest binary32 0x1.b7e152p+0 : 0x1p+0 : inexact-ok
diff --git a/math/auto-libm-test-out-sin b/math/auto-libm-test-out-sin
index e1f6845283..f1d21b179c 100644
--- a/math/auto-libm-test-out-sin
+++ b/math/auto-libm-test-out-sin
@@ -23,31 +23,31 @@ sin 0
= sin tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= sin towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= sin upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok
-sin -0 no-mathvec
-= sin downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= sin upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
+sin -0
+= sin downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= sin upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
sin pi/6
= sin downward binary32 0x8.60a92p-4 : 0x8p-4 : inexact-ok
= sin tonearest binary32 0x8.60a92p-4 : 0x8p-4 : inexact-ok
diff --git a/math/auto-libm-test-out-tan b/math/auto-libm-test-out-tan
index f46fdc7ec6..7d00d03e1d 100644
--- a/math/auto-libm-test-out-tan
+++ b/math/auto-libm-test-out-tan
@@ -23,31 +23,31 @@ tan 0
= tan tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= tan towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= tan upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok
-tan -0 no-mathvec
-= tan downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tan upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
+tan -0
+= tan downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tan upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
tan pi/4
= tan downward binary32 0xc.90fdbp-4 : 0x1p+0 : inexact-ok
= tan tonearest binary32 0xc.90fdbp-4 : 0x1p+0 : inexact-ok
diff --git a/math/auto-libm-test-out-tanh b/math/auto-libm-test-out-tanh
index 19ce2e7b93..8b9427c917 100644
--- a/math/auto-libm-test-out-tanh
+++ b/math/auto-libm-test-out-tanh
@@ -23,31 +23,31 @@ tanh 0
= tanh tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= tanh towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok
= tanh upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok
-tanh -0 no-mathvec
-= tanh downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
-= tanh upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok
+tanh -0
+= tanh downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
+= tanh upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok
tanh 0.75
= tanh downward binary32 0xcp-4 : 0xa.2991fp-4 : inexact-ok
= tanh tonearest binary32 0xcp-4 : 0xa.2991fp-4 : inexact-ok
diff --git a/math/gen-auto-libm-tests.c b/math/gen-auto-libm-tests.c
index 0b1e307fae..ff8a22b90f 100644
--- a/math/gen-auto-libm-tests.c
+++ b/math/gen-auto-libm-tests.c
@@ -96,8 +96,7 @@
zero and infinite results should be ignored; "xfail" indicates the
test is disabled as expected to produce incorrect results,
"xfail-rounding" indicates the test is disabled only in rounding
- modes other than round-to-nearest; "no-mathvec" indicates the test
- is disabled in vector math libraries. Otherwise, test flags are of
+ modes other than round-to-nearest. Otherwise, test flags are of
the form "spurious-" and "missing-", for any
exception ("overflow", "underflow", "inexact", "invalid",
"divbyzero"), "spurious-errno" and "missing-errno", to indicate
@@ -353,7 +352,6 @@ typedef enum
flag_missing_overflow,
flag_missing_underflow,
flag_missing_errno,
- flag_no_mathvec,
num_input_flag_types,
flag_first_flag = 0,
flag_spurious_first = flag_spurious_divbyzero,
@@ -379,7 +377,6 @@ static const char *const input_flags[num_input_flag_types] =
"missing-overflow",
"missing-underflow",
"missing-errno",
- "no-mathvec",
};
/* An input flag, possibly conditional. */
@@ -2056,7 +2053,6 @@ output_for_one_input_case (FILE *fp, const char *filename, test_function *tf,
{
case flag_ignore_zero_inf_sign:
case flag_xfail:
- case flag_no_mathvec:
if (fprintf (fp, " %s%s",
input_flags[it->flags[i].type],
(it->flags[i].cond
diff --git a/math/gen-libm-test.py b/math/gen-libm-test.py
index 397dbd3259..6e8bb56437 100755
--- a/math/gen-libm-test.py
+++ b/math/gen-libm-test.py
@@ -93,8 +93,7 @@ BEAUTIFY_MAP = {'minus_zero': '-0',
# Flags in auto-libm-test-out that map directly to C flags.
FLAGS_SIMPLE = {'ignore-zero-inf-sign': 'IGNORE_ZERO_INF_SIGN',
- 'xfail': 'XFAIL_TEST',
- 'no-mathvec': 'NO_TEST_MATHVEC'}
+ 'xfail': 'XFAIL_TEST'}
# Exceptions in auto-libm-test-out, and their corresponding C flags
# for being required, OK or required to be absent.
diff --git a/math/libm-test-support.c b/math/libm-test-support.c
index 0796f9d495..3fecd87064 100644
--- a/math/libm-test-support.c
+++ b/math/libm-test-support.c
@@ -776,7 +776,7 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
ulps = ULPDIFF (computed, expected);
set_max_error (ulps, curr_max_error);
print_diff = 1;
- if ((exceptions & IGNORE_ZERO_INF_SIGN) == 0
+ if (((exceptions & IGNORE_ZERO_INF_SIGN) == 0) && !flag_test_mathvec
&& computed == 0.0 && expected == 0.0
&& signbit(computed) != signbit (expected))
ok = 0;
diff --git a/math/test-nan-payload.c b/math/test-nan-payload.c
index 4a81dc348b..413791e09f 100644
--- a/math/test-nan-payload.c
+++ b/math/test-nan-payload.c
@@ -16,6 +16,9 @@
License along with the GNU C Library; if not, see
. */
+#define _LIBC_TEST 1
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include
#include
#include
#include
@@ -31,7 +34,7 @@
#define CHECK_IS_NAN(TYPE, A) \
do \
{ \
- if (isnan (A)) \
+ if (isnan (A) && !issignaling (A)) \
puts ("PASS: " #TYPE " " #A); \
else \
{ \
@@ -41,6 +44,19 @@
} \
while (0)
+#define CHECK_PAYLOAD(TYPE, FUNC, A, P) \
+ do \
+ { \
+ if (FUNC (&(A)) == (P)) \
+ puts ("PASS: " #TYPE " payload " #A); \
+ else \
+ { \
+ puts ("FAIL: " #TYPE " payload " #A); \
+ result = 1; \
+ } \
+ } \
+ while (0)
+
#define CHECK_SAME_NAN(TYPE, A, B) \
do \
{ \
@@ -67,33 +83,97 @@
} \
while (0)
+#define CLEAR_ERRNO \
+ do \
+ { \
+ errno = 12345; \
+ } \
+ while (0)
+
+#define CHECK_ERRNO(TYPE, A) \
+ do \
+ { \
+ if (errno == 12345) \
+ puts ("PASS: " #TYPE " " #A " errno"); \
+ else \
+ { \
+ puts ("FAIL: " #TYPE " " #A " errno"); \
+ result = 1; \
+ } \
+ } \
+ while (0)
+
/* Cannot test payloads by memcmp for formats where NaNs have padding
bits. */
#define CAN_TEST_EQ(MANT_DIG) ((MANT_DIG) != 64 && (MANT_DIG) != 106)
-#define RUN_TESTS(TYPE, SFUNC, FUNC, MANT_DIG) \
+#define RUN_TESTS(TYPE, SFUNC, FUNC, PLFUNC, MANT_DIG) \
do \
{ \
+ CLEAR_ERRNO; \
TYPE n123 = WRAP_NAN (FUNC, "123"); \
+ CHECK_ERRNO (TYPE, n123); \
CHECK_IS_NAN (TYPE, n123); \
+ CLEAR_ERRNO; \
TYPE s123 = WRAP_STRTO (SFUNC, "NAN(123)"); \
+ CHECK_ERRNO (TYPE, s123); \
CHECK_IS_NAN (TYPE, s123); \
+ CLEAR_ERRNO; \
TYPE n456 = WRAP_NAN (FUNC, "456"); \
+ CHECK_ERRNO (TYPE, n456); \
CHECK_IS_NAN (TYPE, n456); \
+ CLEAR_ERRNO; \
TYPE s456 = WRAP_STRTO (SFUNC, "NAN(456)"); \
+ CHECK_ERRNO (TYPE, s456); \
CHECK_IS_NAN (TYPE, s456); \
+ CLEAR_ERRNO; \
+ TYPE nh123 = WRAP_NAN (FUNC, "0x123"); \
+ CHECK_ERRNO (TYPE, nh123); \
+ CHECK_IS_NAN (TYPE, nh123); \
+ CLEAR_ERRNO; \
+ TYPE sh123 = WRAP_STRTO (SFUNC, "NAN(0x123)"); \
+ CHECK_ERRNO (TYPE, sh123); \
+ CHECK_IS_NAN (TYPE, sh123); \
+ CLEAR_ERRNO; \
TYPE n123x = WRAP_NAN (FUNC, "123)"); \
+ CHECK_ERRNO (TYPE, n123x); \
CHECK_IS_NAN (TYPE, n123x); \
+ CLEAR_ERRNO; \
TYPE nemp = WRAP_NAN (FUNC, ""); \
+ CHECK_ERRNO (TYPE, nemp); \
CHECK_IS_NAN (TYPE, nemp); \
+ CLEAR_ERRNO; \
TYPE semp = WRAP_STRTO (SFUNC, "NAN()"); \
+ CHECK_ERRNO (TYPE, semp); \
CHECK_IS_NAN (TYPE, semp); \
+ CLEAR_ERRNO; \
TYPE sx = WRAP_STRTO (SFUNC, "NAN"); \
+ CHECK_ERRNO (TYPE, sx); \
CHECK_IS_NAN (TYPE, sx); \
+ CLEAR_ERRNO; \
+ TYPE novf = WRAP_NAN (FUNC, "9999999999" \
+ "99999999999999999999" \
+ "9999999999"); \
+ CHECK_ERRNO (TYPE, novf); \
+ CHECK_IS_NAN (TYPE, novf); \
+ CLEAR_ERRNO; \
+ TYPE sovf = WRAP_STRTO (SFUNC, "NAN(9999999999" \
+ "99999999999999999999" \
+ "9999999999)"); \
+ CHECK_ERRNO (TYPE, sovf); \
+ CHECK_IS_NAN (TYPE, sovf); \
if (CAN_TEST_EQ (MANT_DIG)) \
CHECK_SAME_NAN (TYPE, n123, s123); \
+ CHECK_PAYLOAD (TYPE, PLFUNC, n123, 123); \
+ CHECK_PAYLOAD (TYPE, PLFUNC, s123, 123); \
if (CAN_TEST_EQ (MANT_DIG)) \
CHECK_SAME_NAN (TYPE, n456, s456); \
+ CHECK_PAYLOAD (TYPE, PLFUNC, n456, 456); \
+ CHECK_PAYLOAD (TYPE, PLFUNC, s456, 456); \
+ if (CAN_TEST_EQ (MANT_DIG)) \
+ CHECK_SAME_NAN (TYPE, nh123, sh123); \
+ CHECK_PAYLOAD (TYPE, PLFUNC, nh123, 0x123); \
+ CHECK_PAYLOAD (TYPE, PLFUNC, sh123, 0x123); \
if (CAN_TEST_EQ (MANT_DIG)) \
CHECK_SAME_NAN (TYPE, nemp, semp); \
if (CAN_TEST_EQ (MANT_DIG)) \
@@ -110,9 +190,31 @@ static int
do_test (void)
{
int result = 0;
- RUN_TESTS (float, strtof, nanf, FLT_MANT_DIG);
- RUN_TESTS (double, strtod, nan, DBL_MANT_DIG);
- RUN_TESTS (long double, strtold, nanl, LDBL_MANT_DIG);
+ RUN_TESTS (float, strtof, nanf, getpayloadf, FLT_MANT_DIG);
+ RUN_TESTS (double, strtod, nan, getpayload, DBL_MANT_DIG);
+ RUN_TESTS (long double, strtold, nanl, getpayloadl, LDBL_MANT_DIG);
+#if __HAVE_FLOAT16
+ RUN_TESTS (_Float16, strtof16, nanf16, getpayloadf16, FLT16_MANT_DIG);
+#endif
+#if __HAVE_FLOAT32
+ RUN_TESTS (_Float32, strtof32, nanf32, getpayloadf32, FLT32_MANT_DIG);
+#endif
+#if __HAVE_FLOAT64
+ RUN_TESTS (_Float64, strtof64, nanf64, getpayloadf64, FLT64_MANT_DIG);
+#endif
+#if __HAVE_FLOAT128
+ RUN_TESTS (_Float128, strtof128, nanf128, getpayloadf128, FLT128_MANT_DIG);
+#endif
+#if __HAVE_FLOAT32X
+ RUN_TESTS (_Float32x, strtof32x, nanf32x, getpayloadf32x, FLT32X_MANT_DIG);
+#endif
+#if __HAVE_FLOAT64X
+ RUN_TESTS (_Float64x, strtof64x, nanf64x, getpayloadf64x, FLT64X_MANT_DIG);
+#endif
+#if __HAVE_FLOAT128X
+ RUN_TESTS (_Float128x, strtof128x, nanf128x, getpayloadf128x,
+ FLT128X_MANT_DIG);
+#endif
return result;
}
diff --git a/math/test-tgmath2.c b/math/test-tgmath2.c
index 37afa8a08a..4aeb877b8e 100644
--- a/math/test-tgmath2.c
+++ b/math/test-tgmath2.c
@@ -24,6 +24,8 @@
#include
#include
+#include
+
//#define DEBUG
typedef complex float cfloat;
@@ -87,13 +89,6 @@ enum
int count;
int counts[Tlast][C_last];
-#define FAIL(str) \
- do \
- { \
- printf ("%s failure on line %d\n", (str), __LINE__); \
- result = 1; \
- } \
- while (0)
#define TEST_TYPE_ONLY(expr, rettype) \
do \
{ \
@@ -133,8 +128,6 @@ int counts[Tlast][C_last];
int
test_cos (const int Vint4, const long long int Vllong4)
{
- int result = 0;
-
TEST (cos (vfloat1), float, cos);
TEST (cos (vdouble1), double, cos);
TEST (cos (vldouble1), ldouble, cos);
@@ -152,7 +145,7 @@ test_cos (const int Vint4, const long long int Vllong4)
TEST (cos (Vcdouble1), cdouble, cos);
TEST (cos (Vcldouble1), cldouble, cos);
- return result;
+ return 0;
}
int
diff --git a/misc/Makefile b/misc/Makefile
index 5d17c562fe..7b7f8351bf 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -257,6 +257,8 @@ tests := \
tst-mntent-blank-passno \
tst-mntent-escape \
tst-mntent2 \
+ tst-mremap1 \
+ tst-mremap2 \
tst-preadvwritev \
tst-preadvwritev2 \
tst-preadvwritev64 \
diff --git a/misc/tst-mremap1.c b/misc/tst-mremap1.c
new file mode 100644
index 0000000000..0469991a6c
--- /dev/null
+++ b/misc/tst-mremap1.c
@@ -0,0 +1,46 @@
+/* Test mremap with MREMAP_MAYMOVE.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int
+do_test (void)
+{
+ size_t old_size = getpagesize ();
+ char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
+ old_addr[0] = 1;
+ old_addr[old_size - 1] = 2;
+
+ /* Test MREMAP_MAYMOVE. */
+ size_t new_size = old_size + old_size;
+ char *new_addr = mremap (old_addr, old_size, new_size, MREMAP_MAYMOVE);
+ TEST_VERIFY_EXIT (new_addr != MAP_FAILED);
+ new_addr[0] = 1;
+ new_addr[new_size - 1] = 2;
+ xmunmap (new_addr, new_size);
+
+ return 0;
+}
+
+#include
diff --git a/misc/tst-mremap2.c b/misc/tst-mremap2.c
new file mode 100644
index 0000000000..45be7f0369
--- /dev/null
+++ b/misc/tst-mremap2.c
@@ -0,0 +1,54 @@
+/* Test mremap with MREMAP_FIXED.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+