[php-src] Issue #23082: unserialize_callback_func can no longer be reset to its empty default at runtime

[email protected] (nicolas-grekas)
Newsgroups php.bugs
Message-ID <[email protected]>
Issue: https://github.com/php/php-src/issues/23082
Author: nicolas-grekas

### Description

Since c82acefe470e0444540c63d2329d8cc675d5777c, the `unserialize_callback_func` INI entry uses `OnUpdateStrNotEmpty` instead of `OnUpdateString`. `OnUpdateStrNotEmpty` returns `FAILURE` for an empty value, so the entry can no longer be set back to its default empty value at runtime.

`ini_set()` returns `false` and leaves the previous value in place, silently. Since the default value is empty, this breaks the usual save/restore idiom: the callback stays installed process-wide and fires for unrelated `unserialize()` calls later on.

The following code:

```php
<?php
function my_callback($name) { echo "callback fired for $name\n"; }

// Save the current value and install our own, the usual save/restore idiom.
$prev = ini_set('unserialize_callback_func', 'my_callback');
var_dump($prev);

// Restore it. $prev is "" here, since that is the default value.
var_dump(ini_set('unserialize_callback_func', $prev));
var_dump(ini_get('unserialize_callback_func'));

// The callback is still installed and fires for unrelated code.
$o = unserialize('O:20:"SomeNotExistingClass":0:{}');
```

Resulted in this output:

```
string(0) ""
bool(false)
string(11) "my_callback"
callback fired for SomeNotExistingClass

Warning: unserialize(): Function my_callback() hasn't defined the class it was called for in /tmp/repro.php on line 13
```

But I expected this output instead:

```
string(0) ""
string(11) "my_callback"
string(0) ""
```

`ini_set('unserialize_callback_func', null)` fails the same way.

`ini_restore('unserialize_callback_func')` still works, so it is usable as a workaround, but it resets to the php.ini value rather than to the saved one.

The change looks unintended: the commit message only mentions avoiding a reallocation, `php.ini-production` and `php.ini-development` still ship `unserialize_callback_func =` empty, and there is no `UPGRADING`/`NEWS` entry. This is currently breaking Symfony on the 8.6 nightly, where the idiom is used in Cache, Config, Messenger, Security and VarExporter.

Note that `output_handler` received the same `OnUpdateString` -> `OnUpdateStrNotEmpty` swap in e0221be81e3, though it is `PHP_INI_PERDIR|PHP_INI_SYSTEM` so the runtime impact is not the same.

### PHP Version

PHP 8.6.0-dev (master, 5d588761922). Works as expected on 8.5.8.

### Operating System

Linux
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.