/* Check the VMA name decoration. Copyright (C) 2023 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 #ifndef MAP_STACK # define MAP_STACK 0 #endif static pthread_barrier_t b; static void * tf (void *closure) { /* Wait the thread startup, so thread stack is allocated. */ xpthread_barrier_wait (&b); /* Wait the test to read the process mapping. */ xpthread_barrier_wait (&b); return NULL; } struct proc_maps_t { int n_def_threads; int n_user_threads; }; static struct proc_maps_t read_proc_maps (void) { if (test_verbose) printf ("=== print process %jd memory mapping ===\n", (intmax_t) getpid ()); struct proc_maps_t r = { 0 }; FILE *f = xfopen ("/proc/self/maps", "r"); char *line = NULL; size_t line_len = 0; while (xgetline (&line, &line_len, f)) { if (test_verbose) printf ("%s", line); if (strstr (line, "[anon: glibc: pthread stack:") != NULL) r.n_def_threads++; else if (strstr (line, "[anon: glibc: pthread user stack:") != NULL) r.n_user_threads++; } free (line); xfclose (f); if (test_verbose) printf ("===\n"); return r; } static void do_test_threads (bool set_guard) { enum { num_def_threads = 8, num_user_threads = 2, num_threads = num_def_threads + num_user_threads, }; xpthread_barrier_init (&b, NULL, num_threads + 1); pthread_t thr[num_threads]; { int i = 0; for (; i < num_threads - num_user_threads; i++) { pthread_attr_t attr; xpthread_attr_init (&attr); /* The guard page is not annotated. */ if (!set_guard) xpthread_attr_setguardsize (&attr, 0); thr[i] = xpthread_create (&attr, tf, NULL); xpthread_attr_destroy (&attr); } for (; i < num_threads; i++) { pthread_attr_t attr; xpthread_attr_init (&attr); size_t stacksize = support_small_thread_stack_size (); void *stack = xmmap (0, stacksize, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1); xpthread_attr_setstack (&attr, stack, stacksize); if (!set_guard) xpthread_attr_setguardsize (&attr, 0); thr[i] = xpthread_create (&attr, tf, NULL); xpthread_attr_destroy (&attr); } } /* Wait all threads to finshed statup and stack allocation. */ xpthread_barrier_wait (&b); { struct proc_maps_t r = read_proc_maps (); TEST_COMPARE (r.n_def_threads, num_def_threads); TEST_COMPARE (r.n_user_threads, num_user_threads); } /* Let the threads finish. */ xpthread_barrier_wait (&b); for (int i = 0; i < num_threads; i++) xpthread_join (thr[i]); { struct proc_maps_t r = read_proc_maps (); TEST_COMPARE (r.n_def_threads, 0); TEST_COMPARE (r.n_user_threads, 0); } } static int do_test (void) { support_need_proc ("Reads /proc/self/maps to get stack names."); if (!support_set_vma_name_supported ()) FAIL_UNSUPPORTED ("kernel does not support PR_SET_VMA_ANON_NAME"); do_test_threads (false); do_test_threads (true); return 0; } #include