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
10 changes: 8 additions & 2 deletions ext/spl/SplFileObjectBuiltin.php
Original file line number Diff line number Diff line change
Expand Up @@ -1202,9 +1202,15 @@ public function execute(Frame $frame): void
SplFileObjectBuiltin::CLASS_LC,
'SplFileObject::setFlags()'
);
// php-src zim_SplFileObject_setFlags — exactly 1 user arg (#31008).
// php-src zim_SplFileObject_setFlags — ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG (#31796).
$this->requireExactUserArgCount($frame, 'SplFileObject::setFlags', 1);
$flags = $frame->calledArgs[1]->resolveIndirect()->toInt();
$flags = VmMath::parseZParamLongBuiltinArgForFrame(
$frame,
1,
'SplFileObject::setFlags',
1,
'flags'
);
SplFileObjectStorage::setFlags($object, $flags);
}
}
Expand Down
1 change: 1 addition & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,7 @@
<file>./test/compliance/SplFileObjectExcessArgc30937JITTest.php</file>
<file>./test/compliance/SplFileObjectExcessArgc31008VMTest.php</file>
<file>./test/compliance/SplFileObjectExcessArgc31008JITTest.php</file>
<file>./test/compliance/SplFileObjectSetFlagsNullSoft31796VMTest.php</file>
<file>./test/compliance/DirItExcessArgc31009VMTest.php</file>
<file>./test/compliance/DirItExcessArgc31009JITTest.php</file>
<file>./test/compliance/RiiGlobExcessArgc31010VMTest.php</file>
Expand Down
20 changes: 20 additions & 0 deletions test/compliance/SplFileObjectSetFlagsNullSoft31796VMTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace PHPCompiler;

require_once __DIR__.'/../BaseTest.php';

/** Focused VM PHPT for SplFileObject::setFlags(null) soft-null (#31796). */
final class SplFileObjectSetFlagsNullSoft31796VMTest extends BaseTest
{
protected string $BIN = __DIR__.'/../../bin/vm.php';

public static function providePHPTests(): \Generator
{
$path = __DIR__.'/cases/spl/splfileobject_setflags_null_soft.phpt';
[$name, $code, $sections] = self::parsePHPT($path, 'splfileobject_setflags_null_soft');
yield $name => [$name, $code, $sections];
}
}
27 changes: 27 additions & 0 deletions test/compliance/cases/spl/splfileobject_setflags_null_soft.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
SplFileObject::setFlags(null) — soft-null DEP then flags=0 (#31796)
--FILE--
<?php
error_reporting(E_ALL);
set_error_handler(static function (int $no, string $msg): bool {
if (E_DEPRECATED === $no) {
echo "DEP:{$msg}\n";
return true;
}
echo "E{$no}:{$msg}\n";
return true;
});
$tmp = tempnam(sys_get_temp_dir(), 'sfo31796');
file_put_contents($tmp, "a\nb\n");
try {
$f = new SplFileObject($tmp);
$f->setFlags(null);
echo 'flags=' . $f->getFlags() . "\n";
} catch (Throwable $e) {
echo get_class($e) . ': ' . $e->getMessage() . "\n";
}
@unlink($tmp);
?>
--EXPECT--
DEP:SplFileObject::setFlags(): Passing null to parameter #1 ($flags) of type int is deprecated
flags=0
115 changes: 115 additions & 0 deletions test/unit/Issue31796SplFileObjectSetFlagsNullTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

declare(strict_types=1);

namespace PHPCompiler;

use PHPUnit\Framework\TestCase;

/**
* SplFileObject::setFlags(null) — soft-null E_DEPRECATED then flags=0 (#31796).
*
* php-src: ext/spl/spl_directory.c — zim_SplFileObject_setFlags
*/
final class Issue31796SplFileObjectSetFlagsNullTest extends TestCase
{
public function testVmSetFlagsNullDeprecationThenZero(): void
{
$out = $this->runBin('bin/vm.php', $this->softProbeCode());
$this->assertSame($this->expectedSoftOutput(), $out);
}

public function testJitSetFlagsNullDeprecationThenZero(): void
{
$out = $this->runBin('bin/jit.php', $this->softProbeCode());
$this->assertSame($this->expectedSoftOutput(), $out);
}

public function testVmStrictTypesSetFlagsNullTypeError(): void
{
$out = $this->runBin('bin/vm.php', $this->strictProbeCode());
$this->assertSame(
"TypeError: SplFileObject::setFlags(): Argument #1 (\$flags) must be of type int, null given\n",
$out
);
}

private function expectedSoftOutput(): string
{
return "DEP:SplFileObject::setFlags(): Passing null to parameter #1 (\$flags) of type int is deprecated\n"
."flags=0\n";
}

private function softProbeCode(): string
{
return <<<'PHP'
<?php
error_reporting(E_ALL);
set_error_handler(static function (int $no, string $msg): bool {
if (E_DEPRECATED === $no) {
echo "DEP:{$msg}\n";
return true;
}
echo "E{$no}:{$msg}\n";
return true;
});
$tmp = tempnam(sys_get_temp_dir(), 'sfo31796');
file_put_contents($tmp, "a\nb\n");
try {
$f = new SplFileObject($tmp);
$f->setFlags(null);
echo 'flags=' . $f->getFlags() . "\n";
} catch (Throwable $e) {
echo get_class($e) . ': ' . $e->getMessage() . "\n";
}
@unlink($tmp);
PHP;
}

private function strictProbeCode(): string
{
return <<<'PHP'
<?php
declare(strict_types=1);
error_reporting(E_ALL);
$tmp = tempnam(sys_get_temp_dir(), 'sfo31796s');
file_put_contents($tmp, "a\n");
try {
$f = new SplFileObject($tmp);
$f->setFlags(null);
echo "ok\n";
} catch (Throwable $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
@unlink($tmp);
PHP;
}

private function runBin(string $bin, string $code): string
{
$repo = dirname(__DIR__, 2);
$tmp = tempnam(sys_get_temp_dir(), 'phpc_31796_');
$this->assertNotFalse($tmp);
file_put_contents($tmp, $code);
$env = $_ENV;
LlvmToolchain::applyProcessEnv($env, $repo);
$proc = proc_open(
['php', $repo.'/'.$bin, $tmp],
[0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']],
$pipes,
$repo,
$env
);
$this->assertIsResource($proc);
fclose($pipes[0]);
$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
$exit = proc_close($proc);
@unlink($tmp);
$this->assertSame(0, $exit, $stdout.$stderr);

return $stdout;
}
}
Loading