[php-src] Issue #13612: Corrupted memory in destructor with weak references
| From: | mvorisek | Date: | Wed, 06 Mar 2024 22:02:30 +0000 |
| Subject: | [php-src] Issue #13612: Corrupted memory in destructor with weak references | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-246524@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/13612
Author: mvorisek
### Description
In the code below,
var_dump(array_keys($analysingMap->valueWithOwnerCountByIndex))
called twice prints different results even if the value is not changed between the calls.
I did my best to create a minimal repro. It seems the issue is present when weak references and
destructor are used.
When opcache and/or GC is disabled, the issue is still present. It seems there is some
allocation/refcounting issue in destructors.
repro: https://3v4l.org/h7ZER
```php
<?php
class WeakMap2
{
private array $weakRefs = [];
private array $values = [];
public function offsetSet($object, $value) : void
{
$id = spl_object_id($object);
$this->weakRefs[$id] = \WeakReference::create($object);
$this->values[$id] = $value;
}
}
class WeakAnalysingMapRepro
{
/* private */ public array $valueWithOwnerCountByIndex = [];
private WeakMap2 $ownerDestructorHandlers;
public function __construct()
{
$this->ownerDestructorHandlers = new WeakMap2();
$this->addKeyOwner(new \DateTime());
}
protected function addKeyOwner(object $owner)
{
$handler = new class($this) {
private \WeakReference $weakAnalysingMap;
public function __construct(WeakAnalysingMapRepro $analysingMap)
{
$this->weakAnalysingMap = \WeakReference::create($analysingMap);
}
public function __destruct()
{
$analysingMap = $this->weakAnalysingMap->get();
var_dump(array_keys($analysingMap->valueWithOwnerCountByIndex));
\Closure::bind(static function () use ($analysingMap) {
var_dump(array_keys($analysingMap->valueWithOwnerCountByIndex));
}, null, WeakAnalysingMapRepro::class)();
}
public function addReference($index): void
{
$analysingMap = $this->weakAnalysingMap->get();
$analysingMap->valueWithOwnerCountByIndex[$index] = true;
}
};
$this->ownerDestructorHandlers->offsetSet($owner, $handler);
$handler->addReference(10);
}
}
$map = new WeakAnalysingMapRepro();
unset($map);
echo 'DONE';
```
Resulted in this output:
```
array(1) {
[0]=>
int(10)
}
array(1) {
[0]=>
string(12) "analysingMap"
}
DONE
```
But I expected this output instead:
```
array(1) {
[0]=>
int(10)
}
array(1) {
[0]=>
int(10)
}
DONE
```
### PHP Version
7.4 - master
### Operating System
Windows, Linux