makepad/platform/script/tests/allocation_limit.rs
Admin 2a46d2a405 Land platform, studio, and widget infra from rik2.
HTTP progress, OS file drag, RunView controllers, DropDown2, video,
remote process helpers, and the Studio runbook.
2026-08-18 14:23:57 +02:00

100 lines
2.9 KiB
Rust

use makepad_script::*;
fn test_vm() -> ScriptVm<'static> {
let host = Box::leak(Box::new(0i32));
let std = Box::leak(Box::new(0i32));
ScriptVm {
host,
std,
bx: Box::new(ScriptVmBase::new()),
}
}
fn script(name: &str, code: &str) -> ScriptMod {
ScriptMod {
cargo_manifest_path: String::new(),
module_path: String::new(),
file: format!("allocation_limit_{name}"),
line: 0,
column: 0,
code: code.to_string(),
values: vec![],
}
}
fn eval_limited(name: &str, code: &str, limit: usize) -> (ScriptAllocationReport, Vec<String>) {
let vm = &mut test_vm();
vm.bx.captured_errors = Some(Vec::new());
let (_, report) = vm.with_heap_allocation_limit(limit, |vm| vm.eval(script(name, code)));
(report, vm.take_errors())
}
#[test]
fn sparse_array_index_is_refused_before_resize() {
let (report, errors) = eval_limited(
"sparse_array",
"fn run(){ let values = [] values[1000000000] = 1 42 }\nrun()",
64 * 1024,
);
assert!(report.exceeded, "report={report:?}, errors={errors:#?}");
assert!(
errors
.iter()
.any(|error| error.contains("script allocation limit exceeded")),
"{errors:#?}"
);
}
#[test]
fn sparse_object_index_is_refused_before_resize() {
let (report, errors) = eval_limited(
"sparse_object",
"fn run(){ let values = {} values[1000000000] = 1 42 }\nrun()",
64 * 1024,
);
assert!(report.exceeded, "report={report:?}, errors={errors:#?}");
assert!(errors.iter().any(|error| error.contains("sparse object index")));
}
#[test]
fn repeated_concat_stops_at_the_cumulative_string_budget() {
let mut code = "let text = \"abcdefgh\"\n".to_string();
for _ in 0..20 {
code.push_str("text = text + text\n");
}
code.push_str("text");
let (report, errors) = eval_limited("concat", &code, 32 * 1024);
assert!(report.exceeded);
assert!(errors.iter().any(|error| error.contains("concatenating strings")));
}
#[test]
fn raw_string_builder_fails_closed_only_while_budgeted() {
let vm = &mut test_vm();
vm.bx.captured_errors = Some(Vec::new());
let mut called = false;
let (_, report) = vm.with_heap_allocation_limit(1024, |vm| {
let _ = vm.bx.heap.new_string_with(|_, out| {
called = true;
out.push_str("unbounded");
});
});
let errors = vm.take_errors();
assert!(!called, "sandboxed raw builder ran before it was preflighted");
assert!(report.exceeded);
assert!(errors.iter().any(|error| error.contains("without an allocation preflight")));
let value = vm
.bx
.heap
.new_string_with(|_, out| out.push_str("trusted builder unchanged"));
let text = vm
.bx
.heap
.string_with(value, |_, value| value.to_owned());
assert_eq!(text.as_deref(), Some("trusted builder unchanged"));
}