Uh oh!
There was an error while loading. Please reload this page.
Add ZEND_ACC2_FORBID_DYN_CALLS - #21818
Conversation
Change zend_function_entry.flags to a uint64_t to that both ZEND_ACC_ and ZEND_ACC2_ flags can be represented. Introduce ZEND_FENTRY_FLAGS(flags, flags2) to pass ZEND_ACC2_ flags to ZEND_RAW_FENTRY(), ZEND_FENTRY(). Source-level backwards compatibility is maintained, as passing raw ZEND_ACC_ flags to ZEND_RAW_FENTRY(), ZEND_FENTRY() still works.
Functions that use zend_forbid_dynamic_call() must be flagged with ZEND_ACC2_FORBID_DYN_CALLS. In stubs, this is done by using @forbid-dynamic-calls. To ensure consistency, we assert that the flag exists in zend_forbid_dynamic_call(), and we assert that flagged functions thrown after a dynamic call.
TimWolla
left a comment
There was a problem hiding this comment.
Should Closure::getCurrent() be added to that list or does it work?
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
iluuu1994
left a comment
There was a problem hiding this comment.
Same comments as Tim, but LGTM otherwise.
arnaud-lb
commented
Apr 21, 2026
I've checked, and |
| return ''; | ||
| } | ||
| return sprintf($codeTemplate, implode("|", $flagsByPhpVersions[$currentPhpVersion])); | ||
| return sprintf($codeTemplate, $this->formatFlags($flagsByPhpVersions[$currentPhpVersion])); |
There was a problem hiding this comment.
I'm wondering if ZEND_FENTRY_FLAGS should also be used when the minimum version compatibility is PHP 8.6? At least it would be useful later, when 8.6 will be a few years old, and there will be more ACC2 flags. That's why I think the other two returns should use generate ZEND_FENTRY_FLAGS when possible.
I'm not sure how I didn't see it immediately, but I've just realized that you have thought about this :) Very nice!
DanielEScherzer
left a comment
There was a problem hiding this comment.
So overall this makes sense, but copying from my note on #20848
Also, if you have that flag, you might not even need to call zend_forbid_dynamic_call() in each function, if you instead enforce the flag in the function dispatch logic. Otherwise there is a possibility that the flag is added to a function but not enforced with a zend_forbid_dynamic_call() call
And the reply from @arnaud-lb
This would add overhead for a something that is rare, so I would prefer not to. However, debug builds can verify that an exception was thrown after dynamically calling a flagged function.
I would suggest that the UPGRADING.INTERNALS be a bit stronger than
Functions using zend_forbid_dynamic_call() must be flagged with ZEND_ACC2_FORBID_DYN_CALLS (@forbid-dynamic-calls in stubs)
maybe
Functions using zend_forbid_dynamic_call() must be flagged with ZEND_ACC2_FORBID_DYN_CALLS (@forbid-dynamic-calls in stubs). In debug builds, failing to include that flag will lead to assertion failures.
or something to make it clear that this isn't just a suggestion
Flag functions that forbid dynamic calls with
ZEND_ACC2_FORBID_DYN_CALLS, so that we can recognize them without making a hard-coded list.This will be used in the PFA implementation.
See individual commits for details.
UPGRADING.INTERNALS: