Category
bug · php-src-strict · Throwable / Error materialization
Problem
User throw new TypeError('…') / throw new Error('…', N) initializes $code (getCode works). Engine-bridged throwables from the VM (undefined method, TypeError on args, DivisionByZeroError from /) leave ExceptionSupport::PROP_CODE unset. Throwable::getCode() then fatals on Variable::$integer uninitialized instead of returning 0.
| Repro |
Zend 8.2+ |
VM (2026-07-24) |
try { (new stdClass)->nope(); } catch (Error $e) { echo $e->getCode(); } |
0 |
Fatal: Typed property PHPCompiler\VM\Variable::$integer must not be accessed before initialization |
try { $f=fn(int $x)=>0; $f('a'); } catch (TypeError $e) { echo $e->getCode(); } |
0 |
same Fatal |
try { 1/0; } catch (DivisionByZeroError $e) { echo $e->getCode(); } |
0 |
same Fatal |
try { throw new TypeError('t'); } catch (TypeError $e) { echo $e->getCode(); } |
0 |
0 (OK — ctor path) |
Root cause: BuiltinExceptionSupport::materializeThrowable() / materializeDivisionByZeroError() stamp message/file/line but never ->int(0) on PROP_CODE (unlike Exception::__construct / materializeJsonException).
php-src reference
PHP implementation target
lib/VM/BuiltinExceptionSupport.php — materializeThrowable() + materializeDivisionByZeroError() (and any sibling materializers missing code) must set PROP_CODE to 0 (or the bridged native code)
lib/VM/Builtin/ExceptionGetCode.php — already copies property; fix is at materialize
- PHP-in-PHP only; no new C
Repro
./script/docker-exec.sh -- bash -lc 'cat >/tmp/engine_getcode.php <<'"'"'PHP'"'"'
<?php
ini_set("display_errors", "1");
error_reporting(E_ALL);
foreach ([
"undef" => fn() => (new stdClass)->nope(),
"type" => function () { $f = function (int $x) {}; $f("a"); },
"div" => fn() => 1/0,
] as $name => $fn) {
try { $fn(); }
catch (Throwable $e) {
echo $name, " ", get_class($e), " code=", $e->getCode(), "\n";
}
}
PHP
php /tmp/engine_getcode.php
php bin/vm.php /tmp/engine_getcode.php'
Done when
Category
bug· php-src-strict · Throwable / Error materializationProblem
User
throw new TypeError('…')/throw new Error('…', N)initializes$code(getCode works). Engine-bridged throwables from the VM (undefined method, TypeError on args, DivisionByZeroError from/) leaveExceptionSupport::PROP_CODEunset.Throwable::getCode()then fatals onVariable::$integeruninitialized instead of returning0.try { (new stdClass)->nope(); } catch (Error $e) { echo $e->getCode(); }0Typed property PHPCompiler\VM\Variable::$integer must not be accessed before initializationtry { $f=fn(int $x)=>0; $f('a'); } catch (TypeError $e) { echo $e->getCode(); }0try { 1/0; } catch (DivisionByZeroError $e) { echo $e->getCode(); }0try { throw new TypeError('t'); } catch (TypeError $e) { echo $e->getCode(); }00(OK — ctor path)Root cause:
BuiltinExceptionSupport::materializeThrowable()/materializeDivisionByZeroError()stamp message/file/line but never->int(0)onPROP_CODE(unlikeException::__construct/materializeJsonException).php-src reference
Zend/zend_exceptions.c—zend_throw_exception/zend_exception_get_propsdefaultcode= 0Zend/zend_interfaces.stub.php—Throwable::getCode(): intPHP implementation target
lib/VM/BuiltinExceptionSupport.php—materializeThrowable()+materializeDivisionByZeroError()(and any sibling materializers missing code) must setPROP_CODEto0(or the bridged native code)lib/VM/Builtin/ExceptionGetCode.php— already copies property; fix is at materializeRepro
Done when
getCode()returns0(or Zend code) without secondary fatalthrow new TypeError/throw new Error('x', 7)still match Zend.phptundertest/compliance/cases/; php-src-strict; no php-compiler-strict shortcut