Issue 203625
Summary [llvm-dwp] Infinite loop on GCC DWARF5 .dwo: abbrev scan does not skip DW_FORM_implicit_const value (getCUAbbrev)
Labels new issue
Assignees
Reporter kchri-lmc
    ## Summary

`llvm-dwp` hangs forever (100% CPU, no output) when packing certain `.dwo`
files produced by GCC with `-gsplit-dwarf` (DWARF5, the GCC default since
GCC 11). The same files are parsed fine by `llvm-dwarfdump`. Recompiling the
identical source with `-gdwarf-4` makes `llvm-dwp` succeed.

Reproduced with LLVM 22.1.2 (Ubuntu) and 22.1.7 (Homebrew).

## Minimal reproducer

```cpp
// repro.cpp
#include <string>
std::string s = "x";
```

```sh
$ g++-15 -c -g -gsplit-dwarf repro.cpp   # g++ (Ubuntu 15.2.0-16ubuntu1) 15.2.0
$ llvm-dwp repro.dwo -o repro.dwp        # never terminates, spins at 100% CPU
```

Whether a given `.dwo` hangs is content-dependent (byte luck, see analysis);
this 2-line TU reproduces deterministically with the stated compiler.
`repro.dwo` is attached for convenience.

## Backtrace at the hang

```
#0 llvm::DataExtractor::getULEB128(unsigned long*, llvm::Error*) const
#1 getCUIdentifiers(llvm::InfoSectionUnitHeader&, llvm::StringRef, llvm::StringRef, llvm::StringRef, llvm::StringRef)
#2 llvm::write(llvm::MCStreamer&, llvm::ArrayRef<std::string>, llvm::OnCuIndexOverflow, llvm::Dwarf64StrOffsetsPromotion)
#3 llvm_dwp_main
```

## Root cause analysis

`getCUIdentifiers` (llvm/lib/DWP/DWP.cpp) locates the compile unit's
abbreviation by scanning `.debug_abbrev.dwo` sequentially (helper
`getCUAbbrev`). The skip loop for non-matching declarations reads
`(attribute, form)` ULEB128 pairs until the `(0, 0)` terminator — but does
not handle `DW_FORM_implicit_const` (0x21), whose abbrev declaration carries
an extra SLEB128 value after the form (DWARF5 §7.5.3). The constant's bytes
are then misinterpreted as the next attribute code and the scan desyncs.

Two factors make GCC output hit this where Clang output does not:

1. GCC emits `DW_FORM_implicit_const` in `.dwo` abbrev tables; in the
   attached reproducer 78 declarations use it.
2. GCC orders abbrev declarations by usage frequency, so the
   `DW_TAG_compile_unit` declaration gets a high code (105 in the
   reproducer; Clang emits it as code 1, so the skip loop never executes).

After desync the scan either realigns by luck (pack succeeds, possibly
having read the CU abbrev from a wrong offset) or runs past the end of the
section. At EOF, `DataExtractor::getULEB128` returns 0 **without advancing
the offset**, the returned code never equals the target, and the
`while (getULEB128(...) != AbbrCode)` loop spins forever — the observed
hang.

Verified by simulating both scans over the reproducer's raw
`.debug_abbrev.dwo` bytes (section dumped with objcopy):

repro.dwo contains the exact .dwo (hang is content-dependent — other gcc patch releases may produce luckier bytes from the same source; the attached binary reproduces regardless of local compiler).

[repro.dwo.zip](https://github.com/user-attachments/files/28896882/repro.dwo.zip)

```
buggy scan  (no implicit_const handling): EOF-SPIN (offset stuck at 2843)
correct scan (consumes trailing SLEB)   : found code 105
```

(Simulator script attached: sim.py)

## Suggested fix

In the abbrev skip loop of `getCUAbbrev`, after reading each form, consume
the trailing SLEB128 when the form is `DW_FORM_implicit_const` — mirroring
`DWARFAbbreviationDeclaration::extract`. Independently, the scan should
treat reaching end-of-section as a malformed-input error instead of looping
(check the offset advanced or use the `Error`-aware `DataExtractor` API), so
that any future unknown-form desync fails loudly rather than hanging the
build.

## Environment

- llvm-dwp: 22.1.2 (Ubuntu `llvm-22-tools` 1:22.1.2-1ubuntu1) and 22.1.7 (Homebrew) — identical behavior
- gcc: g++ (Ubuntu 15.2.0-16ubuntu1) 15.2.0; also reproduced with TUs from g++ 13 (content-dependent)
- Target: x86_64-linux-gnu

[repro.cpp](https://github.com/user-attachments/files/28896642/repro.cpp)
[sim.py](https://github.com/user-attachments/files/28896641/sim.py)

_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to