kAworu's avatar

c'est pas la taille qui compte

publié par kAworu
il y a environ un an

En C pour travailler avec les path y a une macro sympa: MAXPATHLEN. En faite, y a aussi PATH_MAX et comme j'ai jamais trouvé la profonde différence entre les deux, j'ai demandé à google. Dans mes recherches, je voulais aussi savoir si la valeur de MAXPATHLEN (ou PATH_MAX) représente la taille réelle du chemin le plus long, ou la taille du buffer contenant le chemin le plus long (la différence entre les deux est que le buffer a besoin d'un slot supplémentaire pour le '\0').

J'ai finalement dérivé (sur le web, on dérive. en tout cas moi souvent.) sur un combat mené par GNU contre ces macros, qui reflète une guerre plus globale de GNU contre les limites arbitraires.

C'est la façon dont tu t'en sert

Mais bon, c'est Hurd qui a la plus grosse quand même

Donc j'atteris ici, une idée de projet de gsoc, la guerre ouverte contre MAXPATHLEN et PATH_MAX. En résumé, POSIX n'exige pas la présence des macros PATH_MAX et MAXPATHLEN, et hurd ne les définit pas. Ça argumente à coup de lien vers un blog post qui explique que de toute manière t'arrives à créer des path plus grand que MAXPATHLEN.

insane what?

Malgré les yeux qui piquent à cause du code C++ qu'on trouve sur le blog post en question, on en tire une conclusion intéressante, finalement pas très surprenante:

c'est la dèche.

ugly

POSIX n'exige pas que l'OS définisse MAXPATHLEN et/ou PATH_MAX, mais le prototype de getcwd(3) utilise implicitement une limite:

char * getcwd(char *buf, size_t size);

Tel que défini par POSIX, pour utiliser getcwd(3) sans MAXPATHLEN il faut faire un loop bien moche, une sorte de brute force de ton programme VS ton OS, voilà un petit exemple:

size_t s = 1024; /* or 42, or whatever */
char *path = NULL;
do {
    s *= 2;
    path = realloc(path, s);
    if (path == NULL)
        break; /* errno is set to ENOMEM */
    if (getcwd(path, s) == NULL) {
        if (errno == ERANGE) {
            /* expected, we will retry with a larger buffer. */
            continue;
        } else {
            /* unexpected, some error from getcwd(3). */
            free(path);
            path = NULL;
        }
    }
} while (/*CONSTCOND*/0);

/*
 * here we have either path == NULL and errno set, or path is the resolved path
 * returned by getcwd(3).
 */

ugly ugly

Mieux (ou pire, je sais pas) realpath(3) est inutilisable sans MAXPATHLEN.

char * realpath(const char *file_name, char *resolved_name);

Le prototype ici demande que l'on connaisse la taille de resolved_name avant, au risque d'un joli buffer overflow.

Comment qu'il faut faire alors?

1. rend ton code moche

T'utilises des extensions. POSIX défini pas ce qui se passe quand tu donne NULL à realpath(3) et getcwd(3) (pour resolved_name et respectivement buf), et plusieurs libc (FreeBSD et glibc pour realpath(3), FreeBSD, OpenBSD, NetBSD et glibc pour getcwd(3)) en profitent pour faire en sorte que la fonction retourne un buffer mallocé de la taille apropriée. glibc défini aussi des extensions GNUish, que ma maman m'a défendu de nommer ici. Bien évidement le tout protégé par de immondes #ifdef pour pas faire n'importe quoi n'importe où.

2. bloat ton projet

Tu réécris la moitié de la libc (pendant la pause de midi, feignasse).

3. oublie la portabilité

T'utilises MAXPATHLEN ou PATH_MAX, et pis bon ba, ton code FAIL sous GNU/Hurd.

bave break™, parce que tu l'as mérité

Dans la guideline de porting Hurd on trouve sous la rubrique dédiée à MAXPATHLEN et PATH_MAX des liens vers deux patch (dont un de pulse-audio) avec des loop ultra moche comme celui de l'exemple de getcwd(3) (mais en encore plus moche, prépares les mouchoirs). Le comble, c'est qu'ils servent d'exemple pour fixer les projets qui pas-compilent sous Hurd parce qu'ils usent de MAXPATHLEN ou PATH_MAX.

Ce qui fait quand même sourire c'est qu'ils disent que c'est la faute des méchants programmeurs (i.e. toi et moi) qui écrivent MAXPATHLEN et PATH_MAX, qui "violent" POSIX, et que nul par ils reconnaissent que POSIX est incohérent sur le sujet.

come to the dark side, we have MAXPATHLEN

Après toutes ces lectures et browsage de code, les questions qui m'ont plongé dans cet histoire sont toujours en suspend. Selon le manuel de realpath(3) sous debian:

[…] In 4.4BSD and Solaris the limit on the pathname length is MAXPATHLEN (found in <sys/param.h>). SUSv2 prescribes PATH_MAX and NAME_MAX, as found in <limits.h> or provided by the pathconf(3) function. […]

Finalement dans la pratique on dirait que soit les deux sont définies, soit aucune, donc fais-toi plaiz et choisis celle que tu trouves la plus sexy.

Concernant la taille, on trouve 50% du code qui utilise path[MAXPATHLEN + 1] mais j'ai pas vu de tel chose dans la doc, donc je pense que simplement path[MAXPATHLEN] suffit.

trois commentaires

écrire un commentaire

  1. professional writer il y a quatre mois professional writer's avatar

    Your makros works really good wothout any problems!

  2. cv writing il y a quatre mois cv writing 's avatar

    I was searching for this script! Thanks a lot for publishing it here

  3. professional resume il y a quatre mois professional resume  's avatar

    I completely agree with you in such points!

écrire un commentaire:


(utilisé pour gravatar, ne sera pas affiché)



tu peux utiliser la syntaxe markdown :)