From 1e594995292f4eb36e8afd42ed62389d7df95873 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Wed, 18 Mar 2026 01:27:38 -0500 Subject: [PATCH] dlopen edge case for non-multi-instance apps avoided. --- dvxshell/shellApp.c | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/dvxshell/shellApp.c b/dvxshell/shellApp.c index e849ffd..780e421 100644 --- a/dvxshell/shellApp.c +++ b/dvxshell/shellApp.c @@ -32,7 +32,7 @@ static void appTaskWrapper(void *arg); static const char *baseName(const char *path); static void cleanupTempFile(ShellAppT *app); static int32_t copyFile(const char *src, const char *dst); -static bool isPathLoaded(const char *path); +static ShellAppT *findLoadedPath(const char *path); static int32_t makeTempPath(const char *origPath, int32_t id, char *out, int32_t outSize); void shellAppInit(void); void shellForceKillApp(AppContextT *ctx, ShellAppT *app); @@ -135,15 +135,16 @@ static int32_t copyFile(const char *src, const char *dst) { } -// Check if a DXE path is already loaded in any active slot. -static bool isPathLoaded(const char *path) { +// Find an active slot with the given DXE path. Returns the slot pointer, +// or NULL if no running app was loaded from this path. +static ShellAppT *findLoadedPath(const char *path) { for (int32_t i = 1; i < SHELL_MAX_APPS; i++) { if (sApps[i].state != AppStateFreeE && strcmp(sApps[i].path, path) == 0) { - return true; + return &sApps[i]; } } - return false; + return NULL; } @@ -264,28 +265,22 @@ int32_t shellLoadApp(AppContextT *ctx, const char *path) { return -1; } - // Check if this DXE is already loaded. If so, we need to inspect its - // descriptor to decide whether to allow a second instance. + // Check if this DXE is already loaded. If so, check whether the app + // allows multiple instances. We read the descriptor from the existing + // slot directly — no need to dlopen again. const char *loadPath = path; char tempPath[260] = {0}; + ShellAppT *existing = findLoadedPath(path); - if (isPathLoaded(path)) { - // Peek at the descriptor from the already-loaded module to check - // multiInstance. Since it's already loaded, dlopen returns the - // existing handle (cheap, no actual reload). - void *peek = dlopen(path, RTLD_GLOBAL); + if (existing) { + // Read multiInstance from the already-loaded descriptor + AppDescriptorT *existDesc = (AppDescriptorT *)dlsym(existing->dxeHandle, "_appDescriptor"); - if (peek) { - AppDescriptorT *peekDesc = (AppDescriptorT *)dlsym(peek, "_appDescriptor"); - bool allow = peekDesc && peekDesc->multiInstance; - dlclose(peek); - - if (!allow) { - char msg[320]; - snprintf(msg, sizeof(msg), "%s is already running.", baseName(path)); - dvxMessageBox(ctx, "Error", msg, MB_OK | MB_ICONERROR); - return -1; - } + if (!existDesc || !existDesc->multiInstance) { + char msg[320]; + snprintf(msg, sizeof(msg), "%s is already running.", baseName(path)); + dvxMessageBox(ctx, "Error", msg, MB_OK | MB_ICONERROR); + return -1; } // Multi-instance allowed: copy to a temp file so dlopen gets