Situação atual: PHP2Shell. Duas vulnerabilidades críticas do PHP (CVSS 9,2) permitem executar código malicioso sem autenticação. Patches disponíveis desde 21/10/2026.O que fazer agora →

memory_limit e Out-of-Memory: o que acontece por dentro

O que acontece quando um script PHP atinge o memory_limit? A mecânica, o novo limite rígido de memória desde os patches de outubro e a relação com a CVE-2026-109618.

Atualizado em 6 min de leituraConhecimento PHP

Em resumo: Um erro de falta de memória (out of memory) do PHP surge quando um script quer pedir mais memória do que a definição memory_limit permite (predefinição: 128 MB por pedido). O PHP interrompe então o pedido com um erro fatal e limpa. Foi precisamente este caminho de interrupção e de limpeza que estava com falhas na CVE-2026-109618, uma das duas vulnerabilidades do PHP2Shell. Desde o PHP 8.5.12, 8.4.27, 8.3.36 e 8.2.35, o memory_limit é um limite flexível, complementado pelo limite rígido memory_hard_limit_percent.

O que significa «Allowed memory size exhausted»?

A conhecida mensagem de erro diz, em substância: «Allowed memory size of 134217728 bytes exhausted (tried to allocate …)». O primeiro número é o limite definido em bytes, aqui 128 MB. Um script tentou, portanto, ocupar memória para além deste limite, por exemplo ao carregar um ficheiro grande, numa consulta enorme à base de dados ou por causa de um ciclo infinito.

Importante para quem decide: o limite aplica-se por processo PHP e por pedido, não ao servidor inteiro. Protege o servidor de que um único script defeituoso consuma toda a memória. A carga total só resulta do número de workers a correr em simultâneo. Com 20 workers PHP-FPM, cada um com um limite de 256 MB, são, em termos de cálculo, mais de 5 GB.

Como o PHP conta a memória

O PHP gere a memória dos pedidos através de um gestor de memória próprio, o Zend Memory Manager. Obtém blocos maiores ao sistema operativo e distribui-os internamente por variáveis, arrays e objetos. É contra este valor reservado que o PHP verifica o memory_limit. A memória que uma extensão pede diretamente ao sistema operativo não aparece, segundo o manual, nesta contagem.

Pode tornar os valores visíveis no código:

<?php
echo memory_get_usage(), PHP_EOL;       // memória atualmente ocupada pelo script
echo memory_get_usage(true), PHP_EOL;   // reservada pelo gestor de memória; é contra ela que o memory_limit verifica
$liste = range(1, 200000);
echo memory_get_peak_usage(), PHP_EOL;  // valor máximo até agora
unset($liste);
memory_reset_peak_usage();              // repor o valor máximo, a partir do PHP 8.2

Como a contagem de referências e a garbage collection voltam a libertar a memória explica-o a página Gestão de memória em PHP.

O que acontece por dentro num out-of-memory

De forma simplificada, uma interrupção por falta de memória decorre nestes passos:

  1. O script pede memória, por exemplo para um novo elemento de array ou ao ler dados do pedido.
  2. O gestor de memória verifica se o pedido excede o limite.
  3. Se for o caso, o PHP desencadeia um erro fatal e abandona de imediato o processamento em curso, mesmo a meio de uma tarefa meio concluída.
  4. As funções de shutdown registadas ainda correm; é com elas que muitas aplicações registam o erro.
  5. No fim, o PHP limpa o pedido e liberta a sua memória. O worker fica depois pronto para o pedido seguinte.

O ponto delicado é o passo 5. A limpeza tem de lidar com estruturas de dados que, na interrupção, estavam apenas meio criadas. Uma interrupção de memória normal não é, segundo a política de segurança do projeto PHP, uma vulnerabilidade, desde que o limite rejeite o pedido e termine apenas o pedido atual. Na CVE-2026-109618, foi precisamente este pressuposto que foi violado: segundo o php.net, o estado de falta de memória podia interromper o PHP enquanto dados internos do pedido estavam apenas parcialmente inicializados, e a limpeza tratava então dados inválidos como válidos. Não publicamos detalhes da exploração; o enquadramento da vulnerabilidade está em CVE-2026-109618.

O novo limite de memória flexível e rígido

Com as versões de segurança de 21/10/2026, o projeto PHP alterou o comportamento. Segundo o manual, o memory_limit é, desde então, um limite flexível: um pedido que o exceda pode, na maioria dos casos, ainda ser concluído antes de se seguir o erro fatal. Um limite rígido separado delimita até onde isso pode ir.

Diretiva Predefinição Alterável Significado
memory_limit 128M INI_ALL Limite de memória por pedido, -1 = sem limite
memory_hard_limit_percent não definido INI_ALL Limite rígido em percentagem do memory_limit, novo desde 8.5.12, 8.4.27, 8.3.36, 8.2.35
post_max_size 8M INI_PERDIR Tamanho máximo dos dados POST
upload_max_filesize 2M INI_PERDIR Tamanho máximo de um ficheiro enviado

Um exemplo do manual: com memory_limit=128M e memory_hard_limit_percent=150, o limite rígido situa-se nos 192 MB. O manual indica a diretiva também como sinal de reconhecimento: se uma versão do PHP não a conhece, está afetada pela CVE-2026-109618 e pela CVE-2026-109619. Um teste rápido para cada versão do PHP instalada:

php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
# bool(false) significa: diretiva desconhecida

No caso de pacotes de distribuições com backport, o changelog do pacote continua a ser a prova determinante, como descrito em Verificar corretamente a versão do PHP e o nível de patches. Verifique também em separado o binário do PHP-FPM, pois pode ter uma versão diferente da linha de comandos.

Limites de memória e PHP2Shell: o que os administradores devem ter em conta agora

As medidas provisórias do php.net para a CVE-2026-109618 giram quase todas em torno da memória e dos tamanhos de pedido. Reduzem o risco, mas não substituem a atualização:

; 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, se forem necessários uploads
php_admin_value[upload_max_filesize] = 6M  ; manter abaixo de post_max_size

Três pontos são decisivos. Primeiro, nenhuma aplicação, nenhum diretório e nenhum outro pool pode voltar a definir um limite finito; o php.net exige expressamente este controlo. Segundo, um serviço com memory_limit=-1 precisa de um limite externo, através de contentor ou cgroup, segundo o php.net de preferência de modo a terminar apenas o worker afetado. RLIMIT_AS e RLIMIT_DATA não são adequados, segundo o php.net. Terceiro, o php.net recomenda limites no servidor web ou no proxy para o tamanho do pedido, o número de campos, as partes multipart, os cabeçalhos e a profundidade de aninhamento.

Importante

O memory_limit=-1 sem limite de memória externo pode paralisar completamente um servidor com carga elevada. Aplique as medidas provisórias apenas em conjunto e apenas até à atualização.

Como definir o limite com o systemd está em Limites de memória com systemd e cgroups; a solução duradoura para o dia a dia é descrita em Definir corretamente o memory_limit.

Como ajuda concretamente a PHP SOS?

Através do serviço de patches PHP, procedemos assim:

  • Verificar o parque instalado: registamos cada versão do PHP no servidor, separada por CLI, FPM e módulo Apache, e testamos se a versão corrigida está a correr.
  • Ordenar os limites de memória: verificamos onde o memory_limit é definido e configuramos os limites de pool e de sistema de modo a que sejam coerentes.
  • Proteger a transição: onde a atualização ainda está bloqueada, aplicamos as medidas do php.net por completo e bloqueadas contra sobreposição.
  • Entregar a prova: recebe por escrito as versões, os estados dos pacotes e a configuração antes e depois da intervenção.

Perguntas frequentes

O que significa a mensagem «Allowed memory size exhausted»?

Um script quis pedir mais memória do que o memory_limit permite. O PHP interrompe então o pedido em curso com um erro fatal. Os outros pedidos e o próprio servidor continuam a funcionar.

O memory_limit aplica-se ao servidor inteiro?

Não, o limite aplica-se por processo PHP e por pedido. Se 20 workers FPM correrem, cada um com um limite de 256 MB, podem em teoria ocupar em conjunto mais de 5 GB. O limite global tem por isso de ser definido através do tamanho do pool, do systemd ou de contentores.

O que é o memory_hard_limit_percent?

É uma nova diretiva, introduzida com o PHP 8.5.12, 8.4.27, 8.3.36 e 8.2.35. Define um limite rígido, como percentagem do memory_limit, que nunca é excedido. O próprio memory_limit é, desde então, um limite flexível.

O memory_limit=-1 protege do PHP2Shell?

Só em parte. O php.net indica a definição como medida provisória contra a CVE-2026-109618, expressamente sem proteção completa. Exige obrigatoriamente um limite de memória externo, e a atualização continua a ser obrigatória.

Fontes

Contacto imediato

Cada hora conta. Escreva-nos agora.

Descreva brevemente o sistema, a versão do PHP e o que observou. Entramos em contacto consigo, esclarecemos a situação e trabalhamos remotamente até o incidente estar concluído e documentado.

Ajuda imediata