Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

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

Đã đóng
#23,811 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
56/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
c, php
Lĩnh vực
backend, testing-qa

Hướng nghiên cứu

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.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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)

Ngôn ngữ chính
C
Star
40.4k
Fork
8.2k
Merge trung bình
2 ngày 17 giờ
Pull request đã merge (30 ngày)
115

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của php/php-src

Tất cả issue của php/php-src

Issue tương tự

Thêm issue về C

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.