3 votes

Pourquoi ai-je une erreur de "stockage" sur ma bibliothèque partagée Ada lors de l'exécution sous un JVM

Nous avons une bibliothèque partagée Ada compilée par GnatPro 19.2 que nous appelons à travers un appel JNA.

Notre application fonctionne bien sous Windows. Lorsque nous la portons sous Linux, l'application plante aléatoirement avec une exception Ada :

erreur de stockage ou accès mémoire erroné.

Le débogage avec gdb (en attachant le processus) n'aide pas beaucoup. Nous obtenons différents SIGSEGV, nous continuons, et après un certain temps nous obtenons l'erreur de stockage sans stack call utilisable.

Notre bibliothèque partagée peut être utilisée avec un appel natif Python sans aucun problème. Le problème est probablement du côté Java.

Nous avons essayé de passer à un autre JVM (openjdk ou jdk officiel) sans succès.

Pourquoi cela se produit-il ? Y a-t-il un moyen de contourner ce problème ?

7voto

Jean-François Fabre Points 94672

Le premier indice est d'obtenir un tas de SIGSEGV lors de la tentative d'attachement d'un débogueur à l'application, puis de voir le programme reprendre lors de la poursuite.

Cela signifie que le signal SIGSEGV est géré du côté Java, comme confirmé dans Pourquoi l'application java plante-t-elle dans gdb mais fonctionne normalement en réalité?.

Java utilise des chargements spéculatifs. Si un pointeur pointe vers une mémoire adressable, le chargement réussit. Rarement, le pointeur ne pointe pas vers une mémoire adressable, et le chargement tenté génère un SIGSEGV ... que le runtime Java intercepte, rend la mémoire à nouveau adressable et redémarre l'instruction de chargement.

Maintenant, ce qui se passe, c'est que par défaut, le runtime GNAT installe un nouveau gestionnaire de signal pour capturer les SIGSEGV et rediriger vers une exception Ada propre. Une caractéristique intéressante des exceptions Ada est qu'elles peuvent afficher la trace de la pile, même sans débogueur. Cette redirection du gestionnaire SIGSEGV le permet.

Mais dans le cas de Java, étant donné que Java utilise des chargements spéculatifs, les SIGSEGV sont attendus de temps en temps du côté Java. Donc, lorsque la bibliothèque partagée Ada a été chargée et initialisée, le gestionnaire SIGSEGV Ada est installé, capture ces SIGSEGV "normaux" et s'arrête immédiatement.

Notez que cela ne se produit pas sous Windows. Le runtime Java ne peut probablement pas utiliser ce mécanisme de chargement spéculatif en raison des limitations de Windows lors de la gestion des accès par violation de mémoire.

La gestion des signaux se fait dans s-intman.adb

 -- Vérifier que le traitement de la propagation d'exception ici est cohérent avec
  -- le traitement du signal d'abandon dans les opérations System.Task_Primitives.

  case signo is
     when SIGFPE  => raise Constraint_Error;
     when SIGILL  => raise Program_Error;
  --   when SIGSEGV => raise Storage_Error;  -- en commentant cette ligne, cela devrait corriger le problème
     when SIGBUS  => raise Storage_Error;
     when others  => null;
  end case;
end Notify_Exception;

Maintenant, il faudrait reconstruire un nouveau runtime natif et l'utiliser à la place de celui par défaut. C'est assez fastidieux et source d'erreurs. Ce fichier fait partie de la bibliothèque gnarl. Nous devrions reconstruire la bibliothèque gnarl dynamiquement avec les bonnes options -gnatp -nostdinc -O2 -fPIC pour créer une substitution de bibliothèque gnatrl ... et refaire cela lors de la mise à niveau du compilateur...

Heureusement, AdaCore a fourni une solution alternative:

Créez d'abord un fichier de pragmas dans le répertoire du projet .gpr (appelons-le no_sigsegv.adc) contenant:

pragma Interrupt_State (SIGSEGV, SYSTEM); 

pour indiquer au runtime de ne pas installer le gestionnaire SIGSEGV

Ensuite, ajoutez ceci au package Compiler du fichier .gpr:

  package Compiler is
    ...
      for local_configuration_pragmas use Project'Project_dir & "/no_sigsegv.adc";

et reconstruisez tout depuis le début. Test : pas un seul crash en aucun cas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X