Bibliothèque partagée de déchargement forcé C ++

J’essaie de créer une application qui recharge une bibliothèque partagée plusieurs fois. Mais à un moment donné, dlmopen échoue avec une erreur

/usr/lib/libc.so.6: cannot allocate memory in static TLS block

Voici le code minimal reproduisant ce problème:

 #include  #include  #include  int main() { for (int i = 0; i < 100; ++i) { void *lib_so = dlmopen(LM_ID_NEWLM, "lib.so", RTLD_LAZY | RTLD_LOCAL); if (lib_so == NULL) { printf("Iteration %i loading failed: %s\n", i, dlerror()); return 1; } dlclose(lib_so); } return 0; } 

Et vide lib.cpp, compilé avec

 g++ -rdynamic -ldl -Wl,-R . -o test main.cpp g++ -fPIC -shared lib.cpp -o lib.so 

Mettre à jour

Il semble que ça plante même avec un seul thread. La question est: comment puis-je forcer un déchargement de bibliothèque ou une destruction d’espaces de noms inutilisés créés avec LM_ID_NEWLM ?

Il existe une limite intégrée au nombre d’espaces de noms de mappes de liens disponibles pour un processus. Ceci est plutôt mal documenté dans le commentaire:

L’implémentation de la glibc prend en charge 16 espaces de noms maximum

dans la page de manuel.

Une fois que vous avez créé un espace de noms de carte de liens, vous ne pouvez plus le supprimer via des API. C’est juste la façon dont il est conçu, et il n’y a pas vraiment de moyen de contourner ce problème sans éditer la source glibc et sans append des hooks.

Utiliser des espaces de noms pour recharger une bibliothèque ne recharge pas réellement la bibliothèque – vous chargez simplement une nouvelle copie de la bibliothèque. Ceci est l’un des cas d’utilisation des espaces de noms – si vous dlopen d’ dlopen plusieurs fois la même bibliothèque, vous obtiendrez le même descripteur dans la même bibliothèque. Cependant, si vous chargez la seconde instance dans un espace de noms différent, vous ne recevrez pas le même handle. Si vous souhaitez effectuer le rechargement, vous devez décharger la bibliothèque à l’aide de dlclose , qui déchargera la bibliothèque une fois la dernière référence à la bibliothèque publiée.

Si vous voulez tenter de forcer le déchargement d’une bibliothèque, vous pouvez essayer d’émettre plusieurs appels dlclose jusqu’à ce qu’il se décharge; Cependant, si vous ne savez pas ce que la bibliothèque a fait (par exemple, les threads générés), il n’y a peut-être aucun moyen d’empêcher un crash dans ce cas.

Les anciennes versions de glibc peuvent avoir des bogues liés à ceci:

https://bugzilla.redhat.com/show_bug.cgi?id=89692 https://sourceware.org/bugzilla/show_bug.cgi?id=14898

Quelle version utilisez-vous? Essayez d’utiliser une nouvelle version de glibc, votre code fonctionne plutôt bien sur mon ordinateur (glibc 2.23).