Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions ext/standard/getenv_.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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());

Expand Down Expand Up @@ -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
);
}
Expand Down
2 changes: 1 addition & 1 deletion test/compliance/cases/stdlib/getenv_enum_case.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion test/compliance/cases/stdlib/getenv_enum_case_jit.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
18 changes: 18 additions & 0 deletions test/compliance/cases/stdlib/getenv_scalar_coerce.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
stdlib getenv() — scalar name coerces without caller strict_types (#4177, ext/standard/basic_functions.c)
--FILE--
<?php
putenv('1=one');
putenv('0=zero');
echo var_export(getenv(1), true), "\n";
echo var_export(getenv(0), true), "\n";
echo var_export(getenv(true), true), "\n";
echo var_export(getenv(false), true), "\n";
echo var_export(getenv(1.0), true), "\n";
?>
--EXPECT--
'one'
'zero'
'one'
false
'one'
18 changes: 18 additions & 0 deletions test/compliance/cases/stdlib/getenv_scalar_coerce_jit.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
stdlib getenv() JIT — scalar name coerces without caller strict_types (#4177)
--FILE--
<?php
putenv('1=one');
putenv('0=zero');
echo var_export(getenv(1), true), "\n";
echo var_export(getenv(0), true), "\n";
echo var_export(getenv(true), true), "\n";
echo var_export(getenv(false), true), "\n";
echo var_export(getenv(1.0), true), "\n";
?>
--EXPECT--
'one'
'zero'
'one'
false
'one'
22 changes: 22 additions & 0 deletions test/repro/issue_4177_getenv_putenv_coerce.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
/**
* Repro for #4177 — getenv()/putenv() scalar→string coercion (php-src-strict).
* Without declare(strict_types=1), Zend coerces int/bool names; with it, TypeError.
*/
putenv('4177KEY=hello');
putenv('1=one');

echo 'getenv int: ', var_export(getenv(1), true), "\n";
echo 'getenv str: ', var_export(getenv('4177KEY'), true), "\n";

try {
putenv(4177001);
echo "putenv int: ok\n";
} catch (Throwable $t) {
echo 'putenv int: ', $t::class, ': ', $t->getMessage(), "\n";
}

$f = fopen('php://memory', 'r+');
fwrite($f, 'x');
rewind($f);
echo 'fread: ', fread($f, 2), "\n";