{"record":{"id":"e12ab172df56e6c3","repo":"jdx/mise","slug":"malformed-mach-o-in","errorCode":null,"errorMessage":"malformed Mach-O in {}","messagePattern":"malformed Mach-O in (.+?)","errorType":"exception","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/macho.rs","lineNumber":74,"sourceCode":"            .position(|w| w == r.placeholder)\n        {\n            out.splice(pos..pos + r.placeholder.len(), r.value.iter().cloned());\n        }\n    }\n    out\n}\n\n/// Patch one 64-bit LE Mach-O slice in place. Returns whether it changed.\nfn patch_slice(slice: &mut [u8], replacements: &[Replacement], path: &Path) -> Result<bool> {\n    if slice.len() < HEADER_SIZE_64 || u32_at(slice, 0) != MH_MAGIC_64_LE {\n        // not a 64-bit LE Mach-O (32-bit or big-endian) — nothing modern on\n        // arm64 macOS; leave it to the caller's generic byte-level pass\n        return Ok(false);\n    }\n    let ncmds = u32_at(slice, 16) as usize;\n    let sizeofcmds = u32_at(slice, 20) as usize;\n    if HEADER_SIZE_64 + sizeofcmds > slice.len() {\n        bail!(\"malformed Mach-O in {}\", path.display());\n    }\n\n    // upper bound for growing the load-command table: the first byte of\n    // section data (everything between sizeofcmds and there is padding)\n    let lc_end = HEADER_SIZE_64 + sizeofcmds;\n    let mut first_data = slice.len();\n    {\n        let mut off = HEADER_SIZE_64;\n        for _ in 0..ncmds {\n            if off + 8 > lc_end {\n                bail!(\"malformed load command table in {}\", path.display());\n            }\n            let cmd = u32_at(slice, off);\n            let cmdsize = u32_at(slice, off + 4) as usize;\n            if cmdsize < 8 || off + cmdsize > lc_end {\n                bail!(\"malformed load command in {}\", path.display());\n            }\n            if cmd == LC_SEGMENT_64 {","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/packages/brew/macho.rs#L56-L92","documentation":"The Mach-O relocation pass found a 64-bit LE header whose sizeofcmds field declares a load-command table larger than the file slice itself. The file is truncated or corrupt, and patching is refused before any offsets are trusted.","triggerScenarios":"patch_slice (via patch_macho on a bottle artifact): slice.len() >= 32 and magic 0xfeedfacf, but HEADER_SIZE_64 + sizeofcmds > slice.len(). Typical for a half-downloaded bottle, a fat-binary slice clipped by truncation, or a non-Mach-O file that happens to start with the magic.","commonSituations":"Interrupted bottle download leaving truncated binaries; corrupted cache; slicing bugs in fat-binary handling of unusual files.","solutions":["Delete the cached bottle and re-pour, verifying checksums","Run otool -hv / file on the artifact — tools that agree it is malformed confirm corruption rather than a parser bug","If standard tools parse it fine, report the file upstream with its header bytes"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Header sanity gate before Mach-O patching.\nfn macho_header_ok(slice: &[u8]) -> bool {\n    slice.len() >= 32\n        && u32::from_le_bytes(slice[0..4].try_into().unwrap()) == 0xfeedfacf\n        && 32 + u32::from_le_bytes(slice[20..24].try_into().unwrap()) as usize <= slice.len()\n}","typeGuard":"fn is_patchable_macho64(slice: &[u8]) -> bool {\n    slice.len() >= 32\n        && u32::from_le_bytes(slice[0..4].try_into().unwrap()) == 0xfeedfacf\n        && (32usize + u32_at(slice, 20) as usize) <= slice.len()\n}","tryCatchPattern":"// Per-artifact: propagate with the file path attached so the failing bottle\n// is identifiable in the pour log.\npatch_macho(&mut content, &replacements, &path)\n    .wrap_err_with(|| format!(\"relocating {}\", path.display()))?;","preventionTips":["Verify bottle checksums on download so truncated Mach-O files never reach relocation","Screen artifacts with otool -hv in CI when pouring third-party bottles"],"tags":["brew","macho","macos","binary-patching","validation"],"backgroundTag":"mach-o-header-validation-failed","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}