Compare commits

...

1 Commits

Author SHA1 Message Date
Claude Bot
b2accd8d60 Fix LazyProperty assertion when Buffer() called in recursive context
This fixes an assertion failure that occurred when Buffer() was called
as a function (not constructor) with a string argument in a recursive
context where console.log was also used.

The issue was caused by re-entrant initialization of the m_utilInspectFunction
LazyProperty. When Buffer() creates a buffer from a string and console.log is
called in a recursive forEach callback, it would trigger util.inspect
initialization. If util.inspect was already being initialized in a parent
call frame, the LazyProperty assertion would fail.

The fix involves two changes:
1. In JSBuffer.cpp: Use constructorInitializedOnMainThread() instead of
   constructor() to avoid triggering lazy initialization of m_typedArrayUint8
2. In ZigGlobalObject.cpp: Eagerly initialize utilInspectFunction() at the
   end of addBuiltinGlobals() to prevent re-entrant initialization issues

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-17 16:10:06 +00:00
3 changed files with 45 additions and 1 deletions

View File

@@ -2786,7 +2786,7 @@ EncodedJSValue constructBufferFromArray(JSC::ThrowScope& throwScope, JSGlobalObj
{
auto* globalObject = defaultGlobalObject(lexicalGlobalObject);
auto* constructor = lexicalGlobalObject->m_typedArrayUint8.constructor(lexicalGlobalObject);
auto* constructor = lexicalGlobalObject->m_typedArrayUint8.constructorInitializedOnMainThread(lexicalGlobalObject);
MarkedArgumentBuffer argsBuffer;
argsBuffer.append(arrayValue);
JSValue target = globalObject->JSBufferConstructor();

View File

@@ -2763,6 +2763,11 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm)
consoleObject->putDirectCustomAccessor(vm, Identifier::fromString(vm, "Console"_s), CustomGetterSetter::create(vm, getConsoleConstructor, nullptr), PropertyAttribute::CustomValue | 0);
consoleObject->putDirectCustomAccessor(vm, Identifier::fromString(vm, "_stdout"_s), CustomGetterSetter::create(vm, getConsoleStdout, nullptr), PropertyAttribute::DontEnum | PropertyAttribute::CustomValue | 0);
consoleObject->putDirectCustomAccessor(vm, Identifier::fromString(vm, "_stderr"_s), CustomGetterSetter::create(vm, getConsoleStderr, nullptr), PropertyAttribute::DontEnum | PropertyAttribute::CustomValue | 0);
// Initialize util.inspect eagerly to avoid re-entrant initialization issues
// when console.log is called during module loading or in recursive contexts
utilInspectFunction();
RETURN_IF_EXCEPTION(scope, );
}
// ===================== start conditional builtin globals =====================

View File

@@ -0,0 +1,39 @@
import { expect, test } from "bun:test";
// Regression test for LazyProperty assertion failure when Buffer() is called
// as a function (not constructor) in a recursive context with console.log
test("Buffer as function in recursive context with console.log should not crash", () => {
const cent = Buffer.from([194]);
let callCount = 0;
const maxCalls = 5; // Limit recursion to avoid infinite loop
function f6() {
const v8 = Buffer("/posts/:slug([a-z]+)");
if (callCount < maxCalls) {
callCount++;
try {
cent.forEach(f6);
} catch (e) {}
}
// This console.log would trigger util.inspect lazy initialization
// If util.inspect isn't pre-initialized, this could cause re-entrant
// initialization and trigger the LazyProperty assertion
console.log(v8);
}
f6();
// If we got here without crashing, the test passes
expect(callCount).toBe(maxCalls);
});
test("Buffer as function should work like Buffer.from for strings", () => {
const b1 = Buffer("hello");
const b2 = Buffer.from("hello");
expect(b1.toString()).toBe("hello");
expect(b2.toString()).toBe("hello");
expect(b1.equals(b2)).toBe(true);
});