From 09e1a8c5c3545322ec6f4a9c230c8cd0317c1246 Mon Sep 17 00:00:00 2001 From: PurHur Date: Tue, 19 May 2026 18:33:18 +0000 Subject: [PATCH] fix(aot): copy hashtable strings on indexed read and value assign explode() PHPT failed intermittently with free(): invalid pointer when reading explode(...)[0] inline: the hashtable could be freed before __hashtable__readStringAt ran. Pin the table across readStringAt, return an owned copy via __string__separate, and separate before __value__writeString. Co-authored-by: Cursor --- lib/JIT.php | 7 ++++++- lib/JIT/Builtin/Type/HashTable.php | 1 + lib/JIT/Variable.php | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/JIT.php b/lib/JIT.php index ca47f4c2..1f13404b 100644 --- a/lib/JIT.php +++ b/lib/JIT.php @@ -653,10 +653,15 @@ private function assignOperand(Operand $result, Variable $value): void { return; case Variable::TYPE_STRING: + $str = $this->context->helper->loadValue($value); + $owned = $this->context->builder->call( + $this->context->lookupFunction('__string__separate'), + $str + ); $this->context->builder->call( $this->context->lookupFunction('__value__writeString'), $valueRef, - $this->context->helper->loadValue($value) + $owned ); return; diff --git a/lib/JIT/Builtin/Type/HashTable.php b/lib/JIT/Builtin/Type/HashTable.php index 063bec7e..8de319fd 100755 --- a/lib/JIT/Builtin/Type/HashTable.php +++ b/lib/JIT/Builtin/Type/HashTable.php @@ -419,6 +419,7 @@ private function implementReadStringAt(): void $values = $this->context->builder->load($this->context->builder->structGep($ht, $map['values'])); $entry = $this->context->builder->inBoundsGep($values, $index); $str = $this->context->builder->call($this->context->lookupFunction('__value__readString'), $entry); + $str = $this->context->builder->call($this->context->lookupFunction('__string__separate'), $str); $this->context->builder->branch($merge); $this->context->builder->positionAtEnd($emptyBlock); $empty = $this->context->builder->call( diff --git a/lib/JIT/Variable.php b/lib/JIT/Variable.php index e3909418..77760119 100755 --- a/lib/JIT/Variable.php +++ b/lib/JIT/Variable.php @@ -439,11 +439,13 @@ public function dimFetch(self $dim, ?Type $expectedType = null): Variable { $this->context->getTypeFromString('size_t') ); if (null !== $expectedType && Type::TYPE_STRING === $expectedType->type) { + $this->context->refcount->addref($ht); $str = $this->context->builder->call( $this->context->lookupFunction('__hashtable__readStringAt'), $ht, $index ); + $this->context->refcount->delref($ht); return new Variable( $this->context,