8000 Display panics on a tree nested 16,384 levels deep · Issue #103 · google/dtoolkit · GitHub
[go: up one dir, main page]

Skip to content

Display panics on a tree nested 16,384 levels deep #103

Open

Description

@calef

Found while comparing dtoolkit against another device tree parser.

Version: dtoolkit 0.4.1.

What happens. Formatting an Fdt with Display panics with "Formatting argument out of range" (src/fdt/node.rs, line 98) on a tree nested 16,384 levels below the root. The node printer indents with {:indent$} at four columns per level, and the width passes u16::MAX. The blob is about 196 KiB and Fdt::new accepts it; 16,383 levels print.

Expected. Display returns the text, or an error, without panicking on a tree that Fdt::new accepted.

Reproduction.

/// Builds a version-17 FDT blob from a structure block and a strings block.
pub fn blob(structure: &[u8], strings: &[u8]) -> Vec<u8> {
    let off_struct = 40 + 16; // header, then one empty reservation entry
    let off_strings = off_struct + structure.len();
    let total = off_strings + strings.len();
    let mut b = Vec::new();
    for v in [0xd00dfeed, total, off_struct, off_strings, 40, 17, 16, 0, strings.len(), structure.len()] {
        b.extend_from_slice(&(v as u32).to_be_bytes());
    }
    b.extend_from_slice(&[0; 16]);
    b.extend_from_slice(structure);
    b.extend_from_slice(strings);
    b
}

pub fn token(s: &mut Vec<u8>, t: u32) {
    s.extend_from_slice(&t.to_be_bytes());
}

/// FDT_BEGIN_NODE with a padded name.
pub fn begin(s: &mut Vec<u8>, name: &str) {
    token(s, 1);
    s.extend_from_slice(name.as_bytes());
    s.push(0);
    while s.len() % 4 != 0 {
        s.push(0);
    }
}
use dtoolkit::fdt::Fdt;
use repro::*;

fn main() {
    let depth = 16_384;
    let mut s = Vec::new();
    begin(&mut s, "");
    for _ in 0..depth {
        begin(&mut s, "a");
    }
    for _ in 0..=depth {
        token(&mut s, 2);
    }
    token(&mut s, 9);
    let b = blob(&s, &[]);
    // Run on a large stack so the recursion itself is not what fails.
    let out = std::thread::Builder::new()
        .stack_size(1 << 30)
        .spawn(move || {
            let fdt = Fdt::new(&b).unwrap();
            format!("{fdt}").len()
        })
        .unwrap()
        .join();
    println!("{depth} levels: {:?}", out.map_err(|_| "panicked"));
}

Output:

thread '<unnamed>' panicked at .../dtoolkit-0.4.1/src/fdt/node.rs:98:13:
Formatting argument out of range
16384 levels: Err("panicked")

Suggestion. Cap the indentation, or write it in a loop. The recursion has no bound either, so on a smaller stack it would overflow first; an iterative printer would avoid both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      0