diff --git a/crates/oxide_vm/src/promise/aggregate.rs b/crates/oxide_vm/src/promise/aggregate.rs index 09d66541..92ce6846 100644 --- a/crates/oxide_vm/src/promise/aggregate.rs +++ b/crates/oxide_vm/src/promise/aggregate.rs @@ -24,6 +24,7 @@ impl Vm { fn make_agg_record(&mut self, values: JsValue, resolve: JsValue, reject: JsValue) -> JsValue { let proto_val = JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject); let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val)); + // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;本次 native 调用内不搬移,借出期间无别名。 let obj = unsafe { &mut *ptr }; let rem_si = self.kernel_core.perm_interner().intern(AGG_REMAINING_PROP).0; self.set_or_create_prop_value(obj, rem_si, JsValue::int(1)); @@ -47,6 +48,7 @@ impl Vm { func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(native_fn as *const ()) })); func.set_native_arg_count(1); let ptr = self.alloc_object(func); + // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;后续 add_fn_name_length 的 shape/属性分配不改对象地址,借出期间无别名。 let obj = unsafe { &mut *ptr }; self.add_fn_name_length(obj, "", 1); let sh = self.kernel_core.shape_forge().as_ref(); @@ -73,6 +75,7 @@ impl Vm { fn make_settled_record(&mut self, status: &str, value_field: &str, value: JsValue) -> JsValue { let proto_val = JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject); let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val)); + // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;写 status/value 属性(含 new_string 分配)期间不搬移,借出期间无别名。 let obj = unsafe { &mut *ptr }; let status_si = self.kernel_core.perm_interner().intern("status").0; let status_val = self.new_string(status); @@ -87,6 +90,7 @@ impl Vm { fn make_aggregate_error(&mut self, errors: JsValue, message: JsValue) -> JsValue { let proto_val = JsValue::from_js_object(self.aggregate_error_proto.as_ptr() as *mut JsObject); let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val)); + // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;写 message/errors 数据属性期间不搬移,借出期间无别名。 let obj = unsafe { &mut *ptr }; // message/errors 为数据属性:writable、非枚举、configurable(CreateMethodProperty)。 let attrs = PropAttributes::new(true, false, true); @@ -173,14 +177,17 @@ impl Vm { // 固定地址后互相接线:proto.constructor ↔ ctor.prototype。 Self::swap_intrinsic_proto(&mut self.aggregate_error_proto, *proto); Self::swap_intrinsic_proto(&mut self.aggregate_error_constructor, *ctor); + // SAFETY: aggregate_error_proto 为堆址固定的 P(Arc 透明包装),本行前刚经 swap_intrinsic_proto 落地;与 ctor_mut 分属不同对象,无别名。 let proto_mut = unsafe { &mut *self.aggregate_error_proto.as_mut_ptr() }; proto_mut .set_prop_at(0u32, JsValue::from_js_object(self.aggregate_error_constructor.as_ptr() as *mut JsObject)); + // SAFETY: aggregate_error_constructor 同为堆址固定的 P(Arc 透明包装);此处写 prototype 槽位(下标 2),与 proto_mut 分属不同对象,无别名。 let ctor_mut = unsafe { &mut *self.aggregate_error_constructor.as_mut_ptr() }; ctor_mut.set_prop_at(2u32, JsValue::from_js_object(self.aggregate_error_proto.as_ptr() as *mut JsObject)); // 绑定 global(槽已存在则更新)。 let global_ptr = self.session.global_object().as_ptr() as *mut JsObject; + // SAFETY: global 对象由 session 持有,存活整个 session;本函数内只改其 shape/属性区,期间无 reset 或对象搬移。 let global = unsafe { &mut *global_ptr }; let si = self.kernel_core.perm_interner().intern("AggregateError").0; let ctor_val = JsValue::from_js_object(self.aggregate_error_constructor.as_ptr() as *mut JsObject); @@ -202,6 +209,7 @@ pub(super) fn promise_static_resolve(vm: &mut Vm, args: &[u8]) -> NativeResult { let ctor = vm.reg(if args.is_empty() { 0 } else { args[0] }); let x = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; if vm.is_promise_value(x) { + // SAFETY: is_promise_value 已验证 x 为原生 Promise 对象,指针非空且存活;此处只读 constructor,即时消费。 let x_obj = unsafe { &*x.as_js_object_ptr() }; let ctor_si = vm.kernel_core.perm_interner().intern("constructor").0; let x_ctor = match vm.ordinary_get(x_obj, ctor_si, x) { @@ -273,6 +281,7 @@ pub(super) fn promise_static_with_resolvers(vm: &mut Vm, args: &[u8]) -> NativeR }; let object_proto = JsValue::from_js_object(vm.session.builtin_world().object_proto.as_ptr() as *mut JsObject); let ptr = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, object_proto)); + // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;写 promise/resolve/reject 属性期间不搬移,借出期间无别名。 let obj = unsafe { &mut *ptr }; let sf = vm.kernel_core.perm_interner().as_ref(); let sh = vm.kernel_core.shape_forge().as_ref(); @@ -707,6 +716,7 @@ fn aggregate_error_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult { Err(err) => return NativeResult::Err(err), }; let err_si = vm.kernel_core.perm_interner().intern("errors").0; + // SAFETY: this 为本次构造得到的既有或新建存活对象;此处写 errors 数据属性,与上方 message 写入顺序独占同一对象,无别名。 let _ = vm.define_data_property(unsafe { &mut *this }, err_si, errors_list, PropAttributes::new(true, false, true)); NativeResult::Ok(JsValue::from_js_object(this)) } diff --git a/crates/oxide_vm/src/promise/reactions.rs b/crates/oxide_vm/src/promise/reactions.rs index a066fdfb..5ad48881 100644 --- a/crates/oxide_vm/src/promise/reactions.rs +++ b/crates/oxide_vm/src/promise/reactions.rs @@ -54,11 +54,13 @@ impl Vm { let (new_promise, resolve, reject) = capability; let state_ptr = self.promise_state_ptr(this_val); let (kind, result) = { + // SAFETY: this_val 已过 is_promise_value 校验,state_ptr 取自 promise_state_ptr;状态盒非空且随对象存活,本块唯一可变借用,读完 state/result 即结束。 let state = unsafe { &mut *state_ptr }; (state.state, state.result) }; match kind { PromiseStateKind::Pending => { + // SAFETY: 同一 state_ptr,前一可变借用已结束;状态盒非空且随 this_val 存活,此处仅向 reactions 追加两条反应,无别名。 let state = unsafe { &mut *state_ptr }; state.reactions.push(PromiseReaction { promise: new_promise, @@ -126,6 +128,7 @@ impl Vm { /// undefined 会错误退回内置;`@@species` 改写支持待补 /// `Promise[Symbol.species]` getter 时一并落地。 fn species_constructor(&mut self, promise: JsValue) -> Result { + // SAFETY: 调用方已按函数文档前提做 is_promise_value 校验,指针非空且指向存活 Promise 对象;此处只读 constructor。 let obj = unsafe { &*promise.as_js_object_ptr() }; let ctor_si = self.kernel_core.perm_interner().intern("constructor").0; let ctor = match self.ordinary_get(obj, ctor_si, promise) { @@ -211,6 +214,7 @@ impl Vm { Err(e) => return Err(oxide_builtins::error::create_type_error(self, &e)), } }; + // SAFETY: get_receiver 两分支均为对象(is_object 原值或 to_object 返回对象),指针非空且存活;此处只读 then 属性。 let receiver_obj = unsafe { &*get_receiver.as_js_object_ptr() }; let then = match self.ordinary_get(receiver_obj, then_si, this_val) { Ok(v) => v, @@ -244,6 +248,7 @@ impl Vm { func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(promise_finally_handler as *const ()) })); func.set_native_arg_count(0); let ptr = self.alloc_object(func); + // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;本次 native 调用内不搬移,借出期间无别名。 let obj = unsafe { &mut *ptr }; let of_si = self.kernel_core.perm_interner().intern(ON_FINALLY_PROP).0; self.set_or_create_prop_value(obj, of_si, on_finally); @@ -278,6 +283,7 @@ fn promise_finally_handler(vm: &mut Vm, args: &[u8]) -> NativeResult { if !callee.is_object() { return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "finally handler is invalid")); } + // SAFETY: callee 来自 reg(254) 且 is_object 守卫保证指针非空存活;此处只读 ON_FINALLY/FINALLY_REJECT 属性。 let callee_obj = unsafe { &*callee.as_js_object_ptr() }; let of_si = vm.kernel_core.perm_interner().intern(ON_FINALLY_PROP).0; let on_finally = vm.resolve_property(callee_obj, of_si).unwrap_or(JsValue::undefined());