fix: transfer 上限界校验限定保持性原样臂与 DataView detach 守卫先于越界

This commit is contained in:
2026-09-23 00:22:35 +00:00
parent f063dadccb
commit bb92f17deb
2 changed files with 26 additions and 11 deletions
+6 -4
View File
@@ -456,8 +456,9 @@ enum TransferKeep {
/// 先于一切守卫观测)。
/// 3. 重取源载荷指针(求值可已晋升/detach/改 immutable),重检状态位:
/// detached → TypeError;immutable → TypeError。
/// 4. 界校验:resizable 源且 newByteLength > 真实上限(重读存储态 − 1)→
/// RangeError;newByteLength > 引擎分配上界 → RangeError。
/// 4. 界校验:仅保持性原样臂——resizable 源且 newByteLength > 真实上限
/// (重读存储态 − 1)→ RangeError;newByteLength > 引擎分配上界 →
/// RangeError(全保持性)。
/// 5. 物化拷贝(载荷指针新鲜,字节借出止于本步)。
/// 6. 新建缓冲(proto 取 %ArrayBuffer.prototype%,保持性按 keep),字节
/// 序列零填充至 newByteLength。
@@ -491,8 +492,9 @@ fn array_buffer_copy_and_detach<H: VmHost>(
if immutable {
return NativeResult::Err(crate::error::create_type_error(vm, "ArrayBuffer is immutable"));
}
// 存储态上限 +1 编码:真实上限 = 存储态 − 1(上限 0 的缓冲只许同长)。
if stored_max != 0 && new_len > stored_max - 1 {
// 保持性原样臂:resizable 源的真实上限(存储态 − 1)须容纳新长度
// (ttf/tti 定长分配无上限约束)。
if matches!(keep, TransferKeep::Preserve) && stored_max != 0 && new_len > stored_max - 1 {
return NativeResult::Err(crate::error::create_range_error(vm, "invalid ArrayBuffer length"));
}
if new_len > MAX_ARRAY_BUFFER_LENGTH {
+20 -7
View File
@@ -119,13 +119,15 @@ fn checked_absolute_offset<H: VmHost>(
}
/// GetViewValue 后半:按已校验的视图与偏移读 N 字节(越界抛 RangeError)。
/// detach 守卫先于范围校验(规范序:IsDetachedBuffer 检查先于越界判定,
/// detach 后越界偏移也抛 TypeError 而非 RangeError)。
fn read_bytes_at<const N: usize, H: VmHost>(vm: &mut H, view: DataViewData, offset: usize) -> Result<[u8; N], JsValue> {
let abs = checked_absolute_offset(vm, view, offset, N)?;
let payload_ptr = array_buffer_payload(vm, view.buffer)?;
// SAFETY: payload_ptr 经 array_buffer_payload 校验为合法 ArrayBuffer 载荷。
let Some(buffer) = unsafe { &*payload_ptr }.data.as_deref() else {
return Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
};
let abs = checked_absolute_offset(vm, view, offset, N)?;
if abs + N > buffer.len() {
return Err(crate::error::create_range_error(vm, "DataView offset out of bounds"));
}
@@ -135,15 +137,16 @@ fn read_bytes_at<const N: usize, H: VmHost>(vm: &mut H, view: DataViewData, offs
}
/// SetViewValue 后半:按已校验的视图与偏移写 N 字节(越界抛 RangeError)。
/// detach 守卫先于范围校验(规范序同读路径)。
fn write_bytes<const N: usize, H: VmHost>(
vm: &mut H, view: DataViewData, offset: usize, bytes: [u8; N],
) -> Result<(), JsValue> {
let abs = checked_absolute_offset(vm, view, offset, N)?;
let payload_ptr = array_buffer_payload(vm, view.buffer)?;
// SAFETY: payload_ptr 经 array_buffer_payload 校验为合法 ArrayBuffer 载荷。
let Some(buffer) = unsafe { &mut *payload_ptr }.data.as_deref_mut() else {
return Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
};
let abs = checked_absolute_offset(vm, view, offset, N)?;
if abs + N > buffer.len() {
return Err(crate::error::create_range_error(vm, "DataView offset out of bounds"));
}
@@ -181,7 +184,8 @@ fn has_data_view_proto<H: VmHost>(vm: &mut H, this_val: JsValue) -> bool {
/// 1. receiver 原型链不含 %DataView.prototype% → TypeError(普通调用面:
/// this = globalThis 不满足;构造路径恒传 DataView 原型链上的 receiver)。
/// 2. buffer 品牌校验(ArrayBufferData)。
/// 3. offset = ToIndex(byteOffset) 传播式;offset > bufferLen → RangeError。
/// 3. offset = ToIndex(byteOffset) 传播式;detached 缓冲 → TypeError(在
/// 偏移强转之后);offset > bufferLen → RangeError。
/// 4. byteLength 缺省/undefined → bufferLen - offset,否则 ToIndex 传播式;
/// offset + byteLength > bufferLen → RangeError。
/// 5. GetPrototypeFromConstructor:经 `ordinary_get` 读 NewTarget(regs[255])
@@ -203,15 +207,18 @@ pub fn data_view_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
let buffer = vm.reg(args[1]);
let payload_ptr = native_try!(array_buffer_payload(vm, buffer));
// SAFETY: payload_ptr 经 array_buffer_payload 校验为合法 ArrayBuffer 载荷。
let Some(data) = unsafe { &*payload_ptr }.data.as_ref() else {
return NativeResult::Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
};
let buffer_len = data.len();
let buf = unsafe { &*payload_ptr }.data.as_deref();
let buffer_len = buf.map_or(0, |d| d.len());
let byte_offset = if args.len() > 2 {
native_try!(to_index(vm, vm.reg(args[2]), "DataView byteOffset out of bounds"))
} else {
0
};
// detach 守卫在偏移强转之后、越界判定之前(规范序:detached 缓冲构造
// 抛 TypeError,且偏移的 ToNumber 已恰好发生一次)。
if buf.is_none() {
return NativeResult::Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
}
if byte_offset > buffer_len {
return NativeResult::Err(crate::error::create_range_error(vm, "DataView byteOffset out of bounds"));
}
@@ -686,8 +693,14 @@ pub fn data_view_byte_offset_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> Nativ
}
/// `DataView.prototype.byteLength` getter:返回视图覆盖的字节长度。
/// 缓冲已 detach → TypeError(规范序:IsDetachedBuffer 检查先于返回值)。
pub fn data_view_byte_length_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
let view = native_try!(get_data_view_data(vm, this_val));
let payload_ptr = native_try!(array_buffer_payload(vm, view.buffer));
// SAFETY: payload_ptr 经 array_buffer_payload 校验为合法 ArrayBuffer 载荷。
if unsafe { &*payload_ptr }.data.is_none() {
return NativeResult::Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
}
NativeResult::Ok(JsValue::float(view.byte_length as f64))
}