From c4f6d914b2725b3400c5797191ffb338c205f610 Mon Sep 17 00:00:00 2001 From: PurHur Date: Fri, 17 Jul 2026 22:27:13 +0000 Subject: [PATCH] Stdlib: getenv() scalar name coercion without strict_types (#4177) Match php-src Z_PARAM_STR_OR_NULL: coerce int/float/bool when the caller is not strict_types; keep TypeError under declare(strict_types=1) (#17765). Co-authored-by: Cursor --- ext/standard/getenv_.php | 14 ++++++++++-- .../cases/stdlib/getenv_enum_case.phpt | 2 +- .../cases/stdlib/getenv_enum_case_jit.phpt | 2 +- .../cases/stdlib/getenv_scalar_coerce.phpt | 18 +++++++++++++++ .../stdlib/getenv_scalar_coerce_jit.phpt | 18 +++++++++++++++ .../repro/issue_4177_getenv_putenv_coerce.php | 22 +++++++++++++++++++ 6 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 test/compliance/cases/stdlib/getenv_scalar_coerce.phpt create mode 100644 test/compliance/cases/stdlib/getenv_scalar_coerce_jit.phpt create mode 100644 test/repro/issue_4177_getenv_putenv_coerce.php diff --git a/ext/standard/getenv_.php b/ext/standard/getenv_.php index 9771f046c1d..7144a61e511 100644 --- a/ext/standard/getenv_.php +++ b/ext/standard/getenv_.php @@ -17,6 +17,7 @@ * getenv() — read process environment (VM; JIT/AOT via GetenvJitHelper / VmEnv, #3710, #5075, #9092). * * php-src: ext/standard/basic_functions.c — zif_getenv + * Z_PARAM_STR_OR_NULL name: coerce scalars when caller is not strict_types (#4177); TypeError under strict (#17765). */ final class getenv_ extends Internal { @@ -49,7 +50,9 @@ public function execute(Frame $frame): void if (2 === $argc) { $localOnly = $frame->calledArgs[1]->resolveIndirect()->toBool(); } - $name = VmString::coerceTypedNullableStringBuiltinArg($frame->calledArgs[0], 'getenv', 0, 'name'); + // Z_PARAM_STR_OR_NULL: coerce int/float/bool when caller is not strict_types (#4177). + // Always-typed rejection (#17765) only applies under caller strict_types (php-src-strict). + $name = VmString::typedNullableStringBuiltinArgForFrame($frame, 0, 'getenv', 0, 'name'); if (null === $name) { $frame->returnVar->array(VmEnv::getAllEnvironmentTable()); @@ -86,7 +89,14 @@ public function call(Context $context, JITVariable ...$args): Value return JitEnv::getenv( $context, - JitStringBuiltinArg::lowerRequiredString($context, $args[0], 'getenv', 0, 'name', '?string'), + JitStringBuiltinArg::lowerStrictOrCoercible( + $context, + $args[0], + 'getenv', + 0, + 'name', + '?string' + ), $localOnlyI8 ); } diff --git a/test/compliance/cases/stdlib/getenv_enum_case.phpt b/test/compliance/cases/stdlib/getenv_enum_case.phpt index ec4863076b0..6ebc007f67d 100644 --- a/test/compliance/cases/stdlib/getenv_enum_case.phpt +++ b/test/compliance/cases/stdlib/getenv_enum_case.phpt @@ -19,5 +19,5 @@ foreach ([ } ?> --EXPECT-- -getenv: getenv(): Argument #1 ($name) must be of type string, E given +getenv: getenv(): Argument #1 ($name) must be of type ?string, E given putenv: putenv(): Argument #1 ($assignment) must be of type string, E given diff --git a/test/compliance/cases/stdlib/getenv_enum_case_jit.phpt b/test/compliance/cases/stdlib/getenv_enum_case_jit.phpt index 4af465aaa05..9269ba0d709 100644 --- a/test/compliance/cases/stdlib/getenv_enum_case_jit.phpt +++ b/test/compliance/cases/stdlib/getenv_enum_case_jit.phpt @@ -19,5 +19,5 @@ foreach ([ } ?> --EXPECT-- -getenv: getenv(): Argument #1 ($name) must be of type string, E given +getenv: getenv(): Argument #1 ($name) must be of type ?string, E given putenv: putenv(): Argument #1 ($assignment) must be of type string, E given diff --git a/test/compliance/cases/stdlib/getenv_scalar_coerce.phpt b/test/compliance/cases/stdlib/getenv_scalar_coerce.phpt new file mode 100644 index 00000000000..c5627e89734 --- /dev/null +++ b/test/compliance/cases/stdlib/getenv_scalar_coerce.phpt @@ -0,0 +1,18 @@ +--TEST-- +stdlib getenv() — scalar name coerces without caller strict_types (#4177, ext/standard/basic_functions.c) +--FILE-- + +--EXPECT-- +'one' +'zero' +'one' +false +'one' diff --git a/test/compliance/cases/stdlib/getenv_scalar_coerce_jit.phpt b/test/compliance/cases/stdlib/getenv_scalar_coerce_jit.phpt new file mode 100644 index 00000000000..16f2cae0ef5 --- /dev/null +++ b/test/compliance/cases/stdlib/getenv_scalar_coerce_jit.phpt @@ -0,0 +1,18 @@ +--TEST-- +stdlib getenv() JIT — scalar name coerces without caller strict_types (#4177) +--FILE-- + +--EXPECT-- +'one' +'zero' +'one' +false +'one' diff --git a/test/repro/issue_4177_getenv_putenv_coerce.php b/test/repro/issue_4177_getenv_putenv_coerce.php new file mode 100644 index 00000000000..839f2cbb5dd --- /dev/null +++ b/test/repro/issue_4177_getenv_putenv_coerce.php @@ -0,0 +1,22 @@ +getMessage(), "\n"; +} + +$f = fopen('php://memory', 'r+'); +fwrite($f, 'x'); +rewind($f); +echo 'fread: ', fread($f, 2), "\n";