From 722089a57a24a05567326e90f3e87554af5af71c Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Thu, 23 Apr 2026 12:38:21 -0400 Subject: [PATCH 1/3] Fix `eltype` for `FatMachOHandle` --- src/MachO/MachOFat.jl | 2 +- test/runtests.jl | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/MachO/MachOFat.jl b/src/MachO/MachOFat.jl index b636f21..68efcf9 100644 --- a/src/MachO/MachOFat.jl +++ b/src/MachO/MachOFat.jl @@ -67,7 +67,7 @@ keys(h::FatMachOHandle) = 1:length(h) iterate(h::FatMachOHandle, idx=1) = idx > length(h) ? nothing : (h[idx], idx+1) lastindex(h::FatMachOHandle) = lastindex(h.header.archs) length(h::FatMachOHandle) = length(h.header.archs) -eltype(::Type{S}) where {S <: FatMachOHandle} = MachOLoadCmdRef +eltype(::Type{<:FatMachOHandle}) = MachOHandle function getindex(h::FatMachOHandle, idx) seek(h.io, h.start + h.header.archs[idx].offset) only(readmeta(h.io, MachOHandle)) diff --git a/test/runtests.jl b/test/runtests.jl index c5b1146..b8a0910 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -217,6 +217,10 @@ function test_fat_libfoo(file) end @test ntotal == 2 @test n64 == 1 + + handles = collect(ohs) + @test handles isa Vector{<:MachOHandle} + @test length(handles) == 2 end function test_metal(file) From df8d9dfcbc39a96a22b20dff17276d5e8030f805 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Wed, 7 Oct 2026 22:27:12 -0400 Subject: [PATCH 2/3] Fix parsing of 64-bit fat Mach-O headers Fat files with `FAT_MAGIC_64` could not be read at all: - `macho_endianness()` did not know `FAT_MAGIC_64` / `FAT_CIGAM_64`, so `readmeta()` threw a `MagicMismatch` for them. - `MachOFatArch64` declared `cputype` and `cpusubtype` as `UInt64`, but in `fat_arch_64` they are 32-bit, as in `fat_arch`. This shifted every following field, so slice offsets were wrong. Add a `libfoo_fat64.dylib` test fixture, made from the slices of `libfoo_fat.dylib` with `llvm-lipo -create -fat64` (LLVM 18). Co-Authored-By: Claude Opus 5.5 --- src/MachO/MachOFat.jl | 4 ++-- src/MachO/MachOHeader.jl | 4 ++-- test/mac64/libfoo_fat64.dylib | Bin 0 -> 16744 bytes test/runtests.jl | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) create mode 100755 test/mac64/libfoo_fat64.dylib diff --git a/src/MachO/MachOFat.jl b/src/MachO/MachOFat.jl index 68efcf9..3cc1c12 100644 --- a/src/MachO/MachOFat.jl +++ b/src/MachO/MachOFat.jl @@ -11,8 +11,8 @@ abstract type MachOFatArchitecture end end @io struct MachOFatArch64 <: MachOFatArchitecture - cputype::UInt64 - cpusubtype::UInt64 + cputype::UInt32 + cpusubtype::UInt32 offset::UInt64 size::UInt64 align::UInt32 diff --git a/src/MachO/MachOHeader.jl b/src/MachO/MachOHeader.jl index de965e6..9a855e4 100644 --- a/src/MachO/MachOHeader.jl +++ b/src/MachO/MachOHeader.jl @@ -74,9 +74,9 @@ Given the `magic` field from a Mach-O file header, return the endianness of the Mach-O header. """ function macho_endianness(magic::UInt32) - if magic in (MH_CIGAM, MH_CIGAM_64, FAT_CIGAM, FAT_CIGAM_METAL) + if magic in (MH_CIGAM, MH_CIGAM_64, FAT_CIGAM, FAT_CIGAM_64, FAT_CIGAM_METAL) return :BigEndian - elseif magic in (MH_MAGIC, MH_MAGIC_64, FAT_MAGIC, FAT_MAGIC_METAL, METALLIB_MAGIC) + elseif magic in (MH_MAGIC, MH_MAGIC_64, FAT_MAGIC, FAT_MAGIC_64, FAT_MAGIC_METAL, METALLIB_MAGIC) return :LittleEndian else throw(MagicMismatch("Invalid Magic (0x$(string(magic, base=16, pad=8)))!")) diff --git a/test/mac64/libfoo_fat64.dylib b/test/mac64/libfoo_fat64.dylib new file mode 100755 index 0000000000000000000000000000000000000000..09a05495d3452b325c52a2fd8c75778efba777b2 GIT binary patch literal 16744 zcmeHOO=weD6uz(lwW_monLpv$0bP)Nj|RA(=Y4mzQh^_W@Dn{^$KNe~bO1OY)n5D)|e0YN|z z5CjAPK|l}?1inH9p8fT9-W2{zkspiwL39JoqX&SRU)_h=_Hg3JFpQv>76E3SUjk(l zfnwWUcHHxA-)}uX7FMbs3!E4KvyD#8xVBv>o-GtJcA=OnA-FJyX`CHIoU?haIcsL- z&jyBV@85f1Ut-T*^9{^hYp-r>aIcY7Ft$Ovpuu>5c`W7StxTlW)4};YcEaVW_v~q24q6bd=jvMBQo3e$lvPcYtz3z_U8@+k&i3uvkw2Lm z?>U!tPL0{|sxw-xo+&#q$S*}}SU+LAU_XZ|}}rieK4rZ8F`*UJ+jTQ9eR1mOqD&z{dqS3H%!{oCJQSh#(*c2m*qDARq_` z0)l`bAP5KoUjl*T;M5Fm`hR2{L>d6O07JO;KbnNq7)~T-!&@GVJiOQtont?1!QlNr z Date: Wed, 7 Oct 2026 22:37:40 -0400 Subject: [PATCH 3/3] Fix `readmeta(io, FatMachOHandle)` for `IOBuffer`s on 32-bit `position()` of an `IOBuffer` is an `Int`, which on 32-bit platforms does not match the `Int64` start of a `FatMachOHandle`. Convert it, as the other handle types already do. Co-Authored-By: Claude Opus 5.5 --- src/MachO/MachOFat.jl | 2 +- test/runtests.jl | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/MachO/MachOFat.jl b/src/MachO/MachOFat.jl index 3cc1c12..52f83e1 100644 --- a/src/MachO/MachOFat.jl +++ b/src/MachO/MachOFat.jl @@ -59,7 +59,7 @@ function readmeta(io::IO,::Type{FatMachOHandle}) # Unpack the header header = unpack(io, header_type, endianness) - return FatMachOHandle(io, start, header, path(io)) + return FatMachOHandle(io, Int64(start), header, path(io)) end # Iteration diff --git a/test/runtests.jl b/test/runtests.jl index 4bcc88f..860620e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -207,7 +207,7 @@ function test_libfoo_and_fooifier(fooifier_path, libfoo_path) end function test_fat_libfoo(file) - ohs = readmeta(open(file, "r")) + ohs = readmeta(file isa IO ? file : open(file, "r")) @test isa(ohs, FatMachOHandle) @test length(ohs) == 2 ntotal, n64 = 0, 0 @@ -245,7 +245,9 @@ test_libfoo_and_fooifier("./linux64/fooifier", "./linux64/libfoo.so") # Run MachO tests test_libfoo_and_fooifier("./mac64/fooifier", "./mac64/libfoo.dylib") test_fat_libfoo("./mac64/libfoo_fat.dylib") +test_fat_libfoo(IOBuffer(read("./mac64/libfoo_fat.dylib"))) test_fat_libfoo("./mac64/libfoo_fat64.dylib") +test_fat_libfoo(IOBuffer(read("./mac64/libfoo_fat64.dylib"))) test_metal("./macmetal/dummy") # Run COFF tests