Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/jsc/modules/BunJSCModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -590,8 +590,14 @@
(JSGlobalObject * globalObject, CallFrame*))
{
MarkedArgumentBuffer list;
// The protected cell set also contains internal cells (unlinked code blocks,
// private symbols, structures). Those are not valid JavaScript values, so
// handing them to JS as-is causes type confusion the first time one is touched.
globalObject->vm().heap.forEachProtectedCell(
[&](JSCell* cell) { list.append(cell); });
[&](JSCell* cell) {
if (cell->isObject())
list.append(cell);

Check warning on line 599 in src/jsc/modules/BunJSCModule.h

View check run for this annotation

Claude / Claude Code Review

Stale JSDoc warning on getProtectedObjects() type declaration

The JSDoc at `packages/bun-types/jsc.d.ts:201` ("Warning: not all of the returned objects are supposed to be observable from JavaScript.") described the pre-fix behavior where internal cells could appear in the array; now that only `JSObject` cells are returned, every element is safely observable and the warning is stale. Consider dropping or rewording that line (and optionally tightening the return type to `object[]`) in this PR so the docs match the new contract.
Comment thread
robobun marked this conversation as resolved.
});
RELEASE_ASSERT(!list.hasOverflowed());
return JSC::JSValue::encode(constructArray(
globalObject, static_cast<JSC::ArrayAllocationProfile*>(nullptr), list));
Expand Down
24 changes: 24 additions & 0 deletions test/js/bun/jsc/bun-jsc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,30 @@ it("deserialize rejects a RegExp record whose pattern does not parse", async ()
expect(exitCode).toBe(0);
});

it("getProtectedObjects returns only objects", async () => {
// The protected cell set also contains internal JSC cells (unlinked code
// blocks, private symbols, structures). Those are not JavaScript values, so
// generic operations on them (Object(), Object.prototype.toString.call,
// String(list)) crashed the process instead of behaving like objects.
const script = `
import { getProtectedObjects } from "bun:jsc";
const list = getProtectedObjects();
for (const value of list) {
if (Object(value) !== value) throw new Error("getProtectedObjects returned a non-object: " + typeof value);
Object.prototype.toString.call(value);
}
console.log("ok", list.length > 0);
`;
await using proc = Bun.spawn({
cmd: [bunExe(), "-e", script],
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
expect({ stdout, stderr, exitCode }).toEqual({ stdout: "ok true\n", stderr: "", exitCode: 0 });
});

it("serialize rejects a CryptoKey created with extractable set to false", async () => {
// bun:jsc serialize() (and node:v8 serialize(), which wraps it) hands the raw
// structured-clone buffer to the caller, so a key imported with
Expand Down
Loading