Skip to content

Address GH-25403: Make pcntl child memory re-keying optional - #25429

Open
kairosci wants to merge 5 commits into
php:masterfrom
kairosci:fix/gh-25403-optional-fork-rekey
Open

kairosci wants to merge 5 commits into
php:masterfrom
kairosci:fix/gh-25403-optional-fork-rekey

Conversation

@kairosci

@kairosci kairosci commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #25403.

Adds an optional rekey_memory argument to all three pcntl fork functions, preserving re-keying by default and all other child initialization. Documents the shared-key trade-off and adds regression coverage. Local tests were not run as requested.

@kairosci

kairosci commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor Author

cc @bukka @arnaud-lb @devnexen

@kairosci
kairosci force-pushed the fix/gh-25403-optional-fork-rekey branch from 8c4b32a to 015efae Compare November 13, 2026 00:11
@devnexen

Copy link
Copy Markdown
Member

as far as this approach goes, it seems valid however it might be possible to do differently I ll try to have a deeper look this week end.

@devnexen

Copy link
Copy Markdown
Member

So, I was thinking about something like this

diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c
index 2b52babc98e..b29875c77f0 100644
--- a/Zend/zend_alloc.c
+++ b/Zend/zend_alloc.c
@@ -2270,22 +2270,7 @@ ZEND_API void zend_mm_refresh_key_child(zend_mm_heap *heap)

        zend_mm_init_key(heap);

-       /* Update shadow pointers with new key */
-       for (uint32_t i = 0; i < ZEND_MM_BINS; i++) {
-               zend_mm_free_slot *slot = heap->free_slot[i];
-               if (!slot) {
-                       continue;
-               }
-               zend_mm_free_slot *next;
-               while ((next = slot->next_free_slot)) {
-                       zend_mm_free_slot **shadow_addr = ZEND_MM_FREE_SLOT_PTR_SHADOW_ADDR(slot, i);
-                       if (UNEXPECTED(next != zend_mm_decode_free_slot_key(old_key, shadow_addr, *shadow_addr))) {
-                               zend_mm_panic("zend_mm_heap corrupted");
-                       }
-                       zend_mm_set_next_free_slot(heap, i, slot, next);
-                       slot = next;
-               }
-       }
+       memset(heap->free_slot, 0, sizeof(heap->free_slot));

        zend_mm_rekey_cached_chunks(heap, old_key);

but the noticeable trade-off is lost of visibility of these inherited holes, can't be reused ...

Comment thread ext/pcntl/README.md Resolved
@kairosci
kairosci requested a review from devnexen November 14, 2026 18:13
@kairosci

Copy link
Copy Markdown
Contributor Author

@devnexen I believe I fixed everything, could you take another look at it? Thanks

Comment thread ext/pcntl/pcntl.stub.php Outdated
#endif

function pcntl_fork(): int {}
function pcntl_fork(bool $rekey_memory = true): int {}

@devnexen devnexen Nov 14, 2026 •

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 find that the rekey_memory name is misleading ; whether it s true or not, zend_mm_init_key() is called.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There is nothing to change; the child already clears inherited free lists instead of re-keying them.

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 free lists are not re-keyed, true, but the child still gets a new key either way and the cached chunks are still re-keyed. So rekey_memory: false reads as "the child keeps the parent's key", which is what the first version of this PR did and not what it does now;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I’ve renamed it to rekey_free_lists. When false, the child still gets a new key; it just skips the inherited free lists.

@kairosci
kairosci requested a review from devnexen November 14, 2026 22:09
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.

pcntl_fork() child re-keys every inherited free list since 8.5 (slow child start, copies inherited memory)

2 participants