Skip to content

mips: fix left shift of negative value in DecodeMemMMReglistImm4Lsl2#2989

Closed
Samin061 wants to merge 2 commits into
capstone-engine:nextfrom
Samin061:mips-mm-reglist-neg-shift
Closed

mips: fix left shift of negative value in DecodeMemMMReglistImm4Lsl2#2989
Samin061 wants to merge 2 commits into
capstone-engine:nextfrom
Samin061:mips-mm-reglist-neg-shift

Conversation

@Samin061

@Samin061 Samin061 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Your checklist for this pull request

  • I've documented or updated the documentation of every API function and struct this PR changes.
  • I've added tests that prove my fix is effective or that my feature works (if possible)

Detailed description

DecodeMemMMReglistImm4Lsl2 decodes the offset of the microMIPS LWM16/SWM16 instructions. The ISA defines the address as:

vAddr = zero_extend(offset||0^2) + GPR[sp]

so the 4-bit offset field is concatenated with two zero bits and then zero-extended. The MMR6 path already treats it as unsigned (fieldFromInstruction_4), but the non-MMR6 path sign-extended the field (SignExtend32((Insn & 0xf), 4)) before the << 2. That was wrong in two ways: whenever the field's top bit is set (field >= 8) the value became negative, so Offset << 2 is a left shift of a negative value (UB), and the decoded offset came out negative instead of the zero-extended value the ISA requires.

ubsan on the unpatched tree:

arch/Mips/MipsDisassembler.c:2432:37: runtime error: left shift of negative value -8

Fix is to zero-extend the field to match both the ISA and the MMR6 path. The shift is then always applied to a non-negative value, so the UB is gone and the offset is correct.

Test plan

Added test_ub_shift_mips_mm_reglist to tests/integration/test_poc.c, next to the existing test_ub_shift_sh_dsp_p signed-shift regression. Building with -fsanitize=undefined -fno-sanitize-recover=undefined and running test_poc aborts at MipsDisassembler.c:2432 before the change and exits cleanly after. cstool micromips 4508 now prints lwm16 $s0, $ra, 0x20($sp) (the zero-extended 8 << 2 == 0x20).

@github-actions github-actions Bot added the Mips Arch label Jul 7, 2026

@Rot127 Rot127 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I see this correctly in the ISA, is the offset first shifted then sign extended.

vAddr = zero_extend(offset||02) + GPR[sp]

https://docs.alexrp.com/mips/micromips32_insns_v6_04.pdf

The ISA defines the offset as zero_extend(offset||0^2), but the non-MMR6
path sign-extended the 4-bit field before the << 2. That both triggered a
left-shift-of-negative-value UB (field top bit set) and produced a wrong
negative offset. Zero-extend the field to match the ISA and the MMR6 path;
the shift is now UB-free.

Signed-off-by: bibi samina <sam@bugqore.com>
@Samin061

Samin061 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

You're right, and good catch. The pseudocode is zero_extend(offset||0^2), so the field is zero-extended, not sign-extended. The old SignExtend32 in the non-MMR6 path was wrong on both counts: it made the offset negative (so 4508 decoded as -0x20 instead of 0x20) and the negative value was what tripped the << 2 UB.

Switched that path to zero-extend the field, matching the MMR6 branch and the ISA. Now cstool micromips 4508 prints lwm16 $s0, $ra, 0x20($sp) and the shift is UB-free. Kept the << 2 since the value is non-negative now.

@Rot127

Rot127 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

If you generate changes with LLMs you have to test them properly and see if they make sense. Feel free to open a PR again if you find time to follow those standards.

@Samin061

Samin061 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Reworked and reopened as #2991. GitHub wouldn't let me reopen this one after the branch was force-pushed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Mips Arch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants