diff --git a/arch/Mips/MipsDisassembler.c b/arch/Mips/MipsDisassembler.c index e9d4f06a54..89b15c5f5e 100644 --- a/arch/Mips/MipsDisassembler.c +++ b/arch/Mips/MipsDisassembler.c @@ -2420,7 +2420,7 @@ static DecodeStatus DecodeMemMMReglistImm4Lsl2(MCInst *Inst, uint32_t Insn, Offset = fieldFromInstruction_4(Insn, 4, 4); break; default: - Offset = SignExtend32((Insn & 0xf), 4); + Offset = fieldFromInstruction_4(Insn, 0, 4); break; } diff --git a/tests/integration/test_poc.c b/tests/integration/test_poc.c index adf9a351eb..efe032be99 100644 --- a/tests/integration/test_poc.c +++ b/tests/integration/test_poc.c @@ -208,6 +208,28 @@ static void test_ub_isintn_xtensa_offset(void) return; } +/// Signed left shift of a negative value when decoding a microMIPS +/// LWM16/SWM16 offset. The ISA defines the offset as zero_extend(offset||0^2), +/// but the 4-bit field was sign-extended to a negative int and then shifted +/// left by 2, which is UB whenever the field's top bit is set (field >= 8). +static void test_ub_shift_mips_mm_reglist(void) +{ + static const uint8_t code[] = { 0x45, 0x08 }; + + csh handle; + if (cs_open(CS_ARCH_MIPS, + CS_MODE_MICRO | CS_MODE_MIPS32 | CS_MODE_BIG_ENDIAN, + &handle) != CS_ERR_OK) + return; + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + cs_insn *insn = NULL; + size_t count = cs_disasm(handle, code, sizeof(code), 0x1000, 0, &insn); + cs_free(insn, count); + cs_close(&handle); + return; +} + int main() { test_overflow_cs_insn_bytes(); @@ -216,6 +238,7 @@ int main() test_integer_overflow(); test_ub_shift_sh_dsp_p(); test_ub_isintn_xtensa_offset(); + test_ub_shift_mips_mm_reglist(); return 0; } diff --git a/tests/issues/issues.yaml b/tests/issues/issues.yaml index 914f3cfc09..f40f95d3c0 100644 --- a/tests/issues/issues.yaml +++ b/tests/issues/issues.yaml @@ -6734,3 +6734,15 @@ test_cases: - asm_text: "ptrue pn10.h" op_str: "pn10.h" + - + input: + name: "issue 2989 microMIPS LWM16 reglist offset zero-extended" + bytes: [ 0x45, 0x08 ] + arch: "CS_ARCH_MIPS" + options: [ CS_MODE_MICRO, CS_MODE_MIPS32, CS_MODE_BIG_ENDIAN ] + address: 0x0 + expected: + insns: + - + asm_text: "lwm16 $s0, $ra, 0x20($sp)" + op_str: "$s0, $ra, 0x20($sp)"