Page 1 sur 1

php_str_replace_in_subject, bug de PHP.

Posté : 10 juin 2008, 12:24
par Hywan
Hey :),

J'ai rencontré un super bug avec PHP, et ça m'embête pas mal.
J'ouvre ma page, l'application httpd plante magistralement, EXC_BAD_ACCESS et KERN_PROTECTION_FAILURE au rendez-vous, ça démarre fort.
Je regarde le thread 0 crashed et je me rends compte que la fonction php_str_replace_in_subject pose problème. Elle dépend de php_str_replace_common, qui à son tour, dépend de zend_do_fcall_common_helper_SPEC.

Je regarde sur Internet, et notamment du côté du bug tracker de PHP et je trouve le bug 20221. Horreur, il existe depuis 2002 et il n'est pas toujours pas réparé. On trouve encore des traces de ce bug en PHP 5.0.4, je suis en 5.2.5 et le bug existe toujours.

Donc, j'ai fini par trouver où est-ce qu'il se déclenchait. À un moment donné, pas de bol, j'utilise la fonction str_replace et ça me fout tout en l'air. Je n'arrive pas vraiment à comprendre pourquoi, car je n'utilise que des chaînes (et pas des tableaux, même si une chaîne est un tableau, je pense que PHP fait la différence pour cette fonction non ?). Voilà. Mais j'ai besoin de cette fonction, alors je fais comment ? J'attends un correctif ou alors j'utilise une autre fonction ?

Merci :).

Posté : 10 juin 2008, 13:36
par nicolas
As-tu un exemple de code permettant de reproduire le bug ?
Dans la doc, il semble que le bug a été corrigé :
Le comportement de cette fonction a changée. Dans les version précédentes, un bogue existait lors de l'utilisation de tableaux avec les paramètres search et replace en même temps. Les index de search qui étaient vides étaient ignorés, mais le pointeur interne de replace n'étais pas incrémenté. Cela a été corrigé en PHP 4.3.3, tout script s'appuyant sur ce bogue, doit supprimer les entrées vides avant d'appeler cette fonction pour imiter le comportement d'origine.
Ou alors je n'ai pas compris quel était le problème, ce qui est tout à fait possible.

Posté : 10 juin 2008, 14:12
par Hywan
Non c'est un bug différent, mais je n'arrive pas à me l'expliquer.

Je cherche "\n" que je remplace par "\n " dans un objet qui contient une collection de collections. Rassurer, c'est tout à fait léger. Chaque objet est transformé en chaîne via __toString. Mais je n'ai pas ce problème avec des petites collections, seulement avec des grosses … Peut-être un problème de mémoire ? Je me questionne.

Posté : 30 juin 2008, 16:00
par Hywan
Aïe, toujours le même bug.
Alors, j'ai un peu fouiné et j'ai essayé plusieurs choses.

Voici d'abord le problème :
str_replace("\n", "\n  ", $element);
J'effectue cette opération afin d'intenter proprement mon code. J'ai vu que PHP prenait beaucoup de mémoire quand j'ai des chaînes assez grosses (20 ou 30 lignes de 80 caractères en gros) et que c'était une cause probable du plantage. Bien, j'essaye preg_replace mais elle prend presque 5 fois plus de mémoire, pas une bonne idée.

Je suis un peu perdu et je ne sais pas quoi faire. Je ne supporte pas l'idée que mon code soit tout pas beau (même si c'est juste histoire de 2 espaces par ci par là), et quoi que je fasse, je retombe sur ce problème de mémoire. PHP tente d'allouer plus de mémoire que le php.ini lui autorise, et paf, erreur.

Une idée ?

Posté : 30 juin 2008, 16:06
par katagoto
Bah, j'en ai bien une mais...
$element=implode("\n  ", explode ("\n", $element));
Bon c'est bof mais bon :?

Posté : 30 juin 2008, 16:13
par Hywan
Déjà essayé, pareil.

Posté : 30 juin 2008, 16:16
par katagoto
Bah tu aura un code dégueulasse ^^

Pour avancé : Tu avais essayé quoi comme REGEX ?

Posté : 30 juin 2008, 16:23
par Hywan
Avec str_replace :
str_replace("\n", "\n  ", $element);
Avec preg_replace :
preg_replace("#\n#", "#\n  #", $element);
Original, je sais …

str_replace doit être la fonction qui prend le moins de mémoire je pense (si on compare toutes les cousines ereg, i, etc.).

Posté : 30 juin 2008, 16:34
par katagoto
Et ça fait planté ton script ???

Posté : 30 juin 2008, 16:38
par Hywan
Cf. mon premier message ……

Posté : 30 juin 2008, 16:56
par katagoto
tu as essayé ça :
preg_replace("#\n#", "#\n\s\s#", $element);
Je penses que c'est le fait de remplacer un caractère par le même caractère mais avec un plus...

Posté : 30 juin 2008, 17:21
par Sékiltoyai
Utilise strtr() à la place de str_replace() . En principe cela devrait mieux fonctionner...

Posté : 30 juin 2008, 17:40
par Hywan
Même problème. C'est à devenir fou.

Posté : 30 juin 2008, 18:28
par savageman
T'as fait quoi ?

Code : Tout sélectionner

strtr($chaine, array("\n" => "\n "));
?

Sinon t'as le droit à exec() ?

J'ai une version en .c si tu veux :

Code : Tout sélectionner

char *str_replace(const char* search, const char* replace, const char* str){ long i = 0; long size_search = strlen(search); long size_str = strlen(str); char *copy = (char *)malloc((size_str + 1) * sizeof(char)); char *found = copy; char *out = NULL; // -- Pour connaitre le nombre de caractères dans out, on récupère // -- le nombre de fois qu'apparait search, puis on le multiplie par // -- la différence entre la taille de la chaine de remplacement // -- et la taille de la chaine à rechercher. out = (char *)malloc((size_str + (substr_count(search, str) * (strlen(replace) - size_search)) + 1) * sizeof(char)); out[i] = '\0'; // Par mesure de sécurité. // On copie la chaine pour pouvoir la manipuler sans risques, et on fait une recherche. strcpy(copy, str); found = strstr(copy, search); while (found != NULL){ // copy = position trouvée i = (found-copy); strncat(out, copy, i); strcat(out, replace); copy += i + size_search; found = strstr(copy, search); } strcat(out, copy); free(copy); return out; }

Posté : 30 juin 2008, 18:36
par Hywan
Uè j'ai fait ça, mais rien n'y fait :(.