• # Un simple bug

    Posté par . En réponse au journal Le paranormal en informatique. Évalué à 10.

    Et toi, ami lecteur, as-tu été témoin de phénomènes vraiment bizarres?

    J’en ai eu un hier.

    Qui s’est avéré en fin de compte n’avoir rien d’inexplicable, mais qui sur le coup m’a fait me poser pas mal de questions...

    Un collaborateur me signale qu’il n’arrive pas à exécuter une règle Make particulière :

    $ make patterns
    make: dosdp-tools: Permission denied
    make: *** Makefile:155:patterns] Error 127

    Huh ? Permission denied ?

    Rapide coup d’œil sur la règle patterns dans le Makefile :

    patterns:
     @dosdp-tools generate --table-format=csv [commande tronquée, elle est assez longue et ce n’est pas important]

    Bon, euh, t’as bien installé dosdp-tools, t’as mis l’exécutable dans le PATH ?

    $ which dosdp-tools
    /tools/dosdp-tools/bin/dosdp-tools
    $ dosdp-tools --version
    name: dosdp-tools, version: 0.19.3, scalaVersion: 2.13.18, sbtVersion: 1.6.2

    Ok... dans le contexte du Makefile le PATH est toujours le bon ?

    patterns:
     @which dosdp-tools
     @dosdp-tools generate --table-format-csv [...]
    $ make patterns
    /tools/dosdp-tools/bin/dosdp-tools
    make: dosdp-tools: Permission denied
    make: *** Makefile:156:patterns] Error 127

    Bon, quelque part, ça a du sens, si le problème était que dosdp-tools était introuvable à cause d’un mauvais PATH ou quelque chose dans le genre on aurait un No such file or directory (ENOENT), pas un Permission denied (EACCES)...

    On a vérifié que l’exécutable était bien exécutable ? Il est pas en 644 ? Et tous les dossiers parents sont bien traversables ? Ah ben oui, tout ça c’est bon, puisque ça marche quand on invoque dosdp-tools directement depuis le shell, on l’a vu plus haut...

    Bon, et si on passe le chemin complet dans le Makefile, il se passe quoi ?

    patterns:
     @/tools/dosdp-tools/bin/dosdp-tools --version
    $ make patterns
    name: dosdp-tools, version: 0.19.3, scalaVersion: 2.13.18, sbtVersion: 1.6.2

    Wopitain ça marche. Donc on dirait bien que Make n’arrive pas à trouver l’exécutable, mais dans ce cas pourquoi il nous sort une Permission denied ???

    (À ce stade vous avez peut-être déjà une petite idée... Moi, à ce moment-là, non.)

    Je vous passe un certain nombre d’essais et erreurs, mais parmi les essais, deux ont été « intéressants » :

    patterns:
     if [ true ]; then dosdp-patterns ... ; fi

    Fonctionne !

    patterns:
     exec dosdp-patterns ...

    Fonctionne ! WTF ? Appeler dosdp-patterns tout court échoue avec un Permission denied mais l’appeler via exec fonctionne ?

    Là, je suis à deux doigts de suggérer de décoller et d’atomiser le site depuis une position en orbite, parce que c’est le seul moyen d’être sûr. Mais avant d’en arriver là, je teste un dernier truc (plus par frustration qu’autre chose) : renommer l’exécutable dosdp-tools en dosdp-wtf (en changeant évidemment l’invocation dans le Makefile), et... ça fonctionne !

    En fait, si l’exécutable s’appelle n’importe quoi sauf dosdp-tools, ça fonctionne.

    Ok... est-ce qu’il y aurait un autre dosdp-tools ailleurs dans le PATH (ça n’expliquerait pas pourquoi Make trouverait cet autre dosdp-tools, mais bon, on ne sait jamais) ? Non.

    Là, je commence (enfin) à avoir une idée, sauf que l’explication à laquelle je pense ne devrait en principe pas arriver.

    $ echo $PATH
    /tools:/tools/dosdp-tools/bin:tools/apache-jena/bin:/usr/local/bin:/usr/bin/bin

    Vous voyez le problème ? Le dossier /tools, qui contient un dossier dosdp-tools, est aussi dans le PATH ; et il est avant le dossier /tools/dosdp-tools/bin, qui contient le fichier exécutable dosdp-tools.

    Normalement, ce n’est pas censé être un problème. Lorsqu’on invoque un exécutable sans son chemin complet, le shell sait qu’il doit chercher un fichier exécutable et non un dossier, donc s’il trouve dans le PATH un dossier du même nom que la commande invoquée, le shell l’ignore simplement et continue sa recherche dans le reste du PATH.

    Mais ça, c’est valable pour le shell.

    Il se trouve que GNU Make, lui, a sa propre logique pour trouver un fichier exécutable dans le PATH, indépendamment de celle du shell. Et que depuis la version 4.3, cette logique... est boguée : Make ne vérifie pas si ce qu’il a trouvé dans le PATH est bien un fichier régulier. S’il trouve dans le PATH un dossier avec le même nom que la commande à invoquer, ben... il tente d’invoquer le dossier !

    (Le bug a été corrigé depuis, mais le correctif n’est pas encore disponible dans une version publiée.)

    Voilà, comme je disais au final il n’y a rien d’inexplicable ou de bizarre — un simple bug, par ailleurs déjà connu et même déjà corrigé au moment où je le découvre. Mais deux heures de perdues à cause de ça quand même...