Issue 184959
Summary [MC][MIPS] Assertion failure in MipsMCCodeEmitter::getSimm18Lsl3Encoding when assembling MIPS64r6 LDPC with non-8-byte-aligned offset
Labels new issue
Assignees
Reporter venkyqz
    ## Summary

There exists a semantic gap in the MIPS64r6 assembly pipeline. The frontend `AsmParser` accepts unaligned PC-relative offsets for the `ldpc` instruction due to a missing specification in `TableGen`. This perfectly bypasses frontend validation, resulting in:

- **Debug Build**: Assertion failure (`Exit 134`)
- **Release Build**: Silent miscompilation (`Exit 0`, emitting incorrect bytes)

This bug is triggerable entirely via assembling (Clang or llvm-mc)

---

## Reproduction
**Godbolt Link**
+ https://godbolt.org/z/bbK6af1hc

**Test File (`poc.s`):**

```asm
.set mips64r6
.text
ldpc $at, 3
```

Any offset not strictly divisible by 8 (e.g., 3, 7, -1) will trigger the divergence.

**Commands:**

```bash
# Debug Build - Crashes with assertion
llvm-mc -filetype=obj -triple=mips64 -mattr=+mips64r6 poc.s
# Exit 134, Assertion failed

# Release Build - Silent miscompilation
llvm-mc -filetype=obj -triple=mips64 -mattr=+mips64r6 poc.s
# Exit 0, emits corrupted object code
```

**Debug Build Output:**

```
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace and instructions to reproduce the bug.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/llvm-mc -filetype=obj -o example.o --triple=mips64el-linux-gnu <source>
 #0 0x0000000000d41d58 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/llvm-mc+0xd41d58)
 #1 0x0000000000d3ee24 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x000074492b642520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x000074492b6969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x000074492b642476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x000074492b6287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x000074492b62871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x000074492b639e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x00000000008a2f4c (/opt/compiler-explorer/clang-assertions-trunk/bin/llvm-mc+0x8a2f4c)
 #9 0x00000000008a9584 llvm::MipsMCCodeEmitter::getBinaryCodeForInstr(llvm::MCInst const&, llvm::SmallVectorImpl<llvm::MCFixup>&, llvm::MCSubtargetInfo const&) const (/opt/compiler-explorer/clang-assertions-trunk/bin/llvm-mc+0x8a9584)
#10 0x00000000008ab628 llvm::MipsMCCodeEmitter::encodeInstruction(llvm::MCInst const&, llvm::SmallVectorImpl<char>&, llvm::SmallVectorImpl<llvm::MCFixup>&, llvm::MCSubtargetInfo const&) const (/opt/compiler-explorer/clang-assertions-trunk/bin/llvm-mc+0x8ab628)
#11 0x0000000000c00b6e llvm::MCObjectStreamer::emitInstToData(llvm::MCInst const&, llvm::MCSubtargetInfo const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/llvm-mc+0xc00b6e)
#12 0x0000000000c034de llvm::MCObjectStreamer::emitInstruction(llvm::MCInst const&, llvm::MCSubtargetInfo const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/llvm-mc+0xc034de)
#13 0x000000000089a835 llvm::MipsELFStreamer::emitInstruction(llvm::MCInst const&, llvm::MCSubtargetInfo const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/llvm-mc+0x89a835)
#14 0x00000000005cbd25 (anonymous namespace)::MipsAsmParser::processInstruction(llvm::MCInst&, llvm::SMLoc, llvm::MCStreamer&, llvm::MCSubtargetInfo const*) MipsAsmParser.cpp:0:0
#15 0x00000000005cdd84 (anonymous namespace)::MipsAsmParser::matchAndEmitInstruction(llvm::SMLoc, unsigned int&, llvm::SmallVectorImpl<std::unique_ptr<llvm::MCParsedAsmOperand, std::default_delete<llvm::MCParsedAsmOperand>>>&, llvm::MCStreamer&, unsigned long&, bool) MipsAsmParser.cpp:0:0
#16 0x0000000000c85857 (anonymous namespace)::AsmParser::parseAndMatchAndEmitTargetInstruction((anonymous namespace)::ParseStatementInfo&, llvm::StringRef, llvm::AsmToken, llvm::SMLoc) AsmParser.cpp:0:0
#17 0x0000000000c99d73 (anonymous namespace)::AsmParser::parseStatement((anonymous namespace)::ParseStatementInfo&, llvm::MCAsmParserSemaCallback*) (.part.0) AsmParser.cpp:0:0
#18 0x0000000000c9dfc3 (anonymous namespace)::AsmParser::Run(bool, bool) AsmParser.cpp:0:0
#19 0x000000000040c6ba main (/opt/compiler-explorer/clang-assertions-trunk/bin/llvm-mc+0x40c6ba)
#20 0x000074492b629d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#21 0x000074492b629e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#22 0x000000000047bbe5 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/llvm-mc+0x47bbe5)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```
---

## Root Cause

The vulnerability stems from a declarative omission in TableGen. The `ldpc` instruction uses `simm18_lsl3` operand (requires 8-byte alignment), but is mapped to an overly permissive parser class.

**Buggy Code (`MipsInstrInfo.td`):**

```cpp
def simm18_lsl3 : Operand<i64> {
  let ParserMatchClass = MipsJumpTargetAsmOperand; // VULNERABILITY: Only calls isImm()
}
```

**Comparison**: Sibling instructions like `addiupc` and `lwpc` (using `simm19_lsl2`) are mapped to `Simm19Lsl2AsmOperand`, which enforces 4-byte alignment via `isS19ImmX4()` predicate. The `simm18_lsl3` operand is missing an analogous `Simm18Lsl3AsmOperand` class with `isS18ImmX8()` validation.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to