-
Notifications
You must be signed in to change notification settings - Fork 5.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Infinite loop in disassembler when processing nested delay slot #1486
Comments
This is definitely a pathological case. We can fix it so that it will not cause the infinite loop, but it still won't process the instructions because of the branch in the delay slot. This situation is considered "UNPREDICTABLE" prior to release 6, and generate a Reserve Instruction Exception in release 6. How was the code generated in the object file? I would assume that the assembler would disallow this situation. |
Absolutely, fixing it so the disassembler does not choke is all I was hoping for!
which best I can tell is the intention of the original code, ie to hang (and possibly provoke and exception) if the forbidden situation where status==6 occurs. The branch within the delay slot is inserted by the compiler for the while() loop. |
Fix implemented for 9.1.2 |
This is a pathological case but I came across it in a real-world framework. In this case it is MIPS but I think it affects all processors that have delay slots. The code in question is something like (object file attached as well):
The instructions at addresses 18 and 1c will send the disassembler into an infinite loop that eventually causes an out of memory exception. While the branch at address 1C is definitely invalid, I guess it should not lead to a "DoS" and as I said this is found in a real-world application.
The idea seems to be that address 18 should never be reached, hence the tight loop, and there is a NOP missing before the next branch instruction.
The problem happens in Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java, in function processInstruction:
Here, first processInstructionFlows is called for the block starting at address 18, as this is a branch to itself the call will add address 18 again to the disassemblerQueue for later analysis. Then, parseDelaySlots is called and throws a NestedDelaySlotException when it sees the branch at address 1c. The exception is caught in disassembleInstructionBlock, where the next loop iteration finds the same address 18 on the disassemblerQueue; and because the instruction was not yet added to the block, the check to see if the block has already been disassembled fails and we have an infinite loop.
A very quick fix is to move block.addInstruction(inst) before the call to parseDelaySlots but I am not sure that will not cause other problems.
I attach a small object file that shows this behavior when you try to disassemble or auto-analyze it.
nesteddelayslot.zip
The text was updated successfully, but these errors were encountered: