Przeglądaj źródła

[libc][libdl] Fix dlopen() failing to find already-loaded modules

Copilot 8 godzin temu
rodzic
commit
828de39c9a

+ 60 - 13
components/libc/posix/libdl/dlmodule.c

@@ -33,32 +33,79 @@ 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.
+ *         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)
 {
     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')
     {
         if (*ptr == '/')
             first = ptr + 1;
+        ptr++;
+    }
+
+    /* find last extension in filename portion only (after last '/') */
+    last_dot = RT_NULL;
+    ptr = first;
+    while (*ptr != '\0')
+    {
         if (*ptr == '.')
-            end = ptr - 1;
+            last_dot = ptr;
+        ptr++;
+    }
+
+    /* determine end position for module name */
+    if (last_dot != RT_NULL && last_dot != first)
+    {
+        /* extension found (dot not at start of filename), strip it */
+        end = last_dot;
+    }
+    /* else: no extension, or filename starts with dot only (e.g., ".hidden"),
+     * use entire filename */
 
-        ptr ++;
+    size = end - first;
+    if (size <= 0)
+    {
+        /* defensive: empty path or path ending with "/" */
+        size = rt_strlen(first);
     }
+    if (size >= name_size)
+        size = name_size - 1;
+
+    rt_strncpy(name, first, size);
+    name[size] = '\0';
+}
 
-    size = end - first + 1;
-    if (size >= RT_NAME_MAX) size = RT_NAME_MAX - 1;
+/* 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

+ 2 - 0
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

+ 14 - 7
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,21 @@ 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.
+     */
+    dlmodule_extract_name(fullpath, module_name, RT_NAME_MAX);
+
     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 +74,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);