diff --git a/phpunit/code/wrapper-argument-move.php b/phpunit/code/wrapper-argument-move.php new file mode 100644 index 00000000..dadf9e3c --- /dev/null +++ b/phpunit/code/wrapper-argument-move.php @@ -0,0 +1,19 @@ +addFiles([$file]); + $compiler->prepareFile($file); + $cppFile = $compiler->convertFile($file); + $code = file_get_contents($cppFile); + + $this->assertStringContainsString( + 'php_phpunit_wrapper_argument_move(php::takeValue(arg_value),php::takeValue(arg_text),' + . 'php::takeValue(arg_items),php::takeValue(arg_object),arg_count,arg_reference,' + . 'php::takeValue(arg_rest));', + $code, + ); + $this->assertStringNotContainsString('php::takeValue(arg_count)', $code); + $this->assertStringNotContainsString('php::takeValue(arg_reference)', $code); + $this->assertStringContainsString( + 'php_phpunitwrapperargumentmovetarget__consume(this_, php::takeValue(arg_value));', + $code, + ); + $this->assertStringNotContainsString('php::takeValue(this_)', $code); + } +} diff --git a/src/Translator.php b/src/Translator.php index 1ecc9a71..b0d69677 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -2712,7 +2712,11 @@ CODE; } $cppCode .= $this->getIndent() . $cppType . ' ' . $var . ' = ' . $expr . ';' . PHP_EOL; } - $callParams .= 'arg_' . $argInfo->name . ','; + $callParam = $var; + if ($this->canConsumeWrapperArgument($argInfo)) { + $callParam = 'php::takeValue(' . $var . ')'; + } + $callParams .= $callParam . ','; } if ($functionDef->method) { @@ -2735,6 +2739,23 @@ CODE; return $cppCode; } + private function canConsumeWrapperArgument(ArgInfo $argInfo): bool + { + if ($argInfo->byRef) { + return false; + } + if ($argInfo->variadic) { + return true; + } + + return in_array($this->getDefaultArgumentType($argInfo), [ + Type::VAR, + Type::STR, + Type::ARRAY, + Type::OBJECT, + ], true); + } + private function genWrapperRequiredArgCountCheck(FunctionDef $functionDef, string $displayName): string { $required = $functionDef->argCountRequired; diff --git a/tests/compiler/functions/wrapper-argument-move.phpt b/tests/compiler/functions/wrapper-argument-move.phpt new file mode 100644 index 00000000..6224abce --- /dev/null +++ b/tests/compiler/functions/wrapper-argument-move.phpt @@ -0,0 +1,47 @@ +--TEST-- +Zend wrappers safely consume dead by-value arguments +--FILE-- +name, $count, $rest]; + return $result; +} + +function main(): void +{ + $reference = 'before'; + $object = (object) ['name' => 'object']; + $result = wrapper_argument_move('mixed', 'text', [10], $object, 5, $reference, 'x', 'y'); + var_dump($reference, $result); +} +?> +--EXPECT-- +string(7) "updated" +array(6) { + [0]=> + string(5) "mixed" + [1]=> + string(4) "text" + [2]=> + int(10) + [3]=> + string(6) "object" + [4]=> + int(5) + [5]=> + array(2) { + [0]=> + string(1) "x" + [1]=> + string(1) "y" + } +}