Erreur dans realloc: sysmalloc assertion failed

a marqué ce sujet comme résolu.

Bonjour,

je suis en train de programmer un terminal, en C. Je suis en train d’implémenter l’autocomplétition. Pour cela, j’ai créé une fonction commandeToStr qui prends une commande en argument et qui renvoie le texte que la commande renvoie. Je l’appelle par exemple comme cela :

1
2
3
4
5
char* searchProg(char* lop, char* mot){
    char  ex[99999];
    snprintf(ex, 99999, "echo '%s' | grep ^%s", lop, mot);
    return commandeToStr(ex);
}

Ou lop est la string contenant la liste des programmes, et mot un début de nom de programme.

Voici sa définition :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
char* commandeToStr(char* comm){
    char* ret = 0;  // Do not forget !!
    char buf[1024];
    int sizeTot;
    int size;
    FILE* firstRes = popen(comm, "r");
    while(fgets(buf, 1024, firstRes)) {
        size = strlen(buf);
        sizeTot = sizeTot + size;
        ret = realloc(ret, sizeTot);
        strcat(ret, buf);
    }
    return ret;
}

J’appelle cette fonction en commençant le nom d’un programme et je presse tab. La plupart du temps, cela marche bien. Mais quand je spam ’tab’, j’obtient forcément au bout d’un moment :

1
2
a.out: malloc.c:2401: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
Abandon (core dumped)

J’ai vu plusieurs personnes ayant eu le même problème sur le net, mais je n’ai pas trouvé de solution…

Merci d’avance !

+0 -0

Le tableau ex d’une taille de 99999 me semble une mauvase idée.

Tu libères bien ret ? Ce n’est pas comme ça qu’on utilise realloc. Tu ne fais aucune vérification du retour, c’est vraiment important.

De manière général, vérifie plus souvent tes retours de fonction

PS: sizeTot n’est pas initialisée ? C’est très certainement ton problème. De manière générale initialise tes variables.

Ce n’est pas le seul problème. Par exemple, ret est alloué mais jamais initialisée. Du coup ta chaine peu commencer par n’importequoi. Tu ne prends pas en compte le '\0' finale de chaine non plus (dans l’allocation avec realloc.

+1 -0

Merci pour vos réponses.

Le tableau ex d’une taille de 99999 me semble une mauvase idée.

Je sais, c’est en attendant de faire quelque chose de plus élégant, ca fait le job.

ret est alloué mais jamais initialisée.

Je l’initialise à 0, du coup realloc est égal à malloc non ?

Ce n’est pas comme ça qu’on utilise realloc

Mais d’après man :

The realloc() function returns a pointer to the newly allocated memory, which is suitably aligned for any built-in type and may be different from ptr, or NULL if the request fails.

Il faudrait juste vérifier qu’il n’est pas NULL, non ?

PS: sizeTot n’est pas initialisée ? C’est très certainement ton problème. De manière générale initialise tes variables.

Effectivement c’est bizarre, mais même en l’initialisant j’ai le même problème.

Tu ne prends pas en compte le ’\0’ finale de chaine non plus (dans l’allocation avec realloc.

YES ! J’ai remplacé par realloc(ret, sizeTot+1) et ca marche ! Merci beaucoup !

Moralité, strlen ne compte pas le \0. Logique en fait.

Aussi, je trouve bizarre de faire appel à popen simplement pour vérifier qu’une chaîne débute par une autre. Tu as pensé à strncmp ?

Certes, mais je l’utilise aussi pour :

1
return commandeToStr("find $(echo $PATH | sed s/:/' '/g) | grep -v /$ | awk -F/ '{print $NF}' | sort | uniq");
-° < Smiley buggé … ?

Merci à vous !

Tu ne dois pas initialisé ret à 0 mais à NULL. Tu me diras, ce n’est pas super important mais quand même un peu.

Pour realloc, c’est plus compliqué que juste vérifier le retour. Mais justement on a un tuto pour ça.

Ensuite, quand je parlais de l’initialisation de ret je parlais de l’initialisation du retour de realloc.

C’est-à-dire que lorsque tu as bien vérifié que realloc faisait ce qu’il doit faire et que tout est bon, tu dois faire :

1
ret[0] = '\0';

Pour au moins la première fois. Car realloc ne garanti pas que l’espace aloué commence par un ’\0’.

Ce que je te conseil de faire, c’est avant ta boucle tu fais un :

1
2
3
4
5
ret = malloc(1);
if( ret == NULL ) {
 // Gestion de l'erreur
}
ret[0] = '\0';

Non, balise de code source buggé, :-°
C’est corrigé dans la prochaine version de ZdS.

+0 -0

Certes, mais je l’utilise aussi pour :

1
return commandeToStr("find $(echo $PATH | sed s/:/' '/g) | grep -v /$ | awk -F/ '{print $NF}' | sort | uniq");
-° < Smiley buggé … ?
ez613

Qui me paraît aussi loin d’être idéal, ça fait passer du temps dans des traitements inutiles. Et dépendre d’un shell pour en coder un, je trouve ça un peu bizarre comme situation.

D’ailleurs, je parlais de strncmp, mais tu aurais encore mieux de construire un arbre par préfixes de toutes tes commandes existantes.

Parce que tu l’utilises comme une chaine de caractère

Supposons que le premier realloc te donne ça en mémoire :

1
ret[0] == 'a';ret[1] == 1;ret[2] == 0;

Alors ta chaine serra invalide quand tu ferras le strcat.

+0 -0

Salut,

Tu ne dois pas initialisé ret à 0 mais à NULL. Tu me diras, ce n’est pas super important mais quand même un peu.

ache

Juste pour dire, les deux écritures sont correctes voire identiques dans le cas où la macroconstante NULL est remplacée par zéro.

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.

ISO/IEC 9899:201x, doc. N1570, 6.3.2.3, Pointers, al. 3, p. 55

NULL which expands to an implementation-defined null pointer constant;

ISO/IEC 9899:201x, doc. N1570, 7.19, Common definitions <stddef.h>, al. 2, p. 288
+0 -0

@Taurre: Certes mais 0 est utilisé pour signaler le stockage d’un nombre et NULL signale l’utilisation d’un pointeur alors que ’\0’ signale l’utilisation d’un charactère1.

Comme je le dis dans mon message, ce n’est pas très important (dans le sens où ils sont égaux).


  1. Alors, j’aborde le sujet tout de suite. Je sais que la norme ne prévoit pas de valeur pour \0 ni même de charset standard pour le C. Mais dans tous les charsets que je connaisse 0 est utilisé comme caractère NUL. Et je ne connais aucun compilateur C qui interprète '\0' comme autre chose que le caractère NUL, d’ailleurs la norme l’utilise dans ses exemples sans vraiment le spécifier correctement. De plus, il peut entrer dans le cadre de l’échapement octal ’\0..’ comme cas limite valant donc 0. 

+0 -0

@Taurre: Certes mais 0 est utilisé pour signaler le stockage d’un nombre et NULL signale l’utilisation d’un pointeur alors que ’\0’ signale l’utilisation d’un charactère.

ache

En effet, à la lecture cela peut avoir plus de sens de différencier les écritures.

Alors, j’aborde le sujet tout de suite […]

ache

C’est pas qu’il peut entrer dans le cadre d’un échapement octal, c’est un échapement octal valant zéro (la syntaxe étant \nnn où seul le premier chiffre [« n » ici] est obligatoire). Par ailleurs, '\0' est toujours traduit vers le caractère nul du jeu d’exécution.

A byte with all bits set to 0, called the null character, shall exist in the basic execution character set; it is used to terminate a character string.

ISO/IEC 9899:201x, doc. N1570, 5.2.1, Character sets, al. 2, p. 22

The numerical value of the octal integer so formed specifies the value of the desired character or wide character.

ISO/IEC 9899:201x, doc. N1570, 6.4.4.4, Character constants, al. 5, p. 68

Édit : cela étant dit, la formulation de l’exemple un peu plus bas est assez malheureuse.

EXAMPLE 1 The construction ’\0’ is commonly used to represent the null character.

ISO/IEC 9899:201x, doc. N1570, 6.4.4.4, Character constants, al. 12, p. 69

Cela laisse sous-entendre, « c’est utilisé le plus souvent, mais c’est pas garantit d’être le caractère nul ». Sauf que si, c’est garantit, cela fait juste allusion à l’emploie d’une constante entière à la place de '\0'.

+0 -0

Merci pour ces précisions :)

J’ai toujours trouvé la spécification de ’\0’ très mauvaise, le seul souvenir que j’ai c’est une remarque qui disait en bref que c’était admis de manière commun que ’\0’ était le caractère final. Apparement je n’ai pas su chercher.

+0 -0

J’ai toujours trouvé la spécification de ’\0’ très mauvaise, le seul souvenir que j’ai c’est une remarque qui disait en bref que c’était admis de manière commun que ’\0’ était le caractère final. Apparement je n’ai pas su chercher.

ache

La norme est sûrement pas un exemple de clarté, je suis le premier à m’y noyer, même si je me suis fais à sa structure et que je sais plus ou moins où chercher une info. ^^"

Chaque partie du langage étant définie dans son coin, il faut souvent combiner plusieurs points pour avoir le fin mot de l’histoire, ici : définition du caractère nul côté jeu de caractère (un byte avec tous ses bits à zéro), puis mise en perspective avec les constantes de type caractère : si elle est définie à l’aide d’une séquence octale ou hexadécimale, alors il n’y a pas de conversion jeu de caractère source -> jeu de caractère d’exécution, c’est la valeur au sein du jeu de caractère d’exécution qui est directement spécifiée (ce qui peut poser problème si la valeur précisée ne correspond à rien, genre \xFF en ASCII). Comme il doit exister au sein du jeu de caractère d’exécution un caractère nul correspondant à un byte avec tous ses bits à zéro, on a jamais de problème en écrivant '\0'.

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte