d1961e79fc
Integrate 182 upstream commits throughb2473e60while retaining MoonWell packaging, branding and the community ruRU pack. Upstream replaces the C Lua/mlua host with benilla-lua/benilla-mlua and the native glue screens with stock GlueXML. The update also includes the new locale/DBC/name rules, cache and interaction handling, rendering, quest log and chat behavior, including the latest quest completion and timed-quest failure fixes. Fork adaptations use the new APIs: stock Wow.ini locales remain intact, while the ruRU overlay reads column zero and retains its ruRU authentication tag and Lua identity. Russian names keep their twelve-letter policy and Unicode roster matching; fonts, spell costs, race/class labels and translated options retain real-pack regression coverage. Windows regression fixes keep the locale-default test valid under instrumented window overrides and the shader assertion independent of checkout line endings. The original C Lua 5.1 host, rebuilt fromc0630f3din an isolated directory, reproduces the complete Windows cos-sweep answer byte for byte; cos now uses platform-specific goldens. Validation on Windows: scripts/gates.sh passed all automatic gates, including real-data and no-install workspace tests, reference tables, documentation, message catalog, render-pass lint, player clippy/tests and engine boots with and without data. MoonWell player clippy also passed with -D warnings. The committed tree exactly matches the full green stamp; five vendored Kira files retain the tested checkout's line endings, with normalized contents unchanged. All three actual ruRU pack regressions passed in both builds. Fifteen test archives were restored read-only from the published client and SHA-256 checked. Each real-data/player rung skipped 31 tests because the optional addon corpus is absent (24 general, 7 Quiver). Live smoke was not run: no declared probe account; no player-account login or character creation was performed. Linux/macOS changes were not locally built.
101 lines
3.6 KiB
Rust
101 lines
3.6 KiB
Rust
//! Long and deep source on a 2 MB thread: a left-nested chain of any length compiles and runs,
|
|
//! as 5.1's parser reads it in a loop, and deep nesting stops at the client's level limit with its
|
|
//! message (or, for loops, at its limit on locals). Neither may overflow the Rust stack.
|
|
|
|
fn on_small_stack(f: impl FnOnce() + Send + 'static) {
|
|
std::thread::Builder::new()
|
|
.stack_size(2 << 20)
|
|
.spawn(f)
|
|
.unwrap()
|
|
.join()
|
|
.unwrap();
|
|
}
|
|
|
|
/// The chunk's first result, or its error.
|
|
fn run(src: String) -> String {
|
|
let mut vm = benilla_lua::new_state();
|
|
vm.exec(
|
|
b"function f() return f end m = { m = function(self) return self end }",
|
|
b"=setup",
|
|
)
|
|
.unwrap();
|
|
match vm.exec(src.as_bytes(), b"=t") {
|
|
Ok(v) => v.first().map_or("none".into(), |&v| vm.display(v)),
|
|
Err(e) => vm.display(e),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn left_nested_chains_compile_at_any_length() {
|
|
on_small_stack(|| {
|
|
let cases = [
|
|
(
|
|
format!("local x = f{} return type(x)", "()".repeat(30000)),
|
|
"function",
|
|
),
|
|
(
|
|
format!("local x = 1{} return x", " and 1".repeat(40000)),
|
|
"1",
|
|
),
|
|
(format!("return m{}", ":m()".repeat(20000)), "table"),
|
|
(format!("return 1{}", "+1".repeat(200000)), "200001"),
|
|
(
|
|
format!("return {}false", "false or ".repeat(49999)),
|
|
"false",
|
|
),
|
|
(
|
|
format!("local t = {{}} t.a = t return t{} == t", ".a".repeat(50000)),
|
|
"true",
|
|
),
|
|
(
|
|
format!("local x = 2 return x{}", "*x".repeat(30000)),
|
|
"1.#INF",
|
|
),
|
|
(format!("return 1 == 1{}", " == true".repeat(30000)), "true"),
|
|
];
|
|
for (src, want) in cases {
|
|
assert_eq!(run(src.clone()), want, "{}", &src[..40]);
|
|
}
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn deep_nesting_stops_at_the_level_limit() {
|
|
on_small_stack(|| {
|
|
let n = 100000;
|
|
let cases = [
|
|
format!("return {}1{}", "(".repeat(n), ")".repeat(n)),
|
|
format!("return {}1", "not ".repeat(n)),
|
|
format!("return {}1", "- ".repeat(n)),
|
|
format!("return 1{}", " .. 1".repeat(n)),
|
|
format!("return 2{}", " ^ 2".repeat(n)),
|
|
format!("return {}1{}", "{".repeat(n), "}".repeat(n)),
|
|
format!("return {}1{}", "f(".repeat(n), ")".repeat(n)),
|
|
format!("return {}1{}", "m[".repeat(n), "]".repeat(n)),
|
|
format!("{}{}", "do ".repeat(n), "end ".repeat(n)),
|
|
format!("{}{}", "if x then ".repeat(n), "end ".repeat(n)),
|
|
format!("{}{}", "while x do ".repeat(n), "end ".repeat(n)),
|
|
format!("{}{}", "repeat ".repeat(n), "until x ".repeat(n)),
|
|
format!("{}{}", "for i = 1, 2 do ".repeat(n), "end ".repeat(n)),
|
|
format!("{}{}", "for k in x do ".repeat(n), "end ".repeat(n)),
|
|
format!(
|
|
"return {}1{}",
|
|
"function() return ".repeat(n),
|
|
" end".repeat(n)
|
|
),
|
|
format!("{}{}", "local function g() ".repeat(n), "end ".repeat(n)),
|
|
];
|
|
for src in cases {
|
|
let got = run(src.clone());
|
|
// Four locals a loop reach the 200 before the levels do.
|
|
let locals =
|
|
src.starts_with("for") && got.contains("too many local variables (limit=200)");
|
|
assert!(
|
|
got.contains("too many syntax levels near") || locals,
|
|
"{}: {got}",
|
|
&src[..40]
|
|
);
|
|
}
|
|
});
|
|
}
|