diff --git a/lib/JIT/Builtin/OpensslDigestRuntime.php b/lib/JIT/Builtin/OpensslDigestRuntime.php index f2bf79cefda..f33e379510a 100644 --- a/lib/JIT/Builtin/OpensslDigestRuntime.php +++ b/lib/JIT/Builtin/OpensslDigestRuntime.php @@ -10,10 +10,15 @@ use PHPLLVM\Value\Function_ as LlvmFunction; /** - * JIT/AOT link for openssl_digest() via OpensslDigestJitHelper PHP (#21081, #22554). + * JIT/AOT link for openssl_digest() via OpensslDigestJitHelper PHP (#21081, #22554, #32868). * * Helper compile: {@see JitVmHelperLink::ensureCompiled} (peer MathModf #22519). * Peer of {@see OpensslEncryptRuntime}. SSOT: {@see \PHPCompiler\ext\openssl\VmOpenssl::digest} + * + * Module-local ABI owner (getNamedFunction first): Builtin\Type no longer always-declares + * an empty shell (#32868 / peer #32866) — leftover Type decls mint openssl_digest.1 + * (#31894 / #32122). + * * php-src: ext/openssl/openssl.c */ final class OpensslDigestRuntime @@ -77,12 +82,37 @@ private static function implementIfMissing(Context $context, string $name, calla return; } - $fn = $context->lookupFunction($name); + $fn = self::declareAbi($context, $name, $probe); $emit($context, $fn); $context->registerFunction($name, $fn); $context->builder->clearInsertionPosition(); } + private static function declareAbi(Context $context, string $name, ?LlvmFunction $probe): LlvmFunction + { + if (null !== $probe) { + return $probe; + } + + $strPtr = $context->getTypeFromString('__string__*'); + $i64 = $context->getTypeFromString('int64'); + + $ft = match ($name) { + '__compiler_openssl_digest' => $context->context->functionType( + $strPtr, + false, + $strPtr, + $strPtr, + $i64 + ), + default => throw new \LogicException( + 'OpensslDigestRuntime unknown ABI '.$name.' (#32868)' + ), + }; + + return $context->module->addFunction($name, $ft); + } + private static function implementDigestBridge(Context $context, LlvmFunction $fn): void { $entry = $fn->appendBasicBlock('ossl_digest_bridge_entry'); diff --git a/lib/JIT/Builtin/Type.php b/lib/JIT/Builtin/Type.php index fb2e709e728..cf6b94c2d18 100755 --- a/lib/JIT/Builtin/Type.php +++ b/lib/JIT/Builtin/Type.php @@ -527,16 +527,10 @@ public function register(): void { // always-on shells removed (#32859): NestedJIT/AOT bridge is OpensslEncryptRuntime // (getNamedFunction first; Type::initialize still ensureLinked). Leftover Type // empty decls vs Runtime ABI drift mint openssl_encrypt.1 (#31894 / #32122). - // openssl_digest — NestedJIT OpensslDigestJitHelper (#21081) - $fntypeOpensslDigest = $this->context->context->functionType( - $strPtr, - false, - $strPtr, - $strPtr, - $i64 - ); - $fnOpensslDigest = $this->context->module->addFunction('__compiler_openssl_digest', $fntypeOpensslDigest); - $this->context->registerFunction('__compiler_openssl_digest', $fnOpensslDigest); + // __compiler_openssl_digest always-on shell removed (#32868): NestedJIT/AOT + // bridge is OpensslDigestRuntime (getNamedFunction first; Type::initialize still + // ensureLinked). Leftover Type empty decls vs Runtime ABI drift mint + // openssl_digest.1 (#31894 / #32122). // openssl_pbkdf2 — HMAC over __compiler_hash (hex) + LLVM hex-decode (#32410) $fntypeOpensslPbkdf2 = $this->context->context->functionType( $strPtr, @@ -1210,6 +1204,7 @@ public function initialize(): void { PasswordCryptoRuntime::ensureLinked($this->context); OpensslEncryptRuntime::ensureLinked($this->context); OpensslSignRuntime::ensureLinked($this->context); + OpensslDigestRuntime::ensureLinked($this->context); StringStrtr::ensureLinked($this->context); StringPhpinfoRuntime::ensureLinked($this->context); StringDir::ensureLinked($this->context); diff --git a/test/unit/TypeDeadOpensslDigestAbiRuntimeShrinkTest.php b/test/unit/TypeDeadOpensslDigestAbiRuntimeShrinkTest.php new file mode 100644 index 00000000000..5ad049b8d3c --- /dev/null +++ b/test/unit/TypeDeadOpensslDigestAbiRuntimeShrinkTest.php @@ -0,0 +1,78 @@ + */ + private function droppedAbis(): array + { + return [ + '__compiler_openssl_digest', + ]; + } + + public function testTypeBuiltinDropsLeftoverAlwaysOnOpensslDigestAbi(): void + { + $type = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/Type.php'); + $this->assertStringContainsString('#32868', $type); + foreach ($this->droppedAbis() as $sym) { + $this->assertDoesNotMatchRegularExpression( + '/addFunction\(\s*[\'"]'.preg_quote($sym, '/').'[\'"]/', + $type, + "Builtin\\Type must not always-declare {$sym} (#32868)" + ); + $this->assertStringNotContainsString( + "registerFunction('{$sym}'", + $type, + "Builtin\\Type must not always-register {$sym} (#32868)" + ); + } + $this->assertStringContainsString("addFunction('exit'", $type); + $this->assertStringContainsString("addFunction('abort'", $type); + $this->assertStringContainsString("registerFunction('__compiler_convert_uuencode'", $type); + $this->assertStringContainsString('OpensslDigestRuntime::ensureLinked', $type); + } + + public function testRuntimeOwnerDeclaresOpensslDigestAbiModuleLocally(): void + { + $svc = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/OpensslDigestRuntime.php'); + $this->assertStringContainsString('#32868', $svc); + $this->assertStringContainsString('declareAbi(', $svc); + $this->assertStringContainsString('getNamedFunction($name)', $svc); + $this->assertStringContainsString('module->addFunction(', $svc); + $this->assertStringNotContainsString('lookupFunction($name)', $svc); + foreach ($this->droppedAbis() as $sym) { + $this->assertStringContainsString($sym, $svc); + } + } + + public function testTypeInitializeStillEnsureLinksOpensslDigestRuntime(): void + { + $type = (string) file_get_contents(__DIR__.'/../../lib/JIT/Builtin/Type.php'); + $this->assertStringContainsString('OpensslDigestRuntime::ensureLinked($this->context)', $type); + } + + public function testPhpHelpersRemainForDroppedUserScriptBuiltins(): void + { + $this->assertFileExists(__DIR__.'/../../ext/openssl/OpensslDigestJitHelper.php'); + $this->assertFileExists(__DIR__.'/../../ext/openssl/openssl_digest.php'); + $this->assertFileDoesNotExist( + dirname(__DIR__, 2).'/lib/AOT/runtime/openssl_digest.c' + ); + $this->assertFileDoesNotExist( + dirname(__DIR__, 2).'/lib/AOT/runtime/phpc_openssl_digest.c' + ); + } +}