drm-shim: implement most readlink() without initializing the shim

This is to avoid a situation where jemalloc initialization calls
readlink(), which then tries to use malloc during init_shim().

Signed-off-by: Rhys Perry <pendingchaos02@gmail.com>
Reviewed-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38350>
This commit is contained in:
Rhys Perry 2025-11-07 16:47:51 +00:00 committed by Marge Bot
parent 4bf8fd5121
commit f3770643f6

View file

@ -96,14 +96,16 @@ REAL_FUNCTION_POINTER(fstat);
REAL_FUNCTION_POINTER(fstat64);
#endif
#define STRINGIZE2(x) #x
#define STRINGIZE(x) STRINGIZE2(x)
static char render_node_dir[] = "/dev/dri/";
/* Full path of /dev/dri/renderD* */
static char *render_node_path;
/* renderD* */
static char *render_node_dirent_name;
/* /sys/dev/char/major: */
static int drm_device_path_len;
static char *drm_device_path;
static char drm_device_path[] = "/sys/dev/char/" STRINGIZE(DRM_MAJOR) ":";
/* /sys/dev/char/major:minor/device */
static int device_path_len;
static char *device_path;
@ -189,6 +191,43 @@ drm_shim_override_file(const char *contents, const char *path_format, ...)
override->contents = strdup(contents);
}
static uint32_t got_function_pointers = 0;
static void
get_function_pointers(void)
{
if (p_atomic_cmpxchg(&got_function_pointers, 0, 1))
return;
GET_FUNCTION_POINTER(access);
GET_FUNCTION_POINTER(close);
GET_FUNCTION_POINTER(closedir);
GET_FUNCTION_POINTER(dup);
GET_FUNCTION_POINTER(fcntl);
GET_FUNCTION_POINTER(fopen);
GET_FUNCTION_POINTER(ioctl);
GET_FUNCTION_POINTER(mmap);
GET_FUNCTION_POINTER(mmap64);
GET_FUNCTION_POINTER(open);
GET_FUNCTION_POINTER(opendir);
GET_FUNCTION_POINTER(readdir);
GET_FUNCTION_POINTER(readdir64);
GET_FUNCTION_POINTER(readlink);
GET_FUNCTION_POINTER(realpath);
#if HAS_XSTAT
GET_FUNCTION_POINTER(__xstat);
GET_FUNCTION_POINTER(__xstat64);
GET_FUNCTION_POINTER(__fxstat);
GET_FUNCTION_POINTER(__fxstat64);
#else
GET_FUNCTION_POINTER(stat);
GET_FUNCTION_POINTER(stat64);
GET_FUNCTION_POINTER(fstat);
GET_FUNCTION_POINTER(fstat64);
#endif
}
static uint32_t inited = 0;
static void
@ -220,33 +259,7 @@ init_shim(void)
_mesa_hash_string,
_mesa_key_string_equal);
GET_FUNCTION_POINTER(access);
GET_FUNCTION_POINTER(close);
GET_FUNCTION_POINTER(closedir);
GET_FUNCTION_POINTER(dup);
GET_FUNCTION_POINTER(fcntl);
GET_FUNCTION_POINTER(fopen);
GET_FUNCTION_POINTER(ioctl);
GET_FUNCTION_POINTER(mmap);
GET_FUNCTION_POINTER(mmap64);
GET_FUNCTION_POINTER(open);
GET_FUNCTION_POINTER(opendir);
GET_FUNCTION_POINTER(readdir);
GET_FUNCTION_POINTER(readdir64);
GET_FUNCTION_POINTER(readlink);
GET_FUNCTION_POINTER(realpath);
#if HAS_XSTAT
GET_FUNCTION_POINTER(__xstat);
GET_FUNCTION_POINTER(__xstat64);
GET_FUNCTION_POINTER(__fxstat);
GET_FUNCTION_POINTER(__fxstat64);
#else
GET_FUNCTION_POINTER(stat);
GET_FUNCTION_POINTER(stat64);
GET_FUNCTION_POINTER(fstat);
GET_FUNCTION_POINTER(fstat64);
#endif
get_function_pointers();
get_dri_render_node_minor();
@ -255,9 +268,6 @@ init_shim(void)
render_node_path);
}
drm_device_path_len =
nfasprintf(&drm_device_path, "/sys/dev/char/%d:", DRM_MAJOR);
device_path_len =
nfasprintf(&device_path,
"/sys/dev/char/%d:%d/device",
@ -272,30 +282,34 @@ init_shim(void)
atexit(destroy_shim);
}
static bool hide_drm_device_path(const char *path)
static bool is_drm_device_path(const char *path)
{
if (render_node_minor == -1)
return false;
/* String starts with /sys/dev/char/226: */
if (strncmp(path, drm_device_path, sizeof(drm_device_path) - 1) == 0)
return true;
/* String starts with /dev/dri/ */
if (strncmp(path, render_node_dir, sizeof(render_node_dir) - 1) == 0)
return true;
return false;
}
static bool hide_drm_device_path(const char *path)
{
/* If the path looks like our fake render node device, then don't hide it.
*/
if (strncmp(path, device_path, device_path_len) == 0 ||
strcmp(path, render_node_path) == 0)
return false;
/* String starts with /sys/dev/char/226: but is not the fake render node.
/* String looks like a device but is not the fake render node.
* We want to hide all other drm devices for the shim.
*/
if (strncmp(path, drm_device_path, drm_device_path_len) == 0)
return true;
/* String starts with /dev/dri/ but is not the fake render node. We want to
* hide all other drm devices for the shim.
*/
if (strncmp(path, render_node_dir, sizeof(render_node_dir) - 1) == 0)
return true;
return false;
return is_drm_device_path(path);
}
static int file_override_open(const char *path)
@ -712,6 +726,12 @@ closedir(DIR *dir)
PUBLIC ssize_t
readlink(const char *path, char *buf, size_t size)
{
/* Shortcut to the real readlink so that jemalloc can use this. */
if (!is_drm_device_path(path)) {
get_function_pointers();
return real_readlink(path, buf, size);
}
init_shim();
if (hide_drm_device_path(path)) {