Skip to content

fix(translator): validate overrides of built-in class methods - #55

Open
AlessioGiacobbe wants to merge 1 commit into
swoole:masterfrom
AlessioGiacobbe:split/internal-class-overrides
Open

fix(translator): validate overrides of built-in class methods#55
AlessioGiacobbe wants to merge 1 commit into
swoole:masterfrom
AlessioGiacobbe:split/internal-class-overrides

Conversation

@AlessioGiacobbe

Copy link
Copy Markdown
Contributor

Overrides of methods inherited from Zend built-in classes were never signature-checked — only PRIVATE/FINAL flags were consulted: class C extends ArrayObject { public function offsetGet(int $key): string {...} } and public static function count(): int both compiled (Zend: fatal). Compiled classes register as internal classes, where ZendVM does not re-run these checks, so the invalid vtables reached runtime.

A reflection-based validator now enforces the Zend ruleset against built-in parents: visibility may widen but not narrow, staticness must match, a by-ref return may be added but not dropped, required-argument counts, per-position by-ref-ness with variadic absorption, parameter contravariance, and return covariance — mapping ReflectionType (named/nullable/union/intersection, self/parent/static) into the existing DNF comparison machinery. TENTATIVE return types are exempt, matching Zend, which only deprecates a tentative mismatch (ArrayObject::count(): string stays accepted).

Verified against Zend 8.4.13, 13-case probe matrix.

Part of the split of #39.

checkParentMethodCanBeOverridden()'s internal-parent branch only checked
the PRIVATE and FINAL modifiers via reflection and then stopped, so an
override of any Zend built-in method was never signature-checked:
narrowed parameters, static/instance mismatches, narrowed visibility and
incompatible real return types were all accepted (all fatal in Zend,
e.g. "Declaration of C::offsetGet(int $key): string must be compatible
with ArrayObject::offsetGet(mixed $key): mixed").

Add validateInternalMethodOverrideSignature(), mirroring Zend's
zend_do_perform_implementation_check on host ReflectionMethod data:

  - visibility may widen but not narrow; staticness must match;
  - a by-ref return may be added but not dropped;
  - the child may not require more arguments; extra parameters must be
    optional or variadic;
  - parameters are contravariant with invariant by-ref-ness, and a
    trailing child variadic absorbs remaining parent positions (a
    variadic parent requires a variadic child);
  - the return type is covariant, enforced ONLY for real return types:
    ReflectionMethod::getReturnType() is null for TENTATIVE return
    types, which Zend merely deprecates on mismatch, never fatals.

ReflectionType data (named/nullable/union/intersection, incl. self,
parent and static) is mapped into the existing accepted-types DNF so the
comparison reuses isReturnTypeCoveredBy()/isAcceptedTypeSubset().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant