Feature/scalar methods#22329
Closed
kralmichal wants to merge 14 commits into
Closed
Conversation
…free under %expect 0)
…nment Compile ZEND_AST_TYPED_VAR_DECL into a cv_types entry plus a new ZEND_ASSIGN_TYPED opcode that verifies/coerces the RHS against the declared scalar type using the same scalar path typed properties use, honoring strict/weak mode. The RHS is copied into a separated tmp before coercion so a CONST literal is never mutated in place. cv_types is kept parallel to vars[] as new CVs are interned, and its synthesized name is released on teardown.
…ls/$this/$GLOBALS FIX A: zend_compile_assign() now emits ZEND_ASSIGN_TYPED (instead of plain ZEND_ASSIGN) for a simple CV target that has a non-NULL cv_types[] entry, so the declared type is enforced on every (re)assignment, not just the initializer. Operand setup mirrors the initializer path in zend_compile_typed_var_decl(); the CV index is computed via EX_VAR_TO_NUM(var_node.u.op.var), matching the VM handler. Because cv_types[] persists, this also covers `int $x; $x = ...;` and post-unset reassignment. Only the simple-CV-target case changes; dim/prop/list/dynamic targets are untouched (a non-CV var_node falls through to ZEND_ASSIGN unchanged). FIX B (finding I1): zend_compile_typed_var_decl() now rejects auto-globals, $this and $GLOBALS with E_COMPILE_ERROR, mirroring how the canonical CV path (zend_try_compile_cv) handles these special names. The variable name is now interned via zval_make_interned_string() so vars[] stays consistent with the canonical path and opcache's interned-string accounting.
cv_types[] (the parallel array of zend_property_info* describing typed local variables) was request-memory only and had no opcache handling: with opcache enabled it leaked on compile, and a file-cached op_array reloaded in another process carried a dangling cv_types pointer, causing a SIGSEGV when a typed local was assigned (finding C1). Mirror the existing op_array->vars handling in all three persistence layers: - zend_persist_calc.c: account for the pointer array plus, per typed slot, the zend_property_info struct and its interned name. - zend_persist.c: zend_shared_memdup the array and each zend_property_info into SHM and intern each name. Types are pure scalar masks, so zend_persist_type() is a no-op (no class/list pointers to relocate). - zend_file_cache.c: SERIALIZE_PTR/UNSERIALIZE_PTR the array and each entry, plus SERIALIZE_STR/UNSERIALIZE_STR each name, in both the full walk and the shared- method (refcount) fast paths. serialize/unserialize_type are no-ops for masks. destroy_op_array() needs no change: persisted op_arrays have refcount==NULL and return early before the vars[]/cv_types[] efree, so the existing guard that protects vars[] already protects cv_types[]. Verified: SHM run with report_memleaks shows no leak; file-cache write+reload (including overwriting the source with garbage under validate_timestamps=0 to force a pure cache load) prints correctly and does not segfault, for both plain functions and class methods.
Add 13 .phpt tests covering the typed-locals feature: basic scalars, weak-mode coercion on init and reassign, strict-mode TypeErrors, uninitialized-then-assign, nullable types, non-numeric weak TypeError, and compile errors for non-scalar type / redeclaration / $this / superglobals. Includes an opcache_persist test guarding cv_types SHM/file-cache continuity.
…erence) Close gap #2: references could bypass a typed local's declared type (`int $x=1; $y=&$x; $y="s";` and `function m(&$r){$r="s";} m($x);`). Reuse the typed-property reference machinery: when a typed CV is aliased by a reference, attach its op_array-owned synthesized zend_property_info as a type source on the resulting zend_reference, so writes through the reference are checked by zend_verify_ref_assignable_zval(). The CV stays a plain value until referenced (no read overhead). ENFORCED reference-creation paths (source attached at ref creation): - ZEND_ASSIGN_REF (`$y = &$x`): new helper zend_assign_to_typed_cv_reference() mirrors zend_assign_to_typed_property_reference() and handles either/both operands typed, the re-binding DEL-before-ADD, and the `$x = &$x` self-alias. - by-ref argument passing (ZEND_SEND_REF, ZEND_SEND_VAR_EX) and ZEND_MAKE_REF: attach when a typed CV is freshly wrapped into a reference. FORBIDDEN at compile time (E_COMPILE_ERROR; these ref paths are not enforced, so they must not silently bypass the type): - `global $x`, `static $x`, `foreach (... as &$x)` on a typed local. Lifecycle: the source list stores only the pointer and never frees the property_info; ZEND_REF_DEL_TYPE_SOURCE frees only the list allocation. The synthesized info is owned by the op_array (freed in destroy_op_array), so the matching DEL is performed when the CV slot is torn down or moved out of the frame -- in i_free_compiled_variables() and zend_detach_symbol_table() (the top-level/symbol-table path) -- before the CV drops its refcount. A frame uses exactly one of those teardown paths, so ADD/DEL stay balanced one-per-CV-slot and the reference can never outlive the op_array with a dangling source. Reference type-error messages (zend_throw_ref_type_error_zval/_type, zend_throw_conflicting_coercion_error, zend_verify_property_type_error) now branch on prop->ce: synthesized local infos have ce == NULL, so they print "local variable $x" instead of dereferencing ce->name (which would segfault). Tests: 7 new .phpt under tests/lang/typed_locals (alias enforce/coerce, by-ref param weak+strict, target-typed alias, and the three compile-error forbids).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.