From ec3b2a2d76e80847dbfab41f534aa0fa522afe7f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 02:30:51 +0000 Subject: [PATCH 1/4] Initial plan From 8a99de17472a472ee46bbb7c795d09a2937e9177 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 02:34:34 +0000 Subject: [PATCH 2/4] [libc][libdl] Fix dlopen() failing to find already-loaded modules Fix name mismatch between dlmodule_find() and _dlmodule_set_name() that caused dlopen() to always reload modules instead of reusing them: 1. In dlopen(): Extract module name from full path before calling dlmodule_find(), matching the stripped name stored by _dlmodule_set_name(). This allows dlopen() to properly find and reuse already-loaded modules. 2. In _dlmodule_set_name(): Fix bug where extension detection searched the entire path instead of just the filename portion. For paths like "/mnt/v1.2/app.so", it would incorrectly find "." in "v1.2" directory name instead of the ".so" extension. Fixes: Module reloading on every dlopen() call, memory leaks from duplicate module instances, and dlclose() cleanup issues. Co-authored-by: BernardXiong <1241087+BernardXiong@users.noreply.github.com> --- components/libc/posix/libdl/dlmodule.c | 20 ++++++++-- components/libc/posix/libdl/dlopen.c | 55 ++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/components/libc/posix/libdl/dlmodule.c b/components/libc/posix/libdl/dlmodule.c index eee45d0843a..22594d0d802 100644 --- a/components/libc/posix/libdl/dlmodule.c +++ b/components/libc/posix/libdl/dlmodule.c @@ -44,17 +44,29 @@ static void _dlmodule_set_name(struct rt_dlmodule *module, const char *path) ptr = first = (char *)path; end = path + rt_strlen(path); + /* find the start of filename (after last '/') */ while (*ptr != '\0') { if (*ptr == '/') first = ptr + 1; - if (*ptr == '.') - end = ptr - 1; + ptr++; + } - ptr ++; + /* find extension in filename portion only (after last '/') */ + ptr = first; + while (*ptr != '\0') + { + if (*ptr == '.') + end = ptr; + ptr++; } - size = end - first + 1; + size = end - first; + if (size <= 0) + { + /* no extension found, use entire filename */ + size = rt_strlen(first); + } if (size >= RT_NAME_MAX) size = RT_NAME_MAX - 1; rt_strncpy(object->name, first, size); diff --git a/components/libc/posix/libdl/dlopen.c b/components/libc/posix/libdl/dlopen.c index 8545bce1180..2c8e3e78d17 100644 --- a/components/libc/posix/libdl/dlopen.c +++ b/components/libc/posix/libdl/dlopen.c @@ -33,7 +33,8 @@ void* dlopen(const char *filename, int flags) { struct rt_dlmodule *module; char *fullpath; - const char*def_path = MODULE_ROOT_DIR; + const char *def_path = MODULE_ROOT_DIR; + char module_name[RT_NAME_MAX]; /* check parameters */ RT_ASSERT(filename != RT_NULL); @@ -48,15 +49,55 @@ void* dlopen(const char *filename, int flags) } else { - fullpath = (char*)filename; /* absolute path, use it directly */ + fullpath = (char *)filename; /* absolute path, use it directly */ + } + + /* Extract module name from path (strip directory and extension) + * This matches the logic in _dlmodule_set_name() so that dlmodule_find() + * can properly locate already-loaded modules by their stored name. + */ + { + const char *first, *end, *ptr; + int size; + + ptr = first = fullpath; + end = fullpath + strlen(fullpath); + + while (*ptr != '\0') + { + if (*ptr == '/') + first = ptr + 1; + ptr++; + } + + /* find extension in filename portion only (after last '/') */ + ptr = first; + while (*ptr != '\0') + { + if (*ptr == '.') + end = ptr; + ptr++; + } + + size = end - first; + if (size <= 0) + { + /* no extension found, use entire filename */ + size = strlen(first); + } + if (size >= RT_NAME_MAX) + size = RT_NAME_MAX - 1; + + rt_strncpy(module_name, first, size); + module_name[size] = '\0'; } rt_enter_critical(); - /* find in module list */ - module = dlmodule_find(fullpath); + /* find in module list using the stripped module name */ + module = dlmodule_find(module_name); - if(module != RT_NULL) + if (module != RT_NULL) { rt_exit_critical(); module->nref++; @@ -67,11 +108,11 @@ void* dlopen(const char *filename, int flags) module = dlmodule_load(fullpath); } - if(fullpath != filename) + if (fullpath != filename) { rt_free(fullpath); } - return (void*)module; + return (void *)module; } RTM_EXPORT(dlopen); From 79d62050aaf21ab8b4de3dcb410ecb0e58235b64 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 02:36:09 +0000 Subject: [PATCH 3/4] [libc][libdl] Extract name extraction to shared function and fix edge cases Address code review feedback: 1. Extract path stripping logic into shared dlmodule_extract_name() function to avoid code duplication between dlopen() and _dlmodule_set_name(). 2. Fix edge case handling for filenames starting with dot (e.g., .hidden). 3. Add proper documentation for the new function. This ensures consistent module name extraction across all code paths. Co-authored-by: BernardXiong <1241087+BernardXiong@users.noreply.github.com> --- components/libc/posix/libdl/dlmodule.c | 57 ++++++++++++++++++++------ components/libc/posix/libdl/dlmodule.h | 2 + components/libc/posix/libdl/dlopen.c | 36 +--------------- 3 files changed, 47 insertions(+), 48 deletions(-) diff --git a/components/libc/posix/libdl/dlmodule.c b/components/libc/posix/libdl/dlmodule.c index 22594d0d802..1b784bcae85 100644 --- a/components/libc/posix/libdl/dlmodule.c +++ b/components/libc/posix/libdl/dlmodule.c @@ -33,16 +33,28 @@ static struct rt_module_symtab *_rt_module_symtab_end = RT_NULL; #pragma section="RTMSymTab" #endif -/* set the name of module */ -static void _dlmodule_set_name(struct rt_dlmodule *module, const char *path) +/** + * @brief Extract module name from a file path by stripping directory and extension. + * + * @param path the file path (e.g., "/mnt/sdcard/apps/clock.so") + * @param name buffer to store the extracted module name + * @param name_size size of the name buffer + * + * @note This function extracts the base name without path and extension. + * For example: "/mnt/sdcard/apps/clock.so" -> "clock" + * For hidden files like ".hidden", the entire filename is used. + */ +void dlmodule_extract_name(const char *path, char *name, int name_size) { int size; - struct rt_object *object; - const char *first, *end, *ptr; + const char *first, *end, *ptr, *last_dot; - object = &(module->parent); - ptr = first = (char *)path; - end = path + rt_strlen(path); + RT_ASSERT(path != RT_NULL); + RT_ASSERT(name != RT_NULL); + RT_ASSERT(name_size > 0); + + ptr = first = path; + end = path + rt_strlen(path); /* find the start of filename (after last '/') */ while (*ptr != '\0') @@ -52,25 +64,44 @@ static void _dlmodule_set_name(struct rt_dlmodule *module, const char *path) ptr++; } - /* find extension in filename portion only (after last '/') */ + /* find last extension in filename portion only (after last '/') */ + last_dot = RT_NULL; ptr = first; while (*ptr != '\0') { if (*ptr == '.') - end = ptr; + last_dot = ptr; ptr++; } + /* determine end position for module name */ + if (last_dot != RT_NULL && last_dot != first) + { + /* extension found and filename doesn't start with dot */ + end = last_dot; + } + /* else: no extension or filename starts with dot, use entire filename */ + size = end - first; if (size <= 0) { - /* no extension found, use entire filename */ + /* edge case: empty filename or only dot(s) */ size = rt_strlen(first); } - if (size >= RT_NAME_MAX) size = RT_NAME_MAX - 1; + if (size >= name_size) + size = name_size - 1; + + rt_strncpy(name, first, size); + name[size] = '\0'; +} + +/* set the name of module */ +static void _dlmodule_set_name(struct rt_dlmodule *module, const char *path) +{ + struct rt_object *object; - rt_strncpy(object->name, first, size); - object->name[size] = '\0'; + object = &(module->parent); + dlmodule_extract_name(path, object->name, RT_NAME_MAX); } #define RT_MODULE_ARG_MAX 8 diff --git a/components/libc/posix/libdl/dlmodule.h b/components/libc/posix/libdl/dlmodule.h index 75ca3258000..418c1a95c7d 100644 --- a/components/libc/posix/libdl/dlmodule.h +++ b/components/libc/posix/libdl/dlmodule.h @@ -82,6 +82,8 @@ void dlmodule_exit(int ret_code); struct rt_dlmodule *dlmodule_find(const char *name); +void dlmodule_extract_name(const char *path, char *name, int name_size); + rt_ubase_t dlmodule_symbol_find(const char *sym_str); #endif diff --git a/components/libc/posix/libdl/dlopen.c b/components/libc/posix/libdl/dlopen.c index 2c8e3e78d17..baaf1667132 100644 --- a/components/libc/posix/libdl/dlopen.c +++ b/components/libc/posix/libdl/dlopen.c @@ -56,41 +56,7 @@ void* dlopen(const char *filename, int flags) * This matches the logic in _dlmodule_set_name() so that dlmodule_find() * can properly locate already-loaded modules by their stored name. */ - { - const char *first, *end, *ptr; - int size; - - ptr = first = fullpath; - end = fullpath + strlen(fullpath); - - while (*ptr != '\0') - { - if (*ptr == '/') - first = ptr + 1; - ptr++; - } - - /* find extension in filename portion only (after last '/') */ - ptr = first; - while (*ptr != '\0') - { - if (*ptr == '.') - end = ptr; - ptr++; - } - - size = end - first; - if (size <= 0) - { - /* no extension found, use entire filename */ - size = strlen(first); - } - if (size >= RT_NAME_MAX) - size = RT_NAME_MAX - 1; - - rt_strncpy(module_name, first, size); - module_name[size] = '\0'; - } + dlmodule_extract_name(fullpath, module_name, RT_NAME_MAX); rt_enter_critical(); From 7683f3d7488f4fc6e58bebe1d96fc13bba6ac802 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 02:37:31 +0000 Subject: [PATCH 4/4] [libc][libdl] Improve documentation and comments for dlmodule_extract_name Clarify the behavior of edge cases in documentation: - Added more examples to the function documentation - Fixed misleading comment about dot handling - Clarified the defensive check purpose Co-authored-by: BernardXiong <1241087+BernardXiong@users.noreply.github.com> --- components/libc/posix/libdl/dlmodule.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/components/libc/posix/libdl/dlmodule.c b/components/libc/posix/libdl/dlmodule.c index 1b784bcae85..7ce60908774 100644 --- a/components/libc/posix/libdl/dlmodule.c +++ b/components/libc/posix/libdl/dlmodule.c @@ -41,8 +41,11 @@ static struct rt_module_symtab *_rt_module_symtab_end = RT_NULL; * @param name_size size of the name buffer * * @note This function extracts the base name without path and extension. - * For example: "/mnt/sdcard/apps/clock.so" -> "clock" - * For hidden files like ".hidden", the entire filename is used. + * Examples: + * - "/mnt/sdcard/apps/clock.so" -> "clock" + * - "/mnt/v1.2/app.so" -> "app" (dots in path are ignored) + * - ".hidden" -> ".hidden" (hidden files without extension) + * - ".hidden.so" -> ".hidden" (hidden files with extension) */ void dlmodule_extract_name(const char *path, char *name, int name_size) { @@ -77,15 +80,16 @@ void dlmodule_extract_name(const char *path, char *name, int name_size) /* determine end position for module name */ if (last_dot != RT_NULL && last_dot != first) { - /* extension found and filename doesn't start with dot */ + /* extension found (dot not at start of filename), strip it */ end = last_dot; } - /* else: no extension or filename starts with dot, use entire filename */ + /* else: no extension, or filename starts with dot only (e.g., ".hidden"), + * use entire filename */ size = end - first; if (size <= 0) { - /* edge case: empty filename or only dot(s) */ + /* defensive: empty path or path ending with "/" */ size = rt_strlen(first); } if (size >= name_size)