Situation actuelle : PHP2Shell. Deux failles PHP critiques (CVSS 9.2) permettent d'exécuter du code malveillant sans authentification. Correctifs disponibles depuis le 21 octobre 2026.Ce qu'il faut faire maintenant →

memory_limit et Out-of-Memory : ce qui se passe à l'intérieur

Que se passe-t-il lorsqu'un script PHP atteint memory_limit ? Mécanique, nouvelle limite mémoire stricte depuis les correctifs d'octobre et lien avec CVE-2026-109618.

État 6 min de lectureSavoir PHP

En bref : une erreur PHP Out of Memory survient lorsqu'un script veut réserver plus de mémoire que le réglage memory_limit ne le permet (par défaut : 128 Mo par requête). PHP interrompt alors la requête par une erreur fatale et nettoie. C'est précisément ce chemin d'interruption et de nettoyage qui était défectueux dans CVE-2026-109618, l'une des deux failles PHP2Shell. Depuis PHP 8.5.12, 8.4.27, 8.3.36 et 8.2.35, memory_limit est une limite souple, complétée par la limite stricte memory_hard_limit_percent.

Que signifie « Allowed memory size exhausted » ?

Le message d'erreur bien connu est, en substance : « Allowed memory size of 134217728 bytes exhausted (tried to allocate …) ». Le premier nombre est la limite configurée en octets, ici 128 Mo. Un script a donc tenté d'occuper de la mémoire au-delà de cette limite, par exemple en chargeant un gros fichier, en exécutant une requête de base de données énorme ou à cause d'une boucle infinie.

Pour les décideurs, c'est important : la limite s'applique par processus PHP et par requête, non à l'ensemble du serveur. Elle évite qu'un seul script défectueux n'épuise toute la mémoire du serveur. La charge totale ne résulte que du nombre de workers tournant simultanément. Avec 20 workers PHP-FPM ayant chacun 256 Mo de limite, cela représente, en calcul, plus de 5 Go.

Comment PHP compte la mémoire

PHP gère la mémoire des requêtes via son propre gestionnaire de mémoire, le Zend Memory Manager. Il obtient de plus gros blocs auprès du système d'exploitation et les distribue en interne aux variables, aux tableaux et aux objets. C'est par rapport à cette valeur réservée que PHP vérifie memory_limit. Selon le manuel, la mémoire qu'une extension demande directement au système d'exploitation n'apparaît pas dans ce décompte.

Vous pouvez rendre les valeurs visibles dans le code :

<?php
echo memory_get_usage(), PHP_EOL;       // mémoire actuellement occupée par le script
echo memory_get_usage(true), PHP_EOL;   // réservée par le gestionnaire de mémoire ; memory_limit vérifie cette valeur
$liste = range(1, 200000);
echo memory_get_peak_usage(), PHP_EOL;  // pic atteint jusqu'ici
unset($liste);
memory_reset_peak_usage();              // réinitialiser le pic, à partir de PHP 8.2

La page Gestion de la mémoire en PHP explique comment le comptage de références et la garbage collection libèrent à nouveau la mémoire.

Ce qui se passe à l'intérieur lors d'un Out-of-Memory

De façon simplifiée, un arrêt pour manque de mémoire se déroule ainsi :

  1. Le script demande de la mémoire, par exemple pour un nouvel élément de tableau ou lors de la lecture des données de la requête.
  2. Le gestionnaire de mémoire vérifie si la demande dépasse la limite.
  3. Si c'est le cas, PHP déclenche une erreur fatale et quitte immédiatement le traitement en cours, y compris au milieu d'une tâche à moitié accomplie.
  4. Les fonctions de shutdown enregistrées s'exécutent encore ; de nombreuses applications y consignent l'erreur.
  5. À la fin, PHP nettoie la requête et libère sa mémoire. Le worker est ensuite prêt pour la requête suivante.

Le point délicat est l'étape 5. Le nettoyage doit savoir traiter des structures de données qui n'étaient qu'à moitié créées lors de l'interruption. Selon la politique de sécurité du projet PHP, un arrêt ordinaire pour manque de mémoire n'est pas une faille de sécurité tant que la limite refuse la demande et que seule la requête en cours se termine. Avec CVE-2026-109618, c'est précisément cette hypothèse qui était mise en défaut : selon php.net, l'état de dépassement de mémoire pouvait interrompre PHP alors que les données internes de la requête n'étaient que partiellement initialisées, et le nettoyage traitait alors des données invalides comme valides. Nous ne publions pas de détails sur l'exploitation ; la description de la faille figure sous CVE-2026-109618.

La nouvelle limite mémoire souple et stricte

Avec les versions de sécurité du 21 octobre 2026, le projet PHP a modifié le comportement. Selon le manuel, memory_limit est depuis une limite souple : une demande qui la dépasse peut, dans la plupart des cas, encore être menée à terme avant que l'erreur fatale ne survienne. Une limite stricte distincte borne jusqu'où cela peut aller.

Directive Valeur par défaut Modifiable Signification
memory_limit 128M INI_ALL limite mémoire par requête, -1 = pas de limite
memory_hard_limit_percent non définie INI_ALL limite stricte en pourcentage de memory_limit, nouvelle depuis 8.5.12, 8.4.27, 8.3.36, 8.2.35
post_max_size 8M INI_PERDIR taille maximale des données POST
upload_max_filesize 2M INI_PERDIR taille maximale d'un fichier téléversé

Un exemple tiré du manuel : avec memory_limit=128M et memory_hard_limit_percent=150, la limite stricte est de 192 Mo. Le manuel cite en même temps la directive comme signe distinctif : si une version de PHP ne la connaît pas, elle est concernée par CVE-2026-109618 et CVE-2026-109619. Un test rapide pour chaque version de PHP installée :

php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
# bool(false) signifie : directive inconnue

Pour les paquets de distributions avec rétroportage, le journal des modifications du paquet reste la preuve déterminante, comme décrit dans Vérifier correctement la version de PHP et le niveau de correctifs. Vérifiez en outre séparément le binaire PHP-FPM, car il peut avoir une autre version que la ligne de commande.

Limites de mémoire et PHP2Shell : ce que les administrateurs doivent observer maintenant

Les mesures transitoires de php.net concernant CVE-2026-109618 tournent presque toutes autour de la mémoire et de la taille des requêtes. Elles réduisent le risque, mais ne remplacent pas la mise à jour :

; Pool FPM, p. ex. /etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M        ; 32M si des uploads sont nécessaires
php_admin_value[upload_max_filesize] = 6M  ; rester en dessous de post_max_size

Trois points sont décisifs. Premièrement, aucune application, aucun répertoire et aucun autre pool ne doit à nouveau fixer une limite finie ; php.net exige expressément ce contrôle. Deuxièmement, un service avec memory_limit=-1 a besoin d'une limite externe, via conteneur ou cgroup, de préférence selon php.net de façon que seul le worker concerné soit terminé. RLIMIT_AS et RLIMIT_DATA sont inadaptés selon php.net. Troisièmement, php.net recommande des limites au niveau du serveur web ou du proxy pour la taille des requêtes, le nombre de champs, les parties multipart, les en-têtes et la profondeur d'imbrication.

Important

memory_limit=-1 sans limite de mémoire externe peut paralyser complètement un serveur en cas de forte charge. N'appliquez les mesures transitoires qu'en bloc et seulement jusqu'à la mise à jour.

La manière de fixer la limite avec systemd est décrite dans Limites de mémoire avec systemd et cgroups ; la solution durable pour le quotidien figure dans Bien définir memory_limit.

Comment PHP SOS aide-t-il concrètement ?

Via le service de correctifs PHP, nous procédons ainsi :

  • Vérifier l'existant : nous recensons chaque version de PHP sur le serveur, séparément pour la CLI, FPM et le module Apache, et testons si la version corrigée tourne.
  • Mettre de l'ordre dans les limites de mémoire : nous vérifions partout où memory_limit est défini et configurons les limites de pool et de système de façon cohérente.
  • Sécuriser la transition : là où la mise à jour est encore bloquée, nous appliquons intégralement les mesures de php.net, verrouillées contre toute redéfinition.
  • Fournir la preuve : vous recevez par écrit les versions, les niveaux de paquets et la configuration avant et après l'intervention.

Questions fréquentes

Que signifie le message « Allowed memory size exhausted » ?

Un script a voulu réserver plus de mémoire que memory_limit ne l'autorise. PHP interrompt alors la requête en cours par une erreur fatale. Les autres requêtes et le serveur lui-même continuent de fonctionner.

memory_limit s'applique-t-il à l'ensemble du serveur ?

Non, la limite s'applique par processus PHP et par requête. Si 20 workers FPM tournent avec 256 Mo de limite chacun, ils peuvent théoriquement occuper ensemble plus de 5 Go. La limite globale doit donc être fixée via la taille des pools, systemd ou les conteneurs.

Qu'est-ce que memory_hard_limit_percent ?

Une nouvelle directive, arrivée avec PHP 8.5.12, 8.4.27, 8.3.36 et 8.2.35. Elle définit une limite stricte, exprimée en pourcentage de memory_limit, qui n'est jamais dépassée. Depuis, memory_limit lui-même est une limite souple.

memory_limit=-1 protège-t-il contre PHP2Shell ?

Seulement en partie. php.net cite ce réglage comme mesure transitoire contre CVE-2026-109618, expressément sans protection complète. Il exige impérativement une limite de mémoire externe, et la mise à jour reste obligatoire.

Sources

Contact immédiat

Chaque heure compte. Écrivez-nous maintenant.

Décrivez brièvement votre système, votre version de PHP et ce que vous avez observé. Nous vous répondons, faisons le point et travaillons à distance jusqu'à la clôture et la documentation de l'incident.

Aide immédiate