https://sourceware.org/bugzilla/show_bug.cgi?id=34490

            Bug ID: 34490
           Summary: RISC-V:objdump -d -l/-S OOM (exponential trie split)
                    on 32-bit ELF with .debug_ranges base-address sentinel
           Product: binutils
           Version: 2.46
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: binutils
          Assignee: unassigned at sourceware dot org
          Reporter: bigmagicreadsun at gmail dot com
  Target Milestone: ---

Created attachment 16908
  --> https://sourceware.org/bugzilla/attachment.cgi?id=16908&action=edit
rv32

Description of problem:
`objdump -d -l` or `objdump -d -S` on a 32-bit ELF whose .debug_ranges uses
the base-address-selection entry exhausts memory (observed up to ~50GB) or
segfaults. `objdump -d` (without -l/-S) works fine. The trigger is the line-
number/source lookup path.

Root cause:
In bfd/dwarf2.c, read_ranges() detects the DWARF base-address-selection
sentinel by comparing the read value against the *host-word-width* sentinel:

    if (low_pc == (bfd_vma) -1 && high_pc != (bfd_vma) -1)
        base_address = high_pc;

(bfd_vma) -1 is 0xFFFFFFFFFFFFFFFF on a 64-bit host.  However, on a 32-bit
target (addr_size == 4) whose backend does not set sign_extend_vma (e.g.
RISC-V), read_address() reads the 4-byte sentinel 0xFFFFFFFF via
bfd_get_32() and returns it ZERO-EXTENDED to 0x00000000FFFFFFFF, which
never equals the 64-bit (bfd_vma)-1.

Consequently the sentinel (0xFFFFFFFF, 0) is misread as the inverted,
invalid range [0xFFFFFFFF, 0) (low_pc > high_pc) and passed to
arange_add() -> insert_arange_in_trie().  The inverted range spans every
bucket at every level of the shared address->CU trie (from_ch == 0x00,
to_ch == 0xff due to (high_pc - 1) underflow), so the trie is split
exhaustively across all 8 VMA levels (~256^8 nodes), exhausting memory.
With ~30 CUs each contributing one such inverted range to the shared trie,
the leaf (capacity TRIE_LEAF_SIZE == 16) repeatedly fills and splits,
making the blowup deterministic.

Note: backends that DO set sign_extend_vma (e.g. 32-bit ARM/x86) are
unaffected because sign-extension turns 0xFFFFFFFF into
0xFFFFFFFFFFFFFFFF, which coincidentally equals (bfd_vma)-1 and thus
masks the bug.

Reproduction:

 ulimit -v 4000000

 riscv64-unknown-elf-objdump -d -S test.elf

80000100 <_start>:

riscv64-unknown-elf-objdump: out of memory allocating 259 bytes after a total
of 4082536448 bytes

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Reply via email to