/* 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