void function containing // inside a string literal is rewritten into unparseable code.
The return-check injection neutralises a trailing // line comment on the last statement, but does not check whether the // is inside a string. 'https://x' becomes 'https:/*x', and the appended */ closes a comment that was never opened.
Version
- typephp/typephp v0.6.14
- PHP 8.5.10
Repro
<?php
require 'vendor/autoload.php';
$code = <<<'PHP'
<?php
namespace App;
class Example
{
public function show(): void
{
echo 'https://example.test/path';
}
}
PHP;
$out = TypePHP\Internal\StreamWrapper::transformSource($code, __DIR__ . '/src/Example.php');
$tmp = tempnam(sys_get_temp_dir(), 'tp') . '.php';
file_put_contents($tmp, $out);
passthru('php -n -l ' . escapeshellarg($tmp));
Actual
public function show(): void
{ if (($__typephpErr = \TypePHP\Internal\RuntimeTypeChecker::setupScope(...)) ...) { ... }
echo 'https:/*example.test/path'; */ if (($__typephpRet = ...
}
Parse error: syntax error, unexpected token "*"
Expected
String literals unchanged. Only // that begins a real comment token may be rewritten.
Notes
- Not avoidable by config.
'returns' => false still corrupts.
- Every PHPUnit test method is
: void, so any assertion carrying a URL triggers it. 14 of 804 files in one codebase.
- Fails loudly. Across those 804 files, 0 produced output that parses with altered string literals — so no silent corruption observed, only parse errors.
Suggested fix
Locate the trailing comment with token_get_all() (T_COMMENT ending the statement) instead of scanning the line text for //.
voidfunction containing//inside a string literal is rewritten into unparseable code.The return-check injection neutralises a trailing
//line comment on the last statement, but does not check whether the//is inside a string.'https://x'becomes'https:/*x', and the appended*/closes a comment that was never opened.Version
Repro
Actual
Expected
String literals unchanged. Only
//that begins a real comment token may be rewritten.Notes
'returns' => falsestill corrupts.: void, so any assertion carrying a URL triggers it. 14 of 804 files in one codebase.Suggested fix
Locate the trailing comment with
token_get_all()(T_COMMENTending the statement) instead of scanning the line text for//.