Skip to content

Stdlib: VM builtins skip arg validation when return is discarded (returnVar null early-return) #5896

Description

@PurHur

Category

stdlib | runtime

Problem

Many ext/standard/* Internal::execute() handlers begin with:

if (null === $frame->returnVar) {
    return;
}

When a builtin is used as a statement (return value discarded), the VM never validates arguments or runs side effects. Zend still validates types and throws.

Verified today (Docker php-compiler:22.04-dev):

Call (statement) Zend PHP 8.2 bin/vm.php today
strip_tags(E::A); TypeError silent no-op, script continues
fputcsv($fp, [E::A]); Error (enum in fields) silent no-op; stream may be invalid

Assigning the return ($r = strip_tags(E::A);) does hit validation — behavior differs from Zend for the same call site.

This pattern appears across dozens of builtins (strip_tags.php, fputcsv.php, hash_.php, md5.php, scandir.php, … — grep null === $frame->returnVar in ext/standard/).

php-src reference

Repro (add test/repro-maintainer/parity_builtin_void_return_skipped.php)

<?php
enum E: string { case A = 'a'; }

// strip_tags — must throw even when return discarded
strip_tags(E::A);
echo "strip_tags_after\n";

$fp = fopen('php://memory', 'r+');
fputcsv($fp, [E::A]);
echo "fputcsv_after\n";
fclose($fp);
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
php8.2 test/repro-maintainer/parity_builtin_void_return_skipped.php 2>&1 || true
php bin/vm.php test/repro-maintainer/parity_builtin_void_return_skipped.php 2>&1 || true'
Engine Expected VM today
Zend Fatal on first call; no strip_tags_after Prints strip_tags_after (and often fputcsv_after)

Scope (this repo)

Path Work
ext/standard/*.php Remove or relocate returnVar === null early returns after argc/type validation; only skip writing $frame->returnVar
lib/VM.php / Frame Optional: central helper so builtins cannot skip validation
Tests test/compliance/cases/stdlib/builtin_void_return_validates.phpt

PHP-in-PHP: fix in PHP builtin bodies only — do not add C branches in runtime/.

php-src-strict

Default CI/compliance must match Zend: invalid operands throw even in void context.

Done when

  • Repro script: VM throws on strip_tags(E::A); and fputcsv($fp, [enum]) without printing *_after
  • Audit grep hits in ext/standard/ — no handler returns before validation when returnVar is null
  • Compliance PHPT green on VM (JIT/AOT if those builtins are lowered)

Related

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    MOST IMPORTANTThis are the most important targetsarea:vmVirtual machineenhancementNew feature or requestimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimphase-4:stdlibPhase 4 – stdlib for web apps

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions