Repository navigation
Conversation
A relocatable object can map no memory at all: compiled from a translation unit with no code and without debug info, it has one segment with vmsize 0 holding an empty __text. MachO inherited Backend.max_addr, which counts every segment, so the object's max_addr was that segment's vmaddr minus one, below its min_addr, and the assertion in Loader._map_object lost the whole load. A segment with vmsize 0 maps nothing, which _load_segment already assumes when it backs none of it. MachO.max_addr now counts only segments with a nonzero vmsize, and falls back to the base address when there are none, as Backend.max_addr does for an object with no segments or sections.
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head A megabench object that failed to load in two corpus sweeps now loads; on 3709 other megabench Mach-O objects, nothing changed.
Dataset evidenceOne environment per side, built from the same trees apart from cle: angr
That object is unavailable: its bytes are not published here. Two more megabench objects, which no sweep has reached yet, fail and load the same way: Regression set: 3709 other megabench Mach-O objects that the sweeps have recorded. They are all 3293 other relocatable objects (1780 arm64, 1513 x86_64); the 16 others with a segment of vmsize 0 (executables: 13 with an empty Alternative not taken: on the baseline env, over the 1285 files under Commands
|
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Loading import sys
import cle
ld = cle.Loader(sys.argv[1], auto_load_libs=False)
obj = ld.main_object
print(obj)
print("min_addr", hex(obj.min_addr), "max_addr", hex(obj.max_addr))
print("segments", [(seg.segname, hex(seg.vaddr), seg.memsize) for seg in obj.segments])
print("backers", list(obj.memory.backers()))The nix store prefix of each traceback path is shortened to Before — the load fails the cle master 8d90286After — the object loads and maps nothing: with this change, 8508ba3 |
|
Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/cle_878 |
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Problem
cle.Loadercannot load a Mach-O relocatable object that maps no memory, such as the new fixturetests/aarch64/relocatable_object_empty.macho, compiled from a translation unit with no code. It fails with an assertion that carries no message:The whole load is lost, so angr cannot open the object at all. A megabench object failed the same way in two corpus sweeps; the validation record identifies it.
Root cause
MachOinheritsBackend.max_addr, the highestmax_addramong the object's segments, and a segment'smax_addrisvaddr + memsize - 1. The empty object's only segment has vmaddr 0 and vmsize 0, so the object'smax_addris -1, one below itsmin_addrof 0.MachO._load_segmentalready treats a segment with vmsize 0 as mapping nothing and backs none of it, butmax_addrstill counted it.Fix
MachO.max_addrcounts only segments with a nonzero vmsize. When there are none it falls back to the base address, which is whatBackend.max_addrreturns for an object with no segments or sections. The empty object now loads withmin_addrandmax_addrboth 0 and nothing backed.The rule is in the Mach-O backend rather than in
Backend.max_addr: the same change there would movemax_addrfor four ELF files in angr/binaries whose highestPT_LOADis empty, and angr places the initial program break frommax_addr.Testing
test_relocatable_object_emptyloads the new fixture and checks its extent and that nothing is backed; it fails on master with theAssertionErrorabove. Over 3709 other megabench Mach-O objects that corpus sweeps have recorded, the load result and every loaded object's extent are unchanged.The fixture is in angr/binaries#264, which needs to merge first.
Validation: #878 (comment)
session: sharpen