From 45d3f5e1dd68261a4c41d4b355b79dc777cfa9ee Mon Sep 17 00:00:00 2001 From: PurHur Date: Thu, 20 Aug 2026 16:00:32 +0000 Subject: [PATCH] php-in-php: drop leftover Type always-on cslashes ABI shells (#32893) StringCslashes already declares addcslashes/stripcslashes via ensureBridge; remove Type empty shells that can mint addcslashes.1 (#31894 / #32122). Co-authored-by: Cursor --- lib/JIT/Builtin/StringCslashes.php | 5 +- lib/JIT/Builtin/Type.php | 11 ++- .../TypeDeadCslashesAbiRuntimeShrinkTest.php | 76 +++++++++++++++++++ 3 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 test/unit/TypeDeadCslashesAbiRuntimeShrinkTest.php diff --git a/lib/JIT/Builtin/StringCslashes.php b/lib/JIT/Builtin/StringCslashes.php index 69858ccbf5f..0ec3c8af745 100644 --- a/lib/JIT/Builtin/StringCslashes.php +++ b/lib/JIT/Builtin/StringCslashes.php @@ -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) */ diff --git a/lib/JIT/Builtin/Type.php b/lib/JIT/Builtin/Type.php index 79b3aec1502..7c7dffb53a5 100755 --- a/lib/JIT/Builtin/Type.php +++ b/lib/JIT/Builtin/Type.php @@ -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. @@ -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); diff --git a/test/unit/TypeDeadCslashesAbiRuntimeShrinkTest.php b/test/unit/TypeDeadCslashesAbiRuntimeShrinkTest.php new file mode 100644 index 00000000000..2c7aa8484cb --- /dev/null +++ b/test/unit/TypeDeadCslashesAbiRuntimeShrinkTest.php @@ -0,0 +1,76 @@ + */ + 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' + ); + } +}