Skip to content

unserialize_callback_func can no longer be reset to its empty default at runtime #23082

Description

@nicolas-grekas

Description

Since c82acef, 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
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 e0221be, 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, 5d58876). Works as expected on 8.5.8.

Operating System

Linux

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions