emscripten-core / emscripten-core/emscripten
[BUG] Dlclose behaves differently as compared to native counterpart
- Lingua principale
- C++
- Stelle
- 27.6k
- Fork
- 3.6k
- Merge medio
- 1g 14h
- PR unite (30g)
- 125
Descrizione
> I don't think you can currently expect dlclose followed by dlopen to replace symbols in the global namespace. I think the first dll to provide I symbol will currently win and that symbol will remain for the life of the program.
>
> If that native behaviour is different to this then I think we would consider a patch to make our behaviour match, in which case please open a bug for that.
_Originally posted by @sbc100 in [#23793](https://github.com/emscripten-core/emscripten/issues/23793#issuecomment-2711234732)_
Here's an example testing the above on my macos
1) main.cpp
```
#include
#include
typedef int (*getXFunc)();
int main() {
// Load lib1
void* handle1 = dlopen("./lib1.dylib", RTLD_NOW | RTLD_GLOBAL);
if (!handle1) {
std::cerr << "Failed to load lib1: " << dlerror() << std::endl;
return -1;
}
getXFunc getX1 = (getXFunc)dlsym(handle1, "getX");
if (!getX1) {
std::cerr << "Failed to get symbol from lib1: " << dlerror() << std::endl;
return -1;
}
std::cout << "Initial x from lib1: " << getX1() << std::endl;
// Close lib1
if (dlclose(handle1) != 0) {
std::cerr << "Failed to close lib1: " << dlerror() << std::endl;
} else {
std::cout << "Closed lib1.so" << std::endl;
}
// Load lib2
void* handle2 = dlopen("./lib2.dylib", RTLD_NOW | RTLD_GLOBAL);
if (!handle2) {
std::cerr << "Failed to load lib2: " << dlerror() << std::endl;
return -1;
}
getXFunc getX2 = (getXFunc)dlsym(handle2, "getX");
if (!getX2) {
std::cerr << "Failed to get symbol from lib2: " << dlerror() << std::endl;
return -1;
}
std::cout << "x after loading lib2: " << getX2() << std::endl;
dlclose(handle2);
return 0;
}
```
2) lib1.cpp
```
#include
int x = 10;
extern "C" int getX() {
return x;
}
__attribute__((constructor))
void init() {
std::cout << "lib1 loaded, x = " << x << std::endl;
}
```
3) lib2.cpp
```
#include
#include
extern "C" int getX(); // Forward declaration
// Define a pointer to x
int* x_ptr = nullptr;
// getX function
extern "C" int getX() {
return *x_ptr;
}
// Constructor runs when lib2 is loaded
__attribute__((constructor))
void init() {
std::cout << "lib2 loaded, checking for symbol 'x'..." << std::endl;
// Look for symbol 'x' in global namespace
void* sym = dlsym(RTLD_DEFAULT, "x");
if (sym) {
std::cout << "Symbol 'x' found from another module." << std::endl;
x_ptr = (int*)sym;
} else {
std::cout << "Symbol 'x' NOT found. Defining x = 99 locally." << std::endl;
static int local_x = 99; // Define our own
x_ptr = &local_x;
}
}
```
Output
```
(xeus-cpp) anutosh491@Anutoshs-MacBook-Air test_undo % clang++ -fPIC -shared -o lib1.dylib lib1.cpp
(xeus-cpp) anutosh491@Anutoshs-MacBook-Air test_undo % clang++ -fPIC -shared -o lib2.dylib lib2.cpp
(xeus-cpp) anutosh491@Anutoshs-MacBook-Air test_undo % clang++ -o main main.cpp
(xeus-cpp) anutosh491@Anutoshs-MacBook-Air test_undo % ./main
lib1 loaded, x = 10
Initial x from lib1: 10
Closed lib1.so
lib2 loaded, checking for symbol 'x'...
Symbol 'x' NOT found. Defining x = 99 locally.
x after loading lib2: 99
```
So I tried finding the symbol `x` in `lib2` once `dlclose` is being applied on `lib1` and if the symbol is not found I print a local x. Does this mean if we use `dlclose` that completely removes the presence of `x` from the global namespace ?
Guida per i contributori
Apri la guida per i contributori
Direzione di ricerca
Inizia eseguendo la riproduzione nativa con main.cpp, lib1.cpp e lib2.cpp, quindi individua i punti di ingresso di Emscripten per il comportamento di dlopen, dlclose e RTLD_DEFAULT. Il lavoro è completo quando è stato stabilito il comportamento previsto dello spazio dei nomi globale dopo dlclose e il risultato di Emscripten è allineato a tale comportamento oppure è chiaramente documentato come diverso.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- cpp, wasm
- Ambito
- operating-systems
- Tipo di issue
- Bug
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Ferma
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 35/100