Skip to main content

idakit_sys/
netnode.rs

1//! `MAXSPECSIZE`, the object-size cap shared by netnode value/sup/hash storage (`netnode.hpp`).
2
3/// The maximum byte length of one netnode value, sup, or hash object.
4///
5/// `MAXSPECSIZE` from `netnode.hpp` (IDA 9.3). The facade enforces the SDK constant itself; this
6/// mirrors its value on the Rust side, redundant by design rather than shared codegen.
7pub const MAXSPECSIZE: usize = 1024;
8
9#[cfg(test)]
10mod tests {
11    use assert2::assert;
12
13    use super::MAXSPECSIZE;
14
15    /// Pulls `const int <name> = <value>;` out of SDK header text.
16    fn header_const(text: &str, name: &str) -> Option<usize> {
17        let needle = format!("{name} = ");
18        let start = text.find(&needle)? + needle.len();
19        let end = start + text[start..].find(';')?;
20        text[start..end].trim().parse().ok()
21    }
22
23    // Pins the mirror to the SDK header's own value, so a version bump that changes the cap
24    // fails here instead of silently overreading a stack buffer. Kernel-free; skips when
25    // IDA_SDK_INCLUDE (this crate's own build script output) is unset.
26    #[test]
27    fn maxspecsize_matches_the_sdk_header() {
28        let Some(dir) = option_env!("IDA_SDK_INCLUDE") else {
29            eprintln!(
30                "skipping: IDA_SDK_INCLUDE unset (no SDK headers to check MAXSPECSIZE against)"
31            );
32            return;
33        };
34        let header = std::path::Path::new(dir).join("netnode.hpp");
35        let text = std::fs::read_to_string(&header)
36            .unwrap_or_else(|e| panic!("read {}: {e}", header.display()));
37        let value = header_const(&text, "MAXSPECSIZE")
38            .unwrap_or_else(|| panic!("MAXSPECSIZE declaration not found in {}", header.display()));
39        assert!(value == MAXSPECSIZE);
40    }
41}