From f3770643f6fec00353ceed733e643150fff000a9 Mon Sep 17 00:00:00 2001 From: Rhys Perry Date: Fri, 7 Nov 2025 16:47:51 +0000 Subject: [PATCH] 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 Reviewed-by: Samuel Pitoiset Part-of: --- src/drm-shim/drm_shim.c | 108 ++++++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 44 deletions(-) diff --git a/src/drm-shim/drm_shim.c b/src/drm-shim/drm_shim.c index 789c05f3d93..42e94c3d852 100644 --- a/src/drm-shim/drm_shim.c +++ b/src/drm-shim/drm_shim.c @@ -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)) {