2010-11-09 3 views
0

J'ai actuellement un problème lors de l'implémentation du scénario suivant en utilisant la configuration suivante: GCC 3.4, Linux.Interruption d'une exécution de fonction C et retour à l'appelant C++

J'ai écrit un outil (en C++) qui charge une bibliothèque partagée (écrite en C). Cette bibliothèque a un bug que je ne peux pas influencer pour réparer. Le problème est qu'il lit une entrée et écrit une sortie décodée. Parfois, si l'entrée est incorrecte, cette bibliothèque sans effectuer de vérification commence le décodage des régions de mémoire suivantes. Cela provoque un segfault. Initialement mon idée était de mettre l'entrée dans la mémoire paginée (linux mmap-syscall) et de protéger (mprotect) la dernière page, contre l'accès. En installant un propre gestionnaire SIGSEGV, mon application C++ peut lancer une exception (lorsqu'elle est compilée avec l'option GCC flag -fnon-call-exceptions). Cette exception va interrompre la lecture de C lib. Je savais que cette lib n'allouait aucune mémoire (ou d'autres ressources) qui pourrait être perdue lors du déroulement de la pile. Le scénario entier a bien fonctionné dans mes tests unitaires, où tout était une seule application C++. Mais maintenant, quand le code C de la lib est appelée, mon application s'arrête juste ... Dois-je reconstruire ce C-SO avec le drapeau -fnon-call-exceptions? Je ne peux pas compiler cette lib, mais seulement la relier, puisque je n'ai accès qu'aux fichiers obj.

Voici l'image de l'environnement d'exécution:

+------------C++ APP----------+ 
|        | 
| Install SIGSEGV handler  | 
| code calling C SO functions | 
|        | 
| +----------C SO Functions------------+ 
| | execute producing SIGSEGV  | 
| +------------------------------------+ 
|        | 
| SIGSEGV Handler called  | 
| => throw Exception  | 
|  to stop execution of | 
|  C function    | 
+-----------------------------+ 

D'autres suggestions sont les bienvenues.

Un grand merci,

Ovanes


post-scriptum Je vois quelques suggestions et critiques, mais ils ne sont pas tous optin. Voici pourquoi: J'ai seulement une interface, où je peux lier à la bibliothèque. La bibliothèque est utilisée pour décoder les structures de données. Le problème est que si j'ai un tableau avec la longueur -1 la bibliothèque commence à décoder le tableau de longueur 0xffffff (sur un système 32 bits). Attendre que la lib se bloque dans un processus séparé n'est pas une option à mon avis. Tout d'abord, le décodage prendra d'une part un temps considérable et produira beaucoup de déchets de l'autre. Depuis mon outil doit montrer la sortie décodée de manière fiable aux utilisateurs. Et ils doivent encore être en mesure de comprendre les traces.

Je ne vois pas le point ici pour contourner un SIGSEGV. Tout d'abord, la bibliothèque lit les données et les écrit dans le fichier que j'ai déjà passé. Je peux configurer comment écrire sur ce handle (bufferisé ou non). De plus, je sais exactement qu'il n'alloue aucune donnée ou ressource de tas. Et enfin, il essaie d'accéder à la mémoire que mon application a protégée pour éviter de telles erreurs. Du point de vue de l'utilisateur, je ne peux pas dire à quelqu'un: Désolé la trace binaire était seulement à moitié décodable, parce que certaines données étaient incohérentes. Je sais que ces données étaient inconstantes et je sais exactement comment faire face à cette incohérence. Je peux donc récupérer gracieusement. Je pense que je vais essayer d'utiliser les fonctions POSIX de sigsetjmp/siglongjmp et j'espère qu'elles feront mieux comme exception. En effet, setjmp/longjmp ou sigsetjmp/siglongjmp sont utilisés pour implémenter des exceptions. Oui, j'ai débogué mon application et je vois que la pile d'appels est valide.

+2

Toute chance que vous pouvez bifurquer la bibliothèque, utilisez une autre bibliothèque, ou écrivez votre propre bibliothèque? Essayer de contourner un bogue provoquant SIGSEGV me semble être la course d'un fou ... –

+0

setjmp/longjmp - J'ai oublié ça, mais ils pourraient fonctionner :) Cependant, je ne comprends pas vraiment votre argument contre un processus séparé: votre approche doit également appeler la bibliothèque et attendre qu'elle se termine ou se bloque. J'ai le sentiment qu'il existe des contraintes supplémentaires liées au but de votre application, mais ce n'est pas très clair. – Lars

+0

@Lars: Vous avez peut-être raison. Mais j'ai encore besoin d'implémenter la protection de la mémoire, etc. dans un processus séparé pour ne pas produire autant de sortie. Le problème avec ici est que l'attente de l'écrasement du processus produit pour un seul message environ 200.000,00 plus de sortie. Toute la manipulation va devenir bizarre. Je devrai passer au processus un nom de fichier où ajouter la sortie décodée et attendre qu'elle se termine/plante. Que l'application en attente en cas d'accident devra ouvrir le fichier et y écrire une ligne d'erreur, le fermer, redémarrer la partie décodage et lui passer le nom du fichier. Trop compliqué – ovanes

Répondre

0

Ok les gars,

Je l'ai fait avec sigsetjmp/siglongjmp. Fonctionne comme un charme. Je peux sauter par-dessus la fonction dans la pile de la fonction d'appelant et y faire la manipulation d'erreur.

Merci pour toutes les suggestions.

Cordialement,

Ovanes

1

Malheureusement, je n'ai pas de réponse au problème comme indiqué - avez-vous essayé d'exécuter votre application sous un débogueur, pour voir où cela se termine exactement? Cependant, une approche alternative qui me vient à l'esprit serait de mettre l'utilisation de la bibliothèque défectueuse dans un programme séparé, de la lancer à partir de votre application et de lui transmettre les données via un tube.

+0

J'aime le son de cette approche alternative. Je * pense * que le PO a raison de deviner que son objet partagé C doit être recompilé avec '-fnon-call-exceptions', ce qu'il ne peut pas faire. – zwol

0

Cette question peut-être stupide, mais doit examiner le fichier de base? Ou exécutez votre application dans le débogueur?

+0

@ovanes Ok, c'est nouveau pour moi. –