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
5 changes: 4 additions & 1 deletion lib/JIT/Builtin/StringCslashes.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@
use PHPCompiler\JIT\NestedJitCompileScope;

/**
* JIT/AOT link for addcslashes/stripcslashes via CslashesJitHelper PHP (#5652, #9578, #21617).
* JIT/AOT link for addcslashes/stripcslashes via CslashesJitHelper PHP (#5652, #9578, #21617, #32893).
*
* Nested helper compile: {@see JitVmHelperLink::ensureBridge} (HelperRuntimeCache + user-script
* env clear — no hand-rolled NestedJit compile loop). Peer: StringAddslashes #18391 / StringQuotemeta #21589 /
* StringStrRepeat #21601.
* Module-local ABI owner (ensureBridge getNamedFunction first): Builtin\Type no longer
* always-declares empty shells (#32893 / peer #32879) — leftover Type decls mint
* addcslashes.1 (#31894 / #32122).
* SSOT: {@see \PHPCompiler\ext\standard\VmString}.
* php-src: ext/standard/string.c — PHP_FUNCTION(addcslashes) / PHP_FUNCTION(stripcslashes)
*/
Expand Down
11 changes: 5 additions & 6 deletions lib/JIT/Builtin/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -580,12 +580,10 @@ public function register(): void {
);
$fnUudecode = $this->context->module->addFunction('__compiler_convert_uudecode', $fntypeUudecode);
$this->context->registerFunction('__compiler_convert_uudecode', $fnUudecode);
$fntypeAddcslashes = $this->context->context->functionType($strPtr, false, $strPtr, $strPtr);
$fnAddcslashes = $this->context->module->addFunction('__compiler_addcslashes', $fntypeAddcslashes);
$this->context->registerFunction('__compiler_addcslashes', $fnAddcslashes);
$fntypeStripcslashes = $this->context->context->functionType($strPtr, false, $strPtr);
$fnStripcslashes = $this->context->module->addFunction('__compiler_stripcslashes', $fntypeStripcslashes);
$this->context->registerFunction('__compiler_stripcslashes', $fnStripcslashes);
// __compiler_addcslashes / __compiler_stripcslashes always-on shells removed
// (#32893): NestedJIT/AOT bridge is StringCslashes (JitVmHelperLink::ensureBridge;
// Type::initialize still ensureLinked / ensureStripcslashes). Leftover Type empty
// decls vs Runtime ABI drift mint addcslashes.1 (#31894 / #32122).
// __compiler_substr_replace always-on shell removed (#32250): user-script
// substr_replace() stays VmString / ext/standard/substr_replace.php. No
// NestedJIT lookupFunction remains.
Expand Down Expand Up @@ -1162,6 +1160,7 @@ public function initialize(): void {
StringHashAlgos::ensureLinked($this->context);
StringQuotPrint::ensureLinked($this->context);
StringUtf8Latin1::ensureLinked($this->context);
StringCslashes::ensureStandaloneBodies($this->context);
StringStrtr::ensureLinked($this->context);
StringPhpinfoRuntime::ensureLinked($this->context);
StringDir::ensureLinked($this->context);
Expand Down
76 changes: 76 additions & 0 deletions test/unit/TypeDeadCslashesAbiRuntimeShrinkTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\Test\Unit;

use PHPUnit\Framework\TestCase;

/**
* Drop leftover always-on addcslashes/stripcslashes ABI shells from Builtin\Type (#32893).
*
* NestedJIT/AOT bridge stays StringCslashes.
* Runtime owner declares module-locally via JitVmHelperLink::ensureBridge so leftover
* Type empty decls cannot mint addcslashes.1 (#31894 / #32122).
*/
final class TypeDeadCslashesAbiRuntimeShrinkTest extends TestCase
{
/** @return list<string> */
private function droppedAbis(): array
{
return [
'__compiler_addcslashes',
'__compiler_stripcslashes',
];
}

public function testTypeBuiltinDropsLeftoverAlwaysOnCslashesAbis(): void
{
$type = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/Type.php');
$this->assertStringContainsString('#32893', $type);
foreach ($this->droppedAbis() as $sym) {
$this->assertDoesNotMatchRegularExpression(
'/addFunction\(\s*[\'"]'.preg_quote($sym, '/').'[\'"]/',
$type,
"Builtin\\Type must not always-declare {$sym} (#32893)"
);
$this->assertStringNotContainsString(
"registerFunction('{$sym}'",
$type,
"Builtin\\Type must not always-register {$sym} (#32893)"
);
}
$this->assertStringContainsString("addFunction('exit'", $type);
$this->assertStringContainsString("addFunction('abort'", $type);
$this->assertStringContainsString("registerFunction('__compiler_convert_uuencode'", $type);
$this->assertStringContainsString('StringCslashes::ensureStandaloneBodies', $type);
}

public function testRuntimeOwnerDeclaresCslashesAbisModuleLocally(): void
{
$svc = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/StringCslashes.php');
$this->assertStringContainsString('#32893', $svc);
$this->assertStringContainsString('JitVmHelperLink::ensureBridge', $svc);
$this->assertStringContainsString('getNamedFunction', $svc);
foreach ($this->droppedAbis() as $sym) {
$this->assertStringContainsString($sym, $svc, "{$sym} must remain owned by StringCslashes (#32893)");
}
}

public function testTypeInitializeStillEnsureLinksCslashesRuntime(): void
{
$type = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/Type.php');
$this->assertStringContainsString('StringCslashes::ensureStandaloneBodies($this->context)', $type);
}

public function testPhpHelpersRemainForDroppedUserScriptBuiltins(): void
{
$this->assertFileExists(__DIR__.'/../../ext/standard/CslashesJitHelper.php');
$this->assertFileDoesNotExist(
dirname(__DIR__, 2).'/lib/AOT/runtime/cslashes.c'
);
$this->assertFileDoesNotExist(
dirname(__DIR__, 2).'/runtime/cslashes.c'
);
}
}
Loading