Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d44605301 | ||
|
|
00a914d7dd |
4 changed files with 145 additions and 13 deletions
73
Cargo.lock
generated
73
Cargo.lock
generated
|
|
@ -17,6 +17,15 @@ version = "1.0.104"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
|
||||
|
||||
[[package]]
|
||||
name = "ar_archive_writer"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73cd58deff2140a0a8eae87e417bd01db68a33e148aa93d1e8cd837e55e312b6"
|
||||
dependencies = [
|
||||
"object",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.1"
|
||||
|
|
@ -67,8 +76,8 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
|||
|
||||
[[package]]
|
||||
name = "cultcache-rs"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/GameCult/CultLib.git?rev=b3bd8dd5e5b208b2012392e9c5d6dfee2441aaa7#b3bd8dd5e5b208b2012392e9c5d6dfee2441aaa7"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/GameCult/CultLib.git?rev=bbb98eaf660e43ef611dc2f5132df99fe21e2f01#bbb98eaf660e43ef611dc2f5132df99fe21e2f01"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
|
|
@ -79,14 +88,16 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_bytes",
|
||||
"serde_json",
|
||||
"serde_stacker",
|
||||
"stacker",
|
||||
"uuid",
|
||||
"windows-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cultcache-rs-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/GameCult/CultLib.git?rev=b3bd8dd5e5b208b2012392e9c5d6dfee2441aaa7#b3bd8dd5e5b208b2012392e9c5d6dfee2441aaa7"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/GameCult/CultLib.git?rev=bbb98eaf660e43ef611dc2f5132df99fe21e2f01#bbb98eaf660e43ef611dc2f5132df99fe21e2f01"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -212,6 +223,15 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.39.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
|
|
@ -233,6 +253,16 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psm"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dcd034599e63b970727f70d79e02d62390a4a84f7c6b827c27c46d5ac3fa622"
|
||||
dependencies = [
|
||||
"ar_archive_writer",
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.47"
|
||||
|
|
@ -335,6 +365,17 @@ dependencies = [
|
|||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_stacker"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4936375d50c4be7eff22293a9344f8e46f323ed2b3c243e52f89138d9bb0f4a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_core",
|
||||
"stacker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
|
|
@ -347,6 +388,19 @@ version = "0.4.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
||||
|
||||
[[package]]
|
||||
name = "stacker"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "707f49d46706bacf8a2b00d51dace3f9de527c13eec3778f570c411f89e69967"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"psm",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.119"
|
||||
|
|
@ -532,6 +586,15 @@ dependencies = [
|
|||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@ resolver = "2"
|
|||
|
||||
[workspace.dependencies]
|
||||
anyhow = "1"
|
||||
cultcache-rs = { git = "https://github.com/GameCult/CultLib.git", rev = "b3bd8dd5e5b208b2012392e9c5d6dfee2441aaa7", package = "cultcache-rs" }
|
||||
cultcache-rs = { git = "https://github.com/GameCult/CultLib.git", rev = "bbb98eaf660e43ef611dc2f5132df99fe21e2f01", package = "cultcache-rs" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
rmp-serde = "1.3"
|
||||
|
|
|
|||
76
crates/thing-contract/tests/decode_stack.rs
Normal file
76
crates/thing-contract/tests/decode_stack.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
//! A surface payload inside CultCache's 256 nesting bound must decode on a small thread without
|
||||
//! aborting the process. Soul's finding `thing2:finding:cut-contract-rs.s1.decode-stack-overflow-
|
||||
//! within-bound` found a 2.8 KB Repeat chain aborting a 1 MiB thread in release at 68 levels and a
|
||||
//! Box chain aborting a 2 MiB debug thread at 24 levels, while the bound admits 125 and 83. A
|
||||
//! stack overflow kills the whole test binary, so these tests fail loudly on a decoder that
|
||||
//! does not grow its stack.
|
||||
|
||||
mod common;
|
||||
|
||||
use common::*;
|
||||
use cultcache_rs::decode_payload;
|
||||
use thing_contract::*;
|
||||
|
||||
const REPEAT_LEVELS: usize = 125;
|
||||
const BOX_LEVELS: usize = 83;
|
||||
|
||||
fn surface(root: Node) -> SurfaceDocument {
|
||||
SurfaceDocument {
|
||||
provider_id: ProviderId::new("provider.a"),
|
||||
label: seg("deep"),
|
||||
version: ver(1),
|
||||
title: "deep".into(),
|
||||
root,
|
||||
commands: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn repeat_chain(levels: usize) -> SurfaceDocument {
|
||||
let mut chain = text("leaf", "bottom");
|
||||
for depth in (0..levels).rev() {
|
||||
chain = Node::Repeat(RepeatNode {
|
||||
common: common(&format!("rep-{depth}")),
|
||||
collection: CollectionSource::Param(param("rows")),
|
||||
key_member: path(&["id"]),
|
||||
template: std::boxed::Box::new(chain),
|
||||
});
|
||||
}
|
||||
surface(chain)
|
||||
}
|
||||
|
||||
fn box_chain(levels: usize) -> SurfaceDocument {
|
||||
let mut chain = text("leaf", "bottom");
|
||||
for depth in (0..levels).rev() {
|
||||
chain = boxed(&format!("box-{depth}"), vec![chain]);
|
||||
}
|
||||
surface(chain)
|
||||
}
|
||||
|
||||
/// Builds, encodes and drops the value on a roomy thread, so only the decode runs on `stack`.
|
||||
fn decode_on_small_thread(build: fn() -> SurfaceDocument, stack: usize) {
|
||||
let expected = std::thread::Builder::new().stack_size(64 << 20).spawn(build).unwrap().join().unwrap();
|
||||
let payload = std::thread::Builder::new()
|
||||
.stack_size(64 << 20)
|
||||
.spawn(move || (rmp_serde::to_vec(&expected).unwrap(), expected))
|
||||
.unwrap()
|
||||
.join()
|
||||
.unwrap();
|
||||
let (bytes, expected) = payload;
|
||||
let decoded = std::thread::Builder::new()
|
||||
.stack_size(stack)
|
||||
.spawn(move || decode_payload::<SurfaceDocument>(&bytes).unwrap())
|
||||
.unwrap()
|
||||
.join()
|
||||
.unwrap();
|
||||
std::thread::Builder::new().stack_size(64 << 20).spawn(move || assert!(decoded == expected)).unwrap().join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repeat_chain_at_the_bound_decodes_on_a_1_mib_thread() {
|
||||
decode_on_small_thread(|| repeat_chain(REPEAT_LEVELS), 1 << 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn box_chain_at_the_bound_decodes_on_a_2_mib_thread() {
|
||||
decode_on_small_thread(|| box_chain(BOX_LEVELS), 2 << 20);
|
||||
}
|
||||
|
|
@ -665,13 +665,6 @@ fn refusal_cases() {
|
|||
|
||||
#[test]
|
||||
fn deep_tree() {
|
||||
// Decoding a Node costs tens of KiB of debug stack per nesting level, so the chain runs on a
|
||||
// thread that has the room; the 2 MiB default does not. The hazard is CultCache's, owned by
|
||||
// cultlib-gaps:follow_up:decode-stack-safety; the test stays on the big thread until it lands.
|
||||
std::thread::Builder::new().stack_size(16 * 1024 * 1024).spawn(deep_tree_body).unwrap().join().unwrap();
|
||||
}
|
||||
|
||||
fn deep_tree_body() {
|
||||
// A 64-deep Box chain.
|
||||
let mut chain = text("leaf", "bottom");
|
||||
for depth in (0..64).rev() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue