Repository navigation
Stdlib: hash_init() / hash_update() / hash_final() / hash_copy() — incremental ext/hash API #3357
Copy link
Copy link
Closed
Labels
area:vmVirtual machineVirtual machineenhancementNew feature or requestNew feature or requestimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimSpec complete: repro, php-src ref, done-when — safe for workers to claimphase-4:stdlibPhase 4 – stdlib for web appsPhase 4 – stdlib for web appsstdlib
Description
Category
stdlib · php-src-strict · spec refresh 2026-06-18
Problem
Incremental ext/hash API is partially landed. hash_init() / hash_update() / hash_final() register and produce correct digests on VM (verified 2026-06-18). Remaining Zend gaps:
hash_copy()— must duplicate non-finalizedHashContext; semantics after partialhash_update/ beforehash_finalhash_pbkdf2()/hash_hkdf()— still missing or stubbed (tracked also by enum-operand issues Stdlib: hash_pbkdf2() — enum case password operand must TypeError (ext/hash/hash.c, php-src-strict) #9027)- JIT/AOT — incremental context resource/object lifecycle on compiled path
Streaming file hashing and PBKDF2 key derivation cannot be expressed end-to-end until copy + KDF land.
php-src reference
- php/php-src
ext/hash/hash.c—php_hash_init,php_hash_update,php_hash_final,php_hash_copy - php/php-src
ext/hash/hash_pbkdf2.c - php/php-src
ext/hash/hash_hkdf.c - php/php-src
ext/hash/hash.stub.php
Repro — incremental digest (GREEN on VM)
<?php
$ctx = hash_init('sha256');
hash_update($ctx, 'hello ');
hash_update($ctx, 'world');
echo hash_final($ctx), "\n";./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
php repro_hash_incremental.php
php bin/vm.php repro_hash_incremental.php
'| Engine | Output |
|---|---|
| Zend | b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 |
| VM | same ✅ |
Repro — hash_copy() before finalize (FAIL / unverified)
<?php
$ctx = hash_init('sha256');
hash_update($ctx, 'hello ');
$ctx2 = hash_copy($ctx);
hash_update($ctx, 'world');
echo hash_final($ctx), "\n";
echo hash_final($ctx2), "\n";| Engine | Expected |
|---|---|
| Zend | full digest on $ctx; hello partial state digest on $ctx2 |
| VM | verify + fix if differs |
Note: hash_copy() after hash_final() must TypeError on both engines (finalized context).
Scope (this repo)
| Area | Path |
|---|---|
| VM | ext/hash/ or ext/standard/VmHash.php — HashContext object lifecycle |
| Builtins | hash_copy.php, hash_pbkdf2.php, hash_hkdf.php registration |
| JIT | deferred v1; document VM-only in matrix |
| Tests | test/compliance/cases/stdlib/hash_copy.phpt, hash_pbkdf2_roundtrip.phpt |
PHP-in-PHP first: digest state in PHP; libc only for underlying algo if already used by hash().
Done when (php-src-strict)
- Incremental repro (above) stays green
-
hash_copy()repro matches Zend for pre-finalize and rejects finalized context -
hash_pbkdf2()round-trip matches Zend test vector (link Stdlib: hash_pbkdf2() — enum case password operand must TypeError (ext/hash/hash.c, php-src-strict) #9027 enum guards separately) -
hash_hkdf()basic extract/expand vector matches Zend -
./script/ci-fast.sh --filter HashContextgreen -
docs/capabilities.mdupdated viascript/capability-matrix.php
Verification
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && vendor/bin/phpunit --filter HashContext'Links
- One-shot
hash()/hash_hmac()(implemented) · Stdlib: hash_algos() / hash_file() / hash_hmac_file() — ext/hash introspection and file hashing #3221hash_file()· Epic: Self-host critical path — compiler compiles itself (M3→M5) #1492
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:vmVirtual machineVirtual machineenhancementNew feature or requestNew feature or requestimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimSpec complete: repro, php-src ref, done-when — safe for workers to claimphase-4:stdlibPhase 4 – stdlib for web appsPhase 4 – stdlib for web appsstdlib
Activity
Bootstrap: ext/hash module skeleton — register hash_init/hash_algos (#…
PurHur commentedon Jul 7, 2026
claim: PHP Compiler STD Lib — starting this run (JIT/AOT incremental hash_context)
PurHur commentedon Jul 7, 2026
Substantive WIP merged to PR #17087.
Done this run
hash_init/hash_update/hash_final/hash_copyviaJitHashContext(object-property buffering +JitHash::hashfinalize).StringHashCryptoPhpbridge fix: coerce ABIi32raw flag → helperi1(fixes AOT module verify for__compiler_hash*).Blocker (not merged)
c:main_before_phpwhenhash_update/hash_finalare linked in the same binary (Docker).hash_init()alone runs.Verify
php bin/vm.php test/repro/hash_context_incremental.php ./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && php bin/compile.php -o /tmp/hash_ctx test/repro/hash_context_incremental.php'PR: #17087
PurHur commentedon Jul 7, 2026
claim: PHP Compiler STD Lib — continuing PR #17087 (AOT execute segfault on hash_update/hash_final)
hash: HashContext JIT properties as TYPE_STRING slots (#3357)
PurHur commentedon Jul 7, 2026
WIP update (continued PR #17087)
Committed
f3e9ed490: HashContext__hc*properties now useTYPE_STRINGobject slots + deep-copy inhash_copy();StringHashCrypto::ensureLinkedmoved tohash_final()only.Still red — AOT execute
test/repro/hash_context_incremental.phpgreenvendor/bin/phpunit test/aot/AotTest.php --filter hash_context_incremental→ empty stdout (compile OK)hash_init()JIT in the same binary appears to poison subsequenthash()echo output (even bareallocate()without property stores). Master cannot AOT-compilehash()at all (LLVM verify i32→i1 bridge); this branch fixes compile viaStringHashCryptoPhp::callHelperBridgebut runtime digest echo is still broken when HashContext builtins are linked.Next step
HashContextJitHelper+ thin ABI (object-keyed incremental state), or gdb onc:main_before_phpwithPHP_COMPILER_LLVM_ASSERT=1ext/hash/hash.cphp_hash_*context copy/finalizeStdlib: advertise locale BCP-47 parsers on default 8.4.0-dev profile (#…
PurHur commentedon Jul 7, 2026
claim: PHP Compiler STD Lib Advanced — continuing hash JIT/AOT PR #17087 (AOT execute segfault)
hash: HashContext AOT slot layout + direct property access (#3357)
PurHur commentedon Jul 7, 2026
Progress update (advanced stdlib): continued PR #17087 branch.
VM:
test/repro/hash_context_incremental.phpgreen.AOT bisect:
hash_init()only → runs OKhash_update()/hash_copy()/hash_final()→ segfault atc:main_before_php(master + branch)Commits pushed: pre-register HashContext
__hc*string slots inregisterExternalClass; direct slot load/store inJitHashContext(avoid double__string__separate). VM unchanged; AOT read path still crashes.Next: bisect whether
loadStringPtrPropertyreturns null/corrupt vsHashContextRuntime/StringHashCryptoinit whenhash_finalis linked; gdb/LLVM IR dump on minimalhash_copybinary.48 remaining items
PurHur commentedon Jul 13, 2026
Run handoff (2026-07-13) — partial progress on user-script hash AOT defer path; merge blocked by master-wide AOT regression.
Claim
claim: PHP Compiler Ext — I/O & Crypto — starting this run (hash AOT standalone digest bridges, PR #17897 / #3357).Work pushed
Branch
agent/issue-3357-hash-aot-standalone:StringHashAlgos: user-script defer → inlineHashAlgosRegistryLLVM (avoid nestedHashAlgosJitHelper/ broken__hashtable__bridge)StringHashCryptoJit: user-script defer → skip nestedHashEqualsJitHelper; stub__compiler_hash_equals; keepStringHashCryptoLlvmEVP pathVerification
Blocker
Master user-script AOT is broken for all
-r/examples compiles (echo-only repro fails LLVM module verify). Root cause is not isolated to hash crypto init — disablingStringHashCryptoinContext::ensureMinimalUserStandaloneBodiesdoes not unblock. Likely recent standalone-init / helper-runtime / hashtable bridge regression (suspect commits around8486e08e7utf8,36952166dmb_numericentity,56c59024fhelper ctors — needs bisect).Next step
writeHashtable/ alloca%__hashtable__*pattern)PurHur commentedon Jul 13, 2026
claim: PHP Compiler Ext — I/O & Crypto — starting this run (hash_pbkdf2 AOT via StringHashCryptoLlvm PKCS5_PBKDF2_HMAC)
Hash AOT: OpenSSL PKCS5_PBKDF2_HMAC bridge for hash_pbkdf2 (#3357) (#…
PurHur commentedon Jul 13, 2026
Merged (hash_pbkdf2 AOT): #18750
Standalone user-script AOT
hash_pbkdf2()now uses OpenSSLPKCS5_PBKDF2_HMACinStringHashCryptoLlvminstead of the null__compiler_hash_pbkdf2stub (exit 139 → correct digest).Verification:
Still open on #3357:
hash_hkdfAOT stub,hash_hmac_algosAOT segfault (pre-existing on master).php-in-php: hash standalone defer — skip nested hash_algos/hash_equal…
PurHur commentedon Jul 14, 2026
claim: PHP Compiler Ext — I/O & Crypto — starting this run (hash_hkdf/hash_pbkdf2 AOT segfault on standalone user-script)
PurHur commentedon Jul 14, 2026
Merged via #18986.
Root cause: user-script standalone AOT defers nested PHP helpers (documented in
UserScriptAotDeferNestedJit).bin2hex()still routed through nestedBin2hexJitHelper→ segfault afterstrlen()on raw hash/HKDF/PBKDF2 output. Raw digests also used__string__initfrom stackallocabuffers → zero/incorrect payload bytes.Fix: inline LLVM hex loop for
bin2hexdefer (mirrorsStringHashCryptoLlvmhex path) +__string__alloc+memcpyfor raw EVP/HKDF/PBKDF2 digests.Verification (Docker):
Hash AOT: LLVM bin2hex defer + memcpy raw digest strings (#3357) (#18986
php-in-php: delete StringHashCryptoLlvm — user-script AOT via JitVmHe…
PurHur commentedon Jul 15, 2026
claim: PHP Compiler Ext — I/O & Crypto — starting this run (hash_final AOT standalone returns raw digest not hex — hash_context_incremental AOT red)
Hash: fix hash_final() standalone AOT hex output (#3357) (#19181)
PurHur commentedon Jul 15, 2026
Merged via #19181.
Fix: standalone AOT
hash_final()now hex-encodes via__compiler_bin2hexwhen$binary=false(was emitting raw 32-byte SHA-256).Verification:
php-in-php: move hash_algos/hmac_algos inline registry LLVM to JitHas…
php-in-php: move hash_algos/hmac_algos inline registry LLVM to JitHas…
php-in-php: move StringHashCryptoLlvm to JitHashCryptoKernel (#19362) (…