[PATCH v4] elf: parse /proc/self/maps as the last resort to find the gap for tst-link-map-contiguous-ldso
Xi Ruoyao
xry111@xry111.site
Thu Jan 22 14:04:01 GMT 2026
The initialization process of libc.so calls mmap() several times and the
kernel may lay the maps into the gap. If all pages in the gap are
occupied, the test would not be able to find the gap with mmap() and the
test would fail.
The failure reproduces most frequently on LoongArch because with the
commonly used page size (16 KiB) the gap only contains 4 pages and the
probability they are all occupied is not near to zero.
With the changes in the patch, a test run may output:
info: ld.so link map is not contiguous
info: object "/dev/zero" found at 0x7ffff1fe0000 - 0x7ffff1fe4000
info: anonymous mapping found at 0x7ffff1fe4000 - 0x7ffff1fec000
Also take the chance to fix a mistake in the "object found at" message
which has puzzled me during the initial debug session.
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
ChangeLog:
v1 -> v2: parse mmap to avoid false postive
v2 -> v3: use %ms to simplify the code and get the full path of ld.so by
matching l_map_start in the maps file
v3 -> v4: move the definition of "path" into the loop body
elf/tst-link-map-contiguous-ldso.c | 62 +++++++++++++++++++++++++++++-
1 file changed, 60 insertions(+), 2 deletions(-)
diff --git a/elf/tst-link-map-contiguous-ldso.c b/elf/tst-link-map-contiguous-ldso.c
index 9f97b8b95a..ba7925943c 100644
--- a/elf/tst-link-map-contiguous-ldso.c
+++ b/elf/tst-link-map-contiguous-ldso.c
@@ -18,15 +18,71 @@
#include <dlfcn.h>
#include <gnu/lib-names.h>
+#include <inttypes.h>
#include <link.h>
#include <stdbool.h>
#include <stdio.h>
#include <support/check.h>
+#include <support/support.h>
#include <support/xdlfcn.h>
#include <support/xunistd.h>
+#include <support/xstdio.h>
#include <sys/mman.h>
#include <unistd.h>
+/* Slow path in case we cannot find a gap with mmap (when the runtime has
+ mapped all the pages in the gap for some reason). */
+static bool
+find_gap_with_proc_self_map (const struct link_map *l)
+{
+ int pagesize = getpagesize ();
+
+ support_need_proc ("Reads /proc/self/maps to find gap in ld.so mapping");
+
+ /* Parse /proc/self/maps and find all the mappings in the ld.so range
+ but not from ld.so. */
+ FILE *f = xfopen ("/proc/self/maps", "r");
+ char *line = NULL, *path_ldso = NULL;
+ size_t len;
+ bool found = false;
+ while (xgetline (&line, &len, f))
+ {
+ uintptr_t from, to;
+ char *path = NULL;
+ int r = sscanf (line, "%" SCNxPTR "-%" SCNxPTR "%*s%*s%*s%*s%ms",
+ &from, &to, &path);
+
+ TEST_VERIFY (r == 2 || r == 3);
+ TEST_COMPARE (from % pagesize, 0);
+ TEST_COMPARE (to % pagesize, 0);
+
+ if (!path_ldso && l->l_map_start == from)
+ {
+ TEST_COMPARE (r, 3);
+ path_ldso = path;
+ continue;
+ }
+
+ if (from > l->l_map_start && to < l->l_map_end
+ && (r == 2 || (path_ldso && strcmp (path, path_ldso))))
+ {
+ if (r == 2)
+ printf ("info: anonymous mapping found at 0x%" SCNxPTR " - 0x%"
+ SCNxPTR "\n", from, to);
+ else
+ printf ("info: object \"%s\" found at 0x%" SCNxPTR " - 0x%"
+ SCNxPTR "\n", path, from, to);
+
+ found = true;
+ }
+
+ free (path);
+ }
+
+ free (path_ldso);
+ return found;
+}
+
static int
do_test (void)
{
@@ -64,16 +120,18 @@ do_test (void)
if ((void *) dlfo.dlfo_link_map != (void *) l)
{
printf ("info: object \"%s\" found at %p\n",
- dlfo.dlfo_link_map->l_name, ptr);
+ dlfo.dlfo_link_map->l_name, expected);
gap_found = true;
}
}
else
TEST_COMPARE (dlfo_ret, -1);
+
xmunmap (ptr, 1);
addr += pagesize;
}
- if (!gap_found)
+
+ if (!gap_found && !find_gap_with_proc_self_map (l))
FAIL ("no ld.so gap found");
}
else
--
2.52.0
More information about the Libc-alpha
mailing list