Skip to content

Stack Overflow due to Recursive DWO Reference in Chromium #476

@EricRahm

Description

@EricRahm

Description

bloaty crashes with a stack overflow (AddressSanitizer: stack-overflow) when running with -d compileunits on binaries where a .dwo file refers to itself via the DW_AT_GNU_dwo_name attribute. This causes infinite recursion in ReadDWARFDebugInfo and ReadDWARFCompileUnits.

Reproduction Steps

  1. Build bloaty with ASAN enabled:

    cmake -B build/main -G Ninja -S . \
      -DCMAKE_BUILD_TYPE=Debug \
      -DBLOATY_ENABLE_ASAN=ON
    cmake --build build/main
  2. Run against a binary with recursive DWO references (e.g., Chrome debug build):

    cd /path/to/chrome-build
    /path/to/bloaty/build/main/bloaty -d compileunits ./chrome

Analysis

ASAN Output

The application crashes with a stack overflow.

AddressSanitizer:DEADLYSIGNAL
=================================================================
==3401789==ERROR: AddressSanitizer: stack-overflow on address 0x7bf03b3ffff8 (pc 0x7ff03fc3e888 bp 0x000000000000 sp 0x7bf03b3ffff0 T1)
Thread T1 created by T0 here:
    #0 0x7ff03fd11612 in pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cpp:250
    #1 0x7ff03f8e6e38 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (/lib/x86_64-linux-gnu/libstdc++.so.6+0xe6e38)
    #2 0x55743569d987 in bloaty::Bloaty::ScanAndRollupFiles(...) src/bloaty.cc:1926
    ...

GDB Backtrace

Running under GDB confirms infinite recursion between ReadDWARFCompileUnits and ReadDWARFDebugInfo.

Command used:

gdb -batch -ex "run" -ex "bt 20" --args /path/to/bloaty/build/main/bloaty -d compileunits ./chrome

Output:

#12 0x000055555668a9b0 in bloaty::dwarf::CU::ReadHeader (...) at src/dwarf/debug_info.cc:175
#13 0x00005555566898e3 in bloaty::dwarf::CUIter::NextCU (...) at src/dwarf/debug_info.cc:121
#14 0x0000555556508446 in bloaty::ReadDWARFDebugInfo (...) at src/dwarf.cc:643
#15 0x0000555556508b20 in bloaty::ReadDWARFCompileUnits (...) at src/dwarf.cc:722
#16 0x0000555556507ceb in bloaty::ReadDWARFDebugInfo (...) at src/dwarf.cc:674
#17 0x0000555556508b20 in bloaty::ReadDWARFCompileUnits (...) at src/dwarf.cc:722
#18 0x0000555556507ceb in bloaty::ReadDWARFDebugInfo (...) at src/dwarf.cc:674
#19 0x0000555556508b20 in bloaty::ReadDWARFCompileUnits (...) at src/dwarf.cc:722
...

Identifying the Offending File

To determine which file caused the recursion, I temporarily instrumented src/dwarf.cc to print the DWO path before recursing:

    std::string dwo_path = ConstructDwoPath(dwo_info);
    if (!dwo_path.empty()) {
      fprintf(stderr, "Processing DWO: %s\n", dwo_path.c_str()); // Added this line
      auto file = MmapInputFileFactory().OpenFile(dwo_path);

Re-running bloaty produced the following output immediately before the stack overflow:

Processing DWO: obj/chrome/chrome_initial/chrome_exe_main_aura.dwo
Processing DWO: obj/chrome/chrome_initial/chrome_exe_main_aura.dwo
Processing DWO: obj/chrome/chrome_initial/chrome_exe_main_aura.dwo
...

Binary Analysis

Inspecting obj/chrome/chrome_initial/chrome_exe_main_aura.dwo with readelf confirmed the self-reference:

$ readelf -wi chrome-build/obj/chrome/chrome_initial/chrome_exe_main_aura.dwo | grep dwo_name
    <10>   DW_AT_GNU_dwo_name: (indexed string: 0x7): obj/chrome/chrome_initial/chrome_exe_main_aura.dwo

Because the DWO name points to the file itself, Bloaty recursively attempts to parse it indefinitely.

Affected Code

The issue lies in src/dwarf.cc where dwo_path is processed without checking if it has already been visited or if it refers to the current file.

// src/dwarf.cc

    std::string dwo_path = ConstructDwoPath(dwo_info);
    if (!dwo_path.empty()) {
      auto file = MmapInputFileFactory().OpenFile(dwo_path);
      dwarf::File dwo_dwarf;
      cu.dwarf().open(*file, &dwo_dwarf, sink);
      // RECURSION HAPPENS HERE
      ReadDWARFCompileUnits(dwo_dwarf, symbol_map, &cu, sink);
    }

Minimal Reproduction

A minimal reproduction can be created using yaml2obj.

  1. Create recursive.yaml:

    ---
    !ELF
    FileHeader:
      Class:           ELFCLASS64
      Data:            ELFDATA2LSB
      Type:            ET_DYN
      Machine:         EM_X86_64
    Sections:
      - Name:            .text
        Type:            SHT_PROGBITS
        Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
        Address:         0x400000
        AddressAlign:    0x10
        Size:            0x100
    DWARF:
      debug_str:
        - recursive.o
        - "."
      debug_abbrev:
        - ID:              0
          Table:
            - Code:            0x1
              Tag:             DW_TAG_compile_unit
              Children:        DW_CHILDREN_no
              Attributes:
                - Attribute:       DW_AT_GNU_dwo_name
                  Form:            DW_FORM_strp
                - Attribute:       DW_AT_comp_dir
                  Form:            DW_FORM_strp
      debug_info:
        - Version:         4
          AbbrevTableID:   0
          AbbrOffset:      0x0
          AddrSize:        8
          Entries:
            - AbbrCode:        0x1
              Values:
                - Value:           0x0 # points to "recursive.o"
                - Value:           0xc # points to "."
  2. Generate the object file:

    yaml2obj recursive.yaml -o recursive.o
  3. Run Bloaty:

    ./bloaty -d compileunits recursive.o

    This will trigger the stack overflow.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions