fix: realm 编号加 512 上界断言并降 kernel 重建缺省防符号键碰撞

This commit is contained in:
2026-10-07 02:53:42 +00:00
parent e5d2f8e4f1
commit 9b2ac86dbe
6 changed files with 78 additions and 25 deletions
Generated
+18 -18
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]]
name = "oxide_builtins"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"chrono",
"fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]]
name = "oxide_bytecode"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"num-bigint",
"oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]]
name = "oxide_cfg"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"oxide_bytecode",
"oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]]
name = "oxide_cli"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"ansi_term",
"bumpalo",
@@ -1225,7 +1225,7 @@ dependencies = [
[[package]]
name = "oxide_code_cache"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"lru",
"oxide_bytecode",
@@ -1234,7 +1234,7 @@ dependencies = [
[[package]]
name = "oxide_compiler"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1253,7 +1253,7 @@ dependencies = [
[[package]]
name = "oxide_dce"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1267,7 +1267,7 @@ dependencies = [
[[package]]
name = "oxide_emit"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"num-bigint",
"oxc_allocator",
@@ -1282,7 +1282,7 @@ dependencies = [
[[package]]
name = "oxide_ir"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"oxide_bytecode",
"oxide_log",
@@ -1291,7 +1291,7 @@ dependencies = [
[[package]]
name = "oxide_kernel"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"bumpalo",
"dashmap",
@@ -1306,7 +1306,7 @@ dependencies = [
[[package]]
name = "oxide_liveness"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1318,7 +1318,7 @@ dependencies = [
[[package]]
name = "oxide_log"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"tracing",
"tracing-appender",
@@ -1327,7 +1327,7 @@ dependencies = [
[[package]]
name = "oxide_parser"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"oxc_allocator",
"oxc_ast",
@@ -1342,7 +1342,7 @@ dependencies = [
[[package]]
name = "oxide_regalloc"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1358,7 +1358,7 @@ dependencies = [
[[package]]
name = "oxide_runtime_api"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"num-bigint",
"num-traits",
@@ -1370,7 +1370,7 @@ dependencies = [
[[package]]
name = "oxide_test262"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1387,7 +1387,7 @@ dependencies = [
[[package]]
name = "oxide_types"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"bumpalo",
"hashbrown 0.14.5",
@@ -1399,7 +1399,7 @@ dependencies = [
[[package]]
name = "oxide_vm"
version = "0.8.51"
version = "0.8.52"
dependencies = [
"bumpalo",
"chrono",
+1 -1
View File
@@ -22,7 +22,7 @@ members = [
]
[workspace.package]
version = "0.8.51"
version = "0.8.52"
edition = "2021"
license = "MIT"
rust-version = "1.80"
+11 -4
View File
@@ -32,7 +32,9 @@ pub struct KernelCore {
active_vms: AtomicUsize,
/// realm 编号计数器:进程内单调递增,`alloc_realm_id` 取当前值后自增。
/// 首个 realm 编号为 0(与旧符号编码一致),至多 2^9 = 512 个 realm
/// (属性键符号空间 29 位减局部下标 20 位)。
/// (属性键符号空间 29 位减局部下标 20 位)。宿主须在单 kernel 生命周期
/// 内创建满 512 个 Vm 前重建 kernel(重建即计数器归零);test262 runner
/// 经 kernel_batch 缺省值(不超 512)满足该约束。
realm_counter: AtomicU32,
}
@@ -197,10 +199,15 @@ impl KernelCore {
/// 分配一个 realm 编号:取计数器当前值后自增,进程内单调递增。
///
/// 首个 realm 编号为 0(与旧符号编码一致),供 `Realm` 构造时固化。
/// 编号空间至多 2^9 = 512(属性键符号空间约束),超出后回绕(debug 断言不触发,
/// 实际单进程 realm 数远小于该上界)。
/// 编号空间至多 2^9 = 512(属性键符号空间 29 位减局部下标 20 位):宿主
/// 须在单 kernel 生命周期内创建满 512 个 Vm 前重建 kernel(重建即计数器
/// 归零),否则超界编号编码的符号属性键与 realm 0 碰撞(属性别名、
/// `Symbol.for` 注册表污染)。debug 构建对超界 fail-fast,release 构建
/// 静默回绕(与引擎其余边界守卫同型)。
pub fn alloc_realm_id(&self) -> u32 {
self.realm_counter.fetch_add(1, Ordering::Relaxed)
let id = self.realm_counter.fetch_add(1, Ordering::Relaxed);
debug_assert!(id < 512, "realm 编号超出 512 上界:宿主须在创建满 512 个 Vm 前重建 kernel");
id
}
}
+1 -1
View File
@@ -95,7 +95,7 @@ impl RunConfig {
\x20 OXIDE_TEST262_CHUNK_SIZE tests per child in chunked mode\n\
\x20 OXIDE_TEST262_CHILD_CHUNK marks a spawned child as chunk worker (any value)\n\
\x20 OXIDE_TEST262_ALLOW_FAIL_EXIT child may exit 1 on fail (any value)\n\
\x20 OXIDE_TEST262_KERNEL_BATCH kernel rebuilds every N tests (default 5000, 1000 under --no-skip)\n\
\x20 OXIDE_TEST262_KERNEL_BATCH kernel rebuilds every N tests (default 256, kept under the 512 realm bound)\n\
\x20 OXIDE_TEST262_LOG_LEVEL runner log level (default info)\n\
\x20 OXIDE_SKIP_UNTIL skip test indexes below N (chunking/supervise resume)\n\
\x20 OXIDE_MAX_TESTS run at most N tests after skip point"
+3 -1
View File
@@ -173,11 +173,13 @@ fn run_tests() -> bool {
.and_then(|n| skip_until.checked_add(n))
.map(|n| n.min(total))
.unwrap_or(total);
// 缺省 256:每 kernel 生命周期 realm 计数不超 512 上界(属性键符号空间约束),
// 留一倍余量防重建边界 off-by-one 触发 debug 断言。
let kernel_batch = std::env::var("OXIDE_TEST262_KERNEL_BATCH")
.ok()
.and_then(|s| s.parse::<usize>().ok())
.filter(|&n| n > 0)
.unwrap_or(if config.no_skip { 1000 } else { 5000 });
.unwrap_or(256);
let chunk_size = std::env::var("OXIDE_TEST262_CHUNK_SIZE")
.ok()
.and_then(|s| s.parse::<usize>().ok())
@@ -107,3 +107,47 @@ fn symbol_key_realm_dimensions_distinct() {
// 跨 realm 同名 well-known 符号也产生不同键。
assert_ne!(encode_symbol_key(0, WELL_KNOWN_SYMBOL_ITERATOR), encode_symbol_key(2, WELL_KNOWN_SYMBOL_ITERATOR));
}
#[test]
fn symbol_key_realm_511_in_range() {
// 511 是 512 上界内的最后一个 realm 编号:realm 位落 bit 20 至 28,与基址
// 不重叠,编码落 29 位符号空间内,往返自洽且与相邻 realm 不碰撞。
for idx in [0u32, 14, 15, 16] {
let key = encode_symbol_key(511, idx);
assert!(is_symbol_key(key));
assert_eq!(decode_symbol_key(key), (511, idx));
assert_ne!(key, encode_symbol_key(0, idx));
assert_ne!(key, encode_symbol_key(510, idx));
}
}
#[test]
fn symbol_key_realm_512_collides_with_realm_zero() {
// 512 是第一个出界 realm 编号:realm 位 bit 9 左移 20 位落 bit 29,与
// SYMBOL_KEY_BASE 的 bit 29 重叠,编码结果与 realm 0 逐字节一致(碰撞)。
for idx in [0u32, 14, 15, 16] {
assert_eq!(encode_symbol_key(512, idx), encode_symbol_key(0, idx));
}
}
#[test]
fn symbol_key_realm_1024_out_of_range_still_injective() {
// 1024 出界但 realm 位 bit 10 左移 20 位落 bit 30,与基址不重叠:键仍单射
// (解码自洽回 1024),仅出文档声明的 29 位符号空间,不与 realm 0 碰撞。
for idx in [0u32, 15, 16] {
let key = encode_symbol_key(1024, idx);
assert!(is_symbol_key(key));
assert_ne!(key, encode_symbol_key(0, idx));
assert_eq!(symbol_realm_id_from_key(key), 1024);
assert_eq!(symbol_local_index_from_key(key), idx);
}
}
#[test]
fn symbol_key_realm_2048_collides_with_realm_zero() {
// 2048 是第二个碰撞环:realm 位 bit 11 左移 20 位落 bit 31,与
// SYMBOL_KEY_BASE 的 bit 31 重叠,编码结果与 realm 0 逐字节一致。
for idx in [0u32, 15, 16] {
assert_eq!(encode_symbol_key(2048, idx), encode_symbol_key(0, idx));
}
}