Hacktoberfest 2026: as issues que os mantenedores marcaram para outubro, abertas e boas para iniciantes. Ver issues do Hacktoberfest

SplFixedArray: leak on re-initialisation during setSize(0), and setSize() broken on missing parent::__construct()

Fechada
#23,811 0 comentários 0 reações 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
4/5
Tempo estimado
3-5 dias
Facilidade para iniciantes
56/100
Tipo de issue
Bug
Clareza
Claramente especificada
Status de atividade
Ativa
Stack de tecnologia
c, php
Domínio
backend, testing-qa

Direção de pesquisa

Start with spl_fixedarray_resize() and spl_fixedarray_dtor(), tracing how cached_resize is read during setSize(0), __construct(), __wakeup(), and __unserialize(). Use ext/spl/tests/bug62904.phpt as the existing regression-test entry point and add coverage for both re-entrant reinitialisation and a subclass that omits parent::__construct(). Done means the reported leaks and no-op resize are covered by tests and the expected sizes are returned.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

Bug Status: Needs Triage
Description

Two defects in SplFixedArray. Both come down to cached_resize being unreliable where it is read, and the fix touches the same function, so I am reporting them together.


1. Memory leak when the array is re-initialised from an element destructor during setSize(0)

spl_fixedarray_dtor() clears elements and size before running the element destructors (from the GH-11959 use-after-free fix), so the array then looks like one that was never constructed. __construct(), __wakeup() and __unserialize() gate on emptiness and re-initialise it, and the in-progress
clear discards the buffer they allocated.

The following code:

<?php
class Reentrant {
    public static ?SplFixedArray $arr = null;
    public function __destruct() {
        if (self::$arr !== null) {
            $arr = self::$arr;
            self::$arr = null;
            $arr->__construct(5);
        }
    }
}

$arr = new SplFixedArray(2);
Reentrant::$arr = $arr;
$arr[0] = new Reentrant();
$arr[1] = "tail";

$arr->setSize(0);
var_dump($arr->getSize());

Resulted in this output:

int(0)
ext/spl/spl_fixedarray.c(95) :  Freeing 0x0000e716d0e84070 (80 bytes)
=== Total 1 memory leaks detected ===

But I expected this output instead:

int(0)

Replacing __construct(5) with __unserialize(["a", "b", "c"]) or __wakeup() leaks the same way. A second site leaks when the destructor follows the re-init with a setSize(): the re-init resets the sentinel, so the setSize() performs a real nested shrink and its erealloc() buffer is discarded too.

This is the same bug as GH-21920, which cb3dc62fd90 fixed for a re-entrant setSize() by testing the resize sentinel first. The other three entry points were not covered.


2. setSize() silently does nothing on a subclass whose constructor does not call parent::__construct()

The following code:

<?php
class S extends SplFixedArray {
    public function __construct() {
    }
}

$s = new S();
var_dump($s->setSize(5));
var_dump($s->getSize());
$s[0] = 'x';

Resulted in this output:

bool(true)
int(0)

Fatal error: Uncaught OutOfBoundsException: Index invalid or out of range in /tmp/rep2.php:10
Stack trace:
#0 {main}
  thrown in /tmp/rep2.php on line 10

But I expected this output instead:

bool(true)
int(5)

zend_object_alloc() zeroes the object, so cached_resize starts at 0 instead of the documented -1. spl_fixedarray_resize() reads >= 0 as "a resize is already in progress" and returns early, so setSize() returns true and does nothing — permanently, for every call on that instance.

This is a regression: cb3dc62fd90 moved the "first initialization" branch below the sentinel check, which exposed the uninitialised sentinel. Before that, this path reached spl_fixedarray_init() and worked.

ext/spl/tests/bug62904.phpt already uses this class shape but only asserts "No crash" after a clone, which is why it was not caught.

PHP Version
PHP 8.4.27-dev (cli) (built from git, NTS DEBUG)
PHP 8.6.0-dev  (cli) (built from git, NTS DEBUG)
Operating System

Linux aarch64 (Ubuntu 24.04)

Linguagem predominante
C
Estrelas
40.4k
Forks
8.2k
Merge médio
2d 17h
PRs com merge (30d)
115

Guia de contribuição

Abrir o guia de contribuição

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de php/php-src

Todas as issues de php/php-src

Issues semelhantes

Mais issues de C

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.