d97d39e8ad
GeneratorState 状态盒此前由 epoch 原对象独占释放,promote 与 sweep 克隆 浅拷贝 native_data 共享同一盒,旧对象 drop 即悬垂。新增 clone 深拷贝 (参照 async_generator),promote/sweep 两处接入,恢复执行读新盒; full_reset 在 session arena 重置前遍历 session 对象释放堆数据, 配合深拷贝形成单所有权。补 sweep/promote/full_reset 三回归与 生成器捕获闭包跨 GC 回归。
37 lines
1.9 KiB
Rust
37 lines
1.9 KiB
Rust
//! 生成器 × session GC 回归:promote 后 full_reset 释放 epoch 原对象与 session 克隆
|
||
//! 的堆数据(各单所有权),不 double-free、不悬垂,VM 继续可用。
|
||
//! sweep 变体与闭包捕获变体见 `vm_support.rs` 内部测试(需 crate 内 `resume_generator`
|
||
//! 在模块表未重建时恢复执行,integration 层无法触达)。
|
||
|
||
use oxide_compiler::compiler::Compiler;
|
||
use oxide_parser::Allocator;
|
||
use oxide_vm::vm::Vm;
|
||
|
||
fn compile(source: &str) -> oxide_bytecode::module::CompiledModule {
|
||
let allocator = Allocator::default();
|
||
let program = oxide_parser::parse(&allocator, source).expect("parse");
|
||
Compiler::new().compile(&program).expect("compile")
|
||
}
|
||
|
||
/// promote + full_reset 变体:global 根持有生成器克隆,full_reset 释放 epoch 原对象
|
||
/// 与 session 克隆的堆数据(各单所有权),不 double-free、不悬垂,VM 继续可用。
|
||
#[test]
|
||
fn generator_promoted_to_global_survives_full_reset_cleanly() {
|
||
let mut vm = Vm::new();
|
||
vm.run(&compile("function* g(){ yield 1; yield 2; } globalThis.it = g(); globalThis.it.next(); 0"))
|
||
.expect("run1");
|
||
assert!(vm.session_object_count() > 0, "生成器挂 global 应被 promote 进 session");
|
||
|
||
// global 含 session 对象即强制重建:旧 global 丢弃、it 槽不存在,全程无悬垂访问
|
||
// (修复前 epoch 原对象释放共享状态盒 → 读已释放内存)。
|
||
vm.full_reset();
|
||
assert_eq!(vm.session_object_count(), 0, "full_reset 应清空 session 对象");
|
||
|
||
let result = vm.run(&compile("typeof it")).expect("run2");
|
||
let text = vm.lookup_str(result).expect("typeof 应返回字符串").to_string();
|
||
assert_eq!(text, "undefined");
|
||
// 新会话可正常创建并推进生成器。
|
||
let ok = vm.run(&compile("function* h(){ yield 9; } var it2 = h(); it2.next().value")).expect("run3");
|
||
assert_eq!(format!("{ok}"), "9");
|
||
}
|