Skip to content

Regression: #[\SensitiveParameter] Exception::getTrace() drops all args — must wrap SensitiveParameterValue (re-#15036/#3351, Zend/zend_exceptions.c) #21339

Description

@PurHur

Category

language · php-src-strict · Pillar 4 Correctness · (re-#15036 / #3351)

Problem

Under current master, Exception::getTrace() for a frame whose callee has #[\SensitiveParameter] returns zero args (argc=0). Zend/php-src keeps the argument vector and replaces sensitive parameters with SensitiveParameterValue objects (non-sensitive args remain visible). Prior #15036 closed after omitting args entirely — that is not php-src-strict.

Probed 2026-07-20 via ./script/docker-exec.sh vs php:8.4-cli.

function f(#[\SensitiveParameter] string $password, string $ok) {
  throw new Exception('boom');
}
try { f('secret', 'visible'); } catch (Throwable $e) {
  // inspect $e->getTrace()[0]['args']
}
Repro Zend 8.4 VM PROFILE=8.4 (2026-07-20)
count($trace[0]['args']) 2 0
$args[0] SensitiveParameterValue (missing)
$args[1] 'visible' (missing)
str_contains($e->getTraceAsString(), 'secret') false false
str_contains($e->getTraceAsString(), 'SensitiveParameterValue') true false

php-src reference

PHP implementation target

  • Restore/adjust trace building in VM (+ JIT/AOT if shared) so sensitive params become SensitiveParameterValue instead of dropping the entire args array
  • Keep non-sensitive args intact; never leak raw sensitive scalars in getTraceAsString()
  • Reuse existing VmSensitiveParam / attribute metadata paths (#10394 lineage); PHP-in-PHP — no new runtime/*.c

Repro

./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && PHP_COMPILER_PROFILE=8.4 php bin/vm.php -r '\''
function f(#[\SensitiveParameter] string $password, string $ok) { throw new Exception("boom"); }
try { f("secret", "visible"); } catch (Throwable $e) {
  $a = $e->getTrace()[0]["args"] ?? [];
  echo "argc=", count($a), "\n";
  echo "a0=", isset($a[0]) && is_object($a[0]) ? get_class($a[0]) : "missing", "\n";
  echo "a1=", isset($a[1]) ? var_export($a[1], true) : "missing", "\n";
}
'\'''

Done when

  • getTrace()[0]['args'] has arity matching the call; sensitive slots are SensitiveParameterValue; others unchanged
  • getTraceAsString() shows SensitiveParameterValue (or equivalent Zend formatting) and never the raw secret
  • Compliance .phpt under test/compliance/cases/ (attributes/exceptions)
  • php-src-strict; no php-compiler-strict shortcut

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

    area:vmVirtual machinebugSomething isn't workingimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimphase-2:languagePhase 2 – language features

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions