Skip to content

sapi/cli: php_cli_server_client_save_header() crash on repeated headers. - #25142

Closed
devnexen wants to merge 3 commits into
php:PHP-8.4from
devnexen:gh23698_fix
Closed

devnexen wants to merge 3 commits into
php:PHP-8.4from
devnexen:gh23698_fix

Conversation

@devnexen

@devnexen devnexen commented Nov 2, 2026

Copy link
Copy Markdown
Member

The merged value was not marked persistent local, which tripped the ZEND_RC_DEBUG assertions, and the second value leaked. Spellings differing only by case also left headers_original_case pointing at the value freed by the headers update. Repeats now update the entry of the first spelling.

The merged value was not marked persistent local, which tripped the
ZEND_RC_DEBUG assertions, and the second value leaked. Spellings differing
only by case also left headers_original_case pointing at the value freed by
the headers update. Repeats now update the entry of the first spelling.
@devnexen
devnexen marked this pull request as ready for review November 2, 2026 04:20
Comment thread sapi/cli/php_cli_server.c Outdated
}

zend_string *orig = client->current_header_name;
if (entry != NULL) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this and the PR doesn't explain why this is needed in simple English
Presumably, one of the hash updates free a string, but there must be a cleaner and simpler solution than looping over the entire hash table, right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alright I ll think of something better

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either you can get the string from the bucket itself; or you stop borrowing the pointer, give headers_original_case its destructor, and use ADDREF

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went for the 2nd solution already locally but will commit soon.

Comment thread sapi/cli/php_cli_server.c
zend_hash_update(&client->request.headers, lc_header_name, &tmp);
/* A repeat spelled differently leaves the first spelling's entry in place while the
* update above releases its value, so this table must own a reference too. */
zend_string_addref(Z_STR(tmp));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the update above releases its value

Then why does the addref come after the update?

@ndossche ndossche left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems okay now.
The array shows pre-existing weird behaviour in that both the stale and the new header values are shown, while we'd expect only the merged ones to remain intuitively, but that's master-only material I believe...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CLI built in server crashes with repeated headers and -DZEND_RC_DEBUG=1

2 participants