1/* Check the VMA name decoration.
2 Copyright (C) 2023-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#include <stdlib.h>
20#include <string.h>
21#include <support/check.h>
22#include <support/support.h>
23#include <support/test-driver.h>
24#include <support/xstdio.h>
25#include <support/xthread.h>
26#include <support/xunistd.h>
27#include <sys/mman.h>
28
29#ifndef MAP_STACK
30# define MAP_STACK 0
31#endif
32
33static pthread_barrier_t b;
34
35static int expected_n_arenas;
36
37static void *
38tf (void *closure)
39{
40 void *p = xmalloc (n: 1024);
41
42 /* Wait the thread startup, so thread stack is allocated. */
43 xpthread_barrier_wait (barrier: &b);
44
45 /* Wait the test to read the process mapping. */
46 xpthread_barrier_wait (barrier: &b);
47
48 free (ptr: p);
49
50 return NULL;
51}
52
53struct proc_maps_t
54{
55 int n_def_threads;
56 int n_user_threads;
57 int n_arenas;
58 int n_malloc_mmap;
59 int n_loader_malloc_mmap;
60};
61
62static struct proc_maps_t
63read_proc_maps (void)
64{
65 if (test_verbose)
66 printf (format: "=== print process %jd memory mapping ===\n",
67 (intmax_t) getpid ());
68 struct proc_maps_t r = { 0 };
69
70 FILE *f = xfopen (path: "/proc/self/maps", mode: "r");
71 char *line = NULL;
72 size_t line_len = 0;
73 while (xgetline (lineptr: &line, n: &line_len, stream: f))
74 {
75 if (test_verbose)
76 printf (format: "%s", line);
77 if (strstr (haystack: line, needle: "[anon: glibc: pthread stack:") != NULL)
78 r.n_def_threads++;
79 else if (strstr (haystack: line, needle: "[anon: glibc: pthread user stack:") != NULL)
80 r.n_user_threads++;
81 else if (strstr (haystack: line, needle: "[anon: glibc: malloc arena]") != NULL)
82 r.n_arenas++;
83 else if (strstr (haystack: line, needle: "[anon: glibc: malloc]") != NULL)
84 r.n_malloc_mmap++;
85 else if (strstr (haystack: line, needle: "[anon: glibc: loader malloc]") != NULL)
86 r.n_loader_malloc_mmap++;
87 }
88 free (ptr: line);
89 xfclose (f);
90
91 if (test_verbose)
92 printf (format: "===\n");
93 return r;
94}
95
96static void
97do_test_threads (bool set_guard)
98{
99 enum
100 {
101 num_def_threads = 8,
102 num_user_threads = 2,
103 num_threads = num_def_threads + num_user_threads,
104 };
105
106 xpthread_barrier_init (barrier: &b, NULL, count: num_threads + 1);
107
108 /* Issue a large malloc to trigger a mmap call. */
109 void *p = xmalloc (n: 256 * 1024);
110
111 pthread_t thr[num_threads];
112 {
113 int i = 0;
114 for (; i < num_threads - num_user_threads; i++)
115 {
116 pthread_attr_t attr;
117 xpthread_attr_init (attr: &attr);
118 /* The guard page is not annotated. */
119 if (!set_guard)
120 xpthread_attr_setguardsize (attr: &attr, guardsize: 0);
121 thr[i] = xpthread_create (attr: &attr, thread_func: tf, NULL);
122 xpthread_attr_destroy (attr: &attr);
123 }
124 for (; i < num_threads; i++)
125 {
126 pthread_attr_t attr;
127 xpthread_attr_init (attr: &attr);
128 size_t stacksize = support_small_thread_stack_size ();
129 void *stack = xmmap (addr: 0,
130 length: stacksize,
131 PROT_READ | PROT_WRITE,
132 MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK,
133 fd: -1);
134 xpthread_attr_setstack (attr: &attr, stackaddr: stack, stacksize);
135 if (!set_guard)
136 xpthread_attr_setguardsize (attr: &attr, guardsize: 0);
137 thr[i] = xpthread_create (attr: &attr, thread_func: tf, NULL);
138 xpthread_attr_destroy (attr: &attr);
139 }
140 }
141
142 /* Wait all threads to finshed statup and stack allocation. */
143 xpthread_barrier_wait (barrier: &b);
144
145 {
146 struct proc_maps_t r = read_proc_maps ();
147 TEST_COMPARE (r.n_def_threads, num_def_threads);
148 TEST_COMPARE (r.n_user_threads, num_user_threads);
149 TEST_COMPARE (r.n_arenas, expected_n_arenas);
150 TEST_COMPARE (r.n_malloc_mmap, 1);
151 /* On some architectures the loader might use more than one page. */
152 TEST_VERIFY (r.n_loader_malloc_mmap >= 1);
153 }
154
155 /* Let the threads finish. */
156 xpthread_barrier_wait (barrier: &b);
157
158 for (int i = 0; i < num_threads; i++)
159 xpthread_join (thr: thr[i]);
160
161 {
162 struct proc_maps_t r = read_proc_maps ();
163 TEST_COMPARE (r.n_def_threads, 0);
164 TEST_COMPARE (r.n_user_threads, 0);
165 TEST_COMPARE (r.n_arenas, expected_n_arenas);
166 TEST_COMPARE (r.n_malloc_mmap, 1);
167 TEST_VERIFY (r.n_loader_malloc_mmap >= 1);
168 }
169
170 free (ptr: p);
171}
172
173static void
174do_prepare (int argc, char *argv[])
175{
176 TEST_VERIFY_EXIT (argc == 2);
177 expected_n_arenas = strtol (argv[1], NULL, 10);
178 expected_n_arenas = expected_n_arenas - 1;
179}
180#define PREPARE do_prepare
181
182static int
183do_test (void)
184{
185 support_need_proc (why_msg: "Reads /proc/self/maps to get stack names.");
186
187 if (!support_set_vma_name_supported ())
188 FAIL_UNSUPPORTED ("kernel does not support PR_SET_VMA_ANON_NAME");
189
190 do_test_threads (false);
191 do_test_threads (true);
192
193 return 0;
194}
195
196#include <support/test-driver.c>
197

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of glibc/elf/tst-decorate-maps.c