mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-28 06:53:42 +08:00
Refuse elements on Array.prototype
This commit is contained in:
@@ -997,6 +997,11 @@ ScrDyn *scr_dyn_get_own_property_descriptor(ScrDyn *target, ScrDyn *key);
|
||||
ScrDyn *scr_dyn_array_proto_call(ScrDyn *target, ScrStr *method, ScrDyn *args);
|
||||
ScrDyn *scr_dyn_array_prototype(void); /* +1, installs native method adapters */
|
||||
ScrDyn *scr_dyn_array_prototype_base(void); /* +1, shared native array identity */
|
||||
/* Native arrays read their holes as undefined without consulting
|
||||
* Array.prototype, so storing an element on Array.prototype raises SC2020.
|
||||
* True (with the error pending) when `recv` is Array.prototype. */
|
||||
bool scr_dyn_array_prototype_element_fence(const ScrDyn *recv);
|
||||
bool scr_dyn_is_array_prototype(const ScrDyn *d);
|
||||
/* The checked-dynamic keyed WRITE (`h.k = v` on a dyn receiver): OBJ sets
|
||||
* the member (JS: later writes win, insertion order); undefined/null and
|
||||
* non-object kinds throw Node's catchable TypeErrors (strict-mode
|
||||
|
||||
@@ -811,6 +811,10 @@ static ScrDyn *scr_dyn_invoke_impl(
|
||||
if (recv->kind == SCR_DYN_HANDLE) {
|
||||
return scr_dynh_dispatch(recv, method, args, argc, what);
|
||||
}
|
||||
if (scr_dyn_is_array_prototype(recv) && dyn_arr_proto_mutates(method)) {
|
||||
scr_dyn_array_prototype_element_fence(recv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (recv->kind == SCR_DYN_PROXY) {
|
||||
|
||||
@@ -674,6 +674,17 @@ void scr_dyn_from_leave(void) {
|
||||
*/
|
||||
static SCR_TL ScrDyn *scr_builtin_array_prototype;
|
||||
|
||||
bool scr_dyn_is_array_prototype(const ScrDyn *d) {
|
||||
return d && d == scr_builtin_array_prototype;
|
||||
}
|
||||
|
||||
bool scr_dyn_array_prototype_element_fence(const ScrDyn *recv) {
|
||||
if (!scr_dyn_is_array_prototype(recv)) return false;
|
||||
static const char message[] = "Elements on Array.prototype are not supported yet";
|
||||
scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Property names are immutable and often repeated across simultaneously live
|
||||
* objects. Entries own references to their bytes; this fixed weak table owns
|
||||
* none. Collisions only reduce sharing, and the final release removes a weak
|
||||
@@ -8527,6 +8538,7 @@ void scr_dyn_key_set(ScrDyn *recv, ScrStr *key, ScrDyn *value) {
|
||||
else idx = idx * 10 + (size_t)(key->data[i] - '0');
|
||||
}
|
||||
if (is_index && idx < 4294967295ULL) {
|
||||
if (scr_dyn_array_prototype_element_fence(recv)) return;
|
||||
if (recv->v.arr.frozen && idx < recv->v.arr.len) {
|
||||
static const char message[] = "Cannot assign to read only property";
|
||||
scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1);
|
||||
|
||||
@@ -1727,3 +1727,53 @@ console.log(util.inspect(extra));
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("elements on Array.prototype", () => {
|
||||
// Holes of native arrays read undefined without consulting
|
||||
// Array.prototype, so storing an element there refuses instead of
|
||||
// letting later hole reads diverge from Node. Named members stay
|
||||
// writable.
|
||||
test("an index write is a named fence (TS lane)", async () => {
|
||||
const r = await compileAndRun(
|
||||
"array-prototype-element-ts",
|
||||
`const proto = Array.prototype as unknown as Record<string, unknown>;
|
||||
proto.label = "named";
|
||||
console.log(proto.label);
|
||||
(Array.prototype as unknown as Record<number, unknown>)[1] = "proto";
|
||||
console.log("unreachable");
|
||||
`,
|
||||
);
|
||||
expect(r.exitCode).toBe(1);
|
||||
expect(r.stdout).toBe("named\n");
|
||||
expect(r.stderr).toMatch(
|
||||
/^Uncaught Error: Elements on Array\.prototype are not supported yet \[SC2020[^\]]*\]\n$/,
|
||||
);
|
||||
});
|
||||
|
||||
test("an index write and a mutating method are named fences (JS lane)", async () => {
|
||||
const write = await compileAndRun(
|
||||
"array-prototype-element-js",
|
||||
`Array.prototype[0] = "proto";
|
||||
console.log("unreachable");
|
||||
`,
|
||||
"cjs",
|
||||
);
|
||||
expect(write.exitCode).toBe(1);
|
||||
expect(write.stdout).toBe("");
|
||||
expect(write.stderr).toMatch(
|
||||
/^Uncaught Error: Elements on Array\.prototype are not supported yet \[SC2020[^\]]*\]\n$/,
|
||||
);
|
||||
const push = await compileAndRun(
|
||||
"array-prototype-push-js",
|
||||
`Array.prototype.push("proto");
|
||||
console.log("unreachable");
|
||||
`,
|
||||
"cjs",
|
||||
);
|
||||
expect(push.exitCode).toBe(1);
|
||||
expect(push.stdout).toBe("");
|
||||
expect(push.stderr).toMatch(
|
||||
/^Uncaught Error: Elements on Array\.prototype are not supported yet \[SC2020[^\]]*\]\n$/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user