jdx/mise · error · eyre::Report

malformed load command in {}

Error message

malformed load command in {}

What it means

A single load command in a 64-bit Mach-O declared a cmdsize smaller than the mandatory 8-byte command header, or large enough to run past the end of the load-command table. Since the parser steps through commands by cmdsize, an invalid size would desynchronize the whole table, so it bails.

Source

Thrown at src/system/packages/brew/macho.rs:90

    let sizeofcmds = u32_at(slice, 20) as usize;
    if HEADER_SIZE_64 + sizeofcmds > slice.len() {
        bail!("malformed Mach-O in {}", path.display());
    }

    // upper bound for growing the load-command table: the first byte of
    // section data (everything between sizeofcmds and there is padding)
    let lc_end = HEADER_SIZE_64 + sizeofcmds;
    let mut first_data = slice.len();
    {
        let mut off = HEADER_SIZE_64;
        for _ in 0..ncmds {
            if off + 8 > lc_end {
                bail!("malformed load command table in {}", path.display());
            }
            let cmd = u32_at(slice, off);
            let cmdsize = u32_at(slice, off + 4) as usize;
            if cmdsize < 8 || off + cmdsize > lc_end {
                bail!("malformed load command in {}", path.display());
            }
            if cmd == LC_SEGMENT_64 {
                let nsects = u32_at(slice, off + 64) as usize;
                for i in 0..nsects {
                    // struct section_64 is 80 bytes; offset field at +48
                    let sect = off + 72 + i * 80;
                    if sect + 80 > off + cmdsize {
                        break;
                    }
                    let file_off = u32_at(slice, sect + 48) as usize;
                    if file_off > 0 {
                        first_data = first_data.min(file_off);
                    }
                }
            }
            off += cmdsize;
        }
    }

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Clear the bottle cache and re-pour from a fresh download
  2. Validate with otool -l <file>; malformed size fields will fail there too if the file is truly corrupt
  3. Report the specific binary upstream if it is reproducibly patchable by ruby-macho/otool
Defensive patterns

Strategy: validation

Validate before calling

// Check each command's size is at least 8 and stays inside the table.
fn command_sizes_ok(slice: &[u8]) -> bool {
    let lc_end = 32 + u32_at(slice, 20) as usize;
    let mut off = 32;
    for _ in 0..u32_at(slice, 16) as usize {
        if off + 8 > lc_end { return false; }
        let cmdsize = u32_at(slice, off + 4) as usize;
        if cmdsize < 8 || off + cmdsize > lc_end { return false; }
        off += cmdsize;
    }
    true
}

Type guard

fn macho_commands_wellformed(slice: &[u8]) -> bool {
    macho_header_ok(slice) && command_sizes_ok(slice)
}

Try / catch

match patch_macho(&mut content, &replacements, &path) {
    Ok(_) => {}
    Err(e) => warn!("{}: malformed Mach-O, left unpatched: {e:#}", path.display()),
}

Prevention

When it happens

Trigger: patch_slice first scan loop: cmdsize < 8 || off + cmdsize > lc_end for some command. Happens with corrupted or malformed binaries where a command's size field is zero/garbage, or where sizeofcmds under-reports the table extent.

Common situations: Truncated or bit-flipped bottle artifacts; Mach-O files processed by broken tooling; fuzzing corpora.

Understand the failure class

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/f61b50ccda0572a7. Report an issue: GitHub.