about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-04-12 18:20:05 +0000
committerptitSeb <sebastien.chev@gmail.com>2023-04-12 18:20:16 +0000
commit5ceedab2137ed65c542ca00e528fe07d121799ad (patch)
treec5aa961838c81e2a1a356e753c22eec7bc588180 /src
parent1c4f3cbf195453b214d3551d012cd17a38b8aaf3 (diff)
downloadbox64-5ceedab2137ed65c542ca00e528fe07d121799ad.tar.gz
box64-5ceedab2137ed65c542ca00e528fe07d121799ad.zip
Improve loading/unloading of libs, and fixed a regression when dlopen a lib after some dlclose
Diffstat (limited to 'src')
-rwxr-xr-xsrc/include/box64context.h1
-rwxr-xr-xsrc/librarian/library.c46
-rwxr-xr-xsrc/wrapped/wrappedlibdl.c9
3 files changed, 39 insertions, 17 deletions
diff --git a/src/include/box64context.h b/src/include/box64context.h
index 2424c130..2c0063e2 100755
--- a/src/include/box64context.h
+++ b/src/include/box64context.h
@@ -57,6 +57,7 @@ typedef struct needed_libs_s {
 
 void free_neededlib(needed_libs_t* needed);
 needed_libs_t* new_neededlib(int n);
+needed_libs_t* copy_neededlib(needed_libs_t* needed);
 void add1_neededlib(needed_libs_t* needed);
 
 typedef struct base_segment_s {
diff --git a/src/librarian/library.c b/src/librarian/library.c
index 20b663db..109a11ba 100755
--- a/src/librarian/library.c
+++ b/src/librarian/library.c
@@ -598,6 +598,8 @@ int IsSameLib(library_t* lib, const char* path)
     int ret = 0;
     if(!lib) 
         return 0;
+    if(lib->type==LIB_UNNKNOW)
+        return 0;
     char* name = Path2Name(path);
     if(!strchr(path, '/') || lib->type==LIB_WRAPPED || !lib->path) {
         if(strcmp(name, lib->name)==0)
@@ -1039,6 +1041,19 @@ void add1_neededlib(needed_libs_t* needed)
     needed->names = (char**)realloc(needed->names, needed->cap*sizeof(char*));
     needed->size++;
 }
+needed_libs_t* copy_neededlib(needed_libs_t* needed)
+{
+    if(!needed)
+        return NULL;
+    needed_libs_t* ret = (needed_libs_t*)calloc(1, sizeof(needed_libs_t));
+    ret->cap = needed->cap;
+    ret->size = needed->size;
+    ret->libs = (library_t**)calloc(ret->cap, sizeof(library_t*));
+    ret->names = (char**)calloc(ret->cap, sizeof(char*));
+    memcpy(ret->libs, needed->libs, ret->size*sizeof(library_t*));
+    memcpy(ret->names, needed->names, ret->size*sizeof(char*));
+    return ret;
+}
 
 void setNeededLibs(library_t* lib, int n, ...)
 {
@@ -1060,39 +1075,52 @@ void IncRefCount(library_t* lib, x64emu_t* emu)
     switch (lib->type) {
         case LIB_WRAPPED:
             ++lib->w.refcnt;
+            if(lib->w.needed)
+                for(int i=0; i<lib->w.needed->size; ++i)
+                    IncRefCount(lib->w.needed->libs[i], emu);
             break;
         case LIB_EMULATED:
             ++lib->e.elf->refcnt;
+            if(lib->e.elf->needed)
+                for(int i=0; i<lib->e.elf->needed->size; ++i)
+                    IncRefCount(lib->e.elf->needed->libs[i], emu);
     }
 }
 
 int DecRefCount(library_t** lib, x64emu_t* emu)
 {
     if(!lib || !*lib)
-        return 0;
+        return 1;
     if((*lib)->type==LIB_UNNKNOW)
-        return 0;
-    int ret = 0;
+        return 1;
+    int ret = 1;
+    needed_libs_t* needed = NULL;
+    int freed = 0;
     switch ((*lib)->type) {
         case LIB_WRAPPED:
+            needed = (*lib)->w.needed;
             if(!(ret=--(*lib)->w.refcnt)) {
-                if((*lib)->w.needed)
-                    for(int i=0; i<(*lib)->w.needed->size; ++i)
-                        DecRefCount(&(*lib)->w.needed->libs[i], emu);
+                needed = copy_neededlib(needed);
+                freed=1;
                 Free1Library(lib, emu);
             }
             break;
         case LIB_EMULATED:
+            needed = (*lib)->e.elf->needed;
             if(!(ret=--(*lib)->e.elf->refcnt)) {
-                if((*lib)->e.elf->needed)
-                    for(int i=0; i<(*lib)->e.elf->needed->size; ++i)
-                        DecRefCount(&(*lib)->e.elf->needed->libs[i], emu);
+                needed = copy_neededlib(needed);
+                freed=1;
                 removeLinkMapLib(*lib);
                 FiniLibrary(*lib, emu);
                 Free1Library(lib, emu);
             }
             break;
     }
+    if(needed)
+        for(int i=0; i<needed->size; ++i)
+            DecRefCount(&needed->libs[i], emu);
+    if(freed)
+        free_neededlib(needed);
     return ret;
 }
 
diff --git a/src/wrapped/wrappedlibdl.c b/src/wrapped/wrappedlibdl.c
index 2089a12c..ab154a27 100755
--- a/src/wrapped/wrappedlibdl.c
+++ b/src/wrapped/wrappedlibdl.c
@@ -37,8 +37,6 @@ void FreeDLPrivate(dlprivate_t **lib) {
     box_free(*lib);
 }
 
-static needed_libs_t dl_loaded = {0};
-
 // dead_cells consider the "2" value to be some king of issue?
 #define MIN_NLIB 3
 
@@ -146,9 +144,6 @@ void* my_dlopen(x64emu_t* emu, void *filename, int flag)
             snprintf(dl->last_error, 129, "Cannot dlopen(\"%s\"/%p, %X)\n", rfilename, filename, flag);
             return NULL;
         }
-        add1_neededlib(&dl_loaded);
-        dl_loaded.names[dl_loaded.size-1] = tmp.names[0];
-        dl_loaded.libs[dl_loaded.size-1] = tmp.libs[0];
         lib = GetLibInternal(rfilename);
         RunDeferredElfInit(emu);
     } else {
@@ -339,9 +334,7 @@ int my_dlclose(x64emu_t* emu, void *handle)
         return -1;
     }
     dl->count[nlib] = dl->count[nlib]-1;
-    if(!DecRefCount(&dl->libs[nlib], emu)) {
-        dl->count[nlib] = 0;
-    }
+    DecRefCount(&dl->libs[nlib], emu);
     return 0;
 }
 int my_dladdr1(x64emu_t* emu, void *addr, void *i, void** extra_info, int flags)