Bug 5: Argument manquant lors de l'appel à une subroutine


Le problème

Nous faisons appel à une subroutine réclamant 5 arguments en entrée, mais nous ne lui en donnons que 4. Il y a donc un problème de segmentation fault (core dumped). Cela correspond à une erreur mémoire c'est à dire dire qu'on essaie d'accéder à un espace mémoire qui n'est pas autorisé. 

Nous pourrions imaginer le même mais avec 6 arguments en entrée pour 5 requis par exemple.


Option de débogage

Il n'existe pas pas d'option à la compilation sous GNU fortran permettant de détecter ce genre de problème directement. Il existe deux manières de détecter ce genre de problème: l'utilisation d'un débogueur ou la création d'interface.

Première méthode : Utilisation d'un debogueur:

Il va falloir passer par le débogueur gdb ou DDD avec l'option -g à la compilation afin de voir une erreur.

Quand on lance notre programme avec gdb, on obtient l'erreur suivante:

Program received signal SIGSEGV, Segmentation fault.
0x000000000040261e in fill_array (x=..., i1=1, i2=300, j1=1, 
   j2=<error reading variable: Cannot access memory at address 0x0>)
    at fill_array.f90:2
2    subroutine fill_array(x,i1,i2,j1,j2)

Que l'on peut interpréter facilement par le fait que dans la subroutine fill_array il y a un problème de segmentation à la ligne 2, et plus précisément que la variable j2 n'est pas stockée dans la mémoire donc n'a pas été entrée à l'appel de la subroutine.

Notons que si on fait l'inverse, c'est à dire on entre trop d'arguments, il n'est pas possible de le détecter avec gdb.

Seconde méthode: utilisation d'interfaces (méthode avancée)

Il est également possible d'utiliser des interfaces. Cette méthode est plus longue que la précédente à mettre en place, mais aura l'avantage de détecter les erreurs dès la compilation.

Qu'est ce qu'une interface? Une interface est un processus Fortran que l'on peut placer dans le programme principal ou dans un module pour ne pas encombrer celui-ci. Une interface fait référence à une subroutine quand le programme principal l'appelle et va vérifier qu'ils sont bien connectés.

Mais bien mieux que de long discours voici un exemple de code:

INTERFACE

    SUBROUTINE volume_cone (r,h)

        REAL, volume_cone

        REAL, INTENT(IN) :: r,h

    END SUBROUTINE volume_cone

END INTERFACE

Vous pouvez télécharger ici le fichier contenant un module avec les interfaces dans notre cas et le makefile ajusté en conséquence.

 

Une interface est extrêmement pratique car elle détecte les problème dès la compilation, et nous renvoie un rapport d'erreur assez précis:

gfortran -c -g mod_interface.f90
gfortran -c -g buggy_program.f90
buggy_program.f90:65.35:
        call fill_array(psi,1,nx,1)
                                   1
Error: Missing actual argument for argument 'j2' at (1)
make: *** [buggy_program.o] Error 1

Les deux premières lignes sont des étapes de la compilation.

La troisième ligne vous indique dans "quel_fichier":"quelle_ligne"."quelle_colonne" est l'erreur.

La ligne suivante vous montre explicitement la partie du code qui est deficient, ici le nombre d'argument appelé pour la subroutine fill_array.

La cinquième ligne vous qu'il manque l'argument 'j2' quand vous appelez la subroutine fill_array.

Enfin la dernière ligne indique que la compilation c'est arrêtée ici, et qu'elle a échouée.

 

Ne vous reste plus qu'à corriger votre erreur dans votre fichier source.