Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
return standard_return()
# If the stack is constructed in such a way that
# we would return to the next instruction, it is
# effectively a subroutine call.
if self.stack.match(i.pc, ret_size):
i.ret_indirect_type = RetIndirectType.CALL
self.log.assert_jump(i.pc, set_dirty=False)
for s in self.stack.pop(ret_size):
if s.instruction:
s.instruction.stack_manipulation = StackManipulation.HARMLESS
return self.call(i, self.log.jump_assertions[i.pc])
# Otherwise, if we know this is a jump table, then it's a simple jump.
elif i.is_jump_table:
i.ret_indirect_type = RetIndirectType.JUMP
for s in stack_entries:
if s.instruction:
s.instruction.stack_manipulation = StackManipulation.HARMLESS
self.jump(i, self.log.jump_assertions[i.pc])
return False
# We don't know for certain that this is a jump table, signal
# an unknown state.
else:
self._unknown_subroutine_state(
i,
unknown_reason=UnknownReason.STACK_MANIPULATION,
stack_manipulator=stack_manipulator,
)
return False
state_change_before: StateChange,
):
super().__init__()
self.log = log
self.pc = pc
self.state = State(p)
self.registers = registers
self.subroutine_pc = subroutine_pc
self.opcode = opcode
self._argument = argument
self.state_change_before = state_change_before
self.state_change_after = StateChange(unknown_reason=UnknownReason.UNKNOWN)
self.stack_manipulation = StackManipulation.NONE
self.ret_indirect_type = RetIndirectType.NONE
if i.operation == Op.RTI:
return standard_return()
ret_size = 2 if i.operation == Op.RTS else 3
stack_entries = self.stack.pop(ret_size)
# Check for stack manipulations.
stack_manipulator = self._check_stack_manipulation(i, stack_entries)
if not stack_manipulator:
return standard_return()
# If the stack is constructed in such a way that
# we would return to the next instruction, it is
# effectively a subroutine call.
if self.stack.match(i.pc, ret_size):
i.ret_indirect_type = RetIndirectType.CALL
self.log.assert_jump(i.pc, set_dirty=False)
for s in self.stack.pop(ret_size):
if s.instruction:
s.instruction.stack_manipulation = StackManipulation.HARMLESS
return self.call(i, self.log.jump_assertions[i.pc])
# Otherwise, if we know this is a jump table, then it's a simple jump.
elif i.is_jump_table:
i.ret_indirect_type = RetIndirectType.JUMP
for s in stack_entries:
if s.instruction:
s.instruction.stack_manipulation = StackManipulation.HARMLESS
self.jump(i, self.log.jump_assertions[i.pc])
return False
# We don't know for certain that this is a jump table, signal
def indirect_jumps(self) -> List[int]:
return [
i.pc
for i in self.instructions.values()
if i.is_indirect_jump or i.ret_indirect_type != RetIndirectType.NONE
]
reason = i.state_change_after.unknown_reason
if i.is_call and reason == UnknownReason.INDIRECT_JUMP:
return [*jump_table_suggestion(), ("instruction", StateChange())]
elif i.is_jump and reason == UnknownReason.INDIRECT_JUMP:
if i.subroutine.does_save_state_in_incipit:
return [*jump_table_suggestion(), ("subroutine", StateChange())]
else:
return [*jump_table_suggestion(), *unified_state_suggestion()]
elif i.is_return and reason == UnknownReason.STACK_MANIPULATION:
return unified_state_suggestion()
elif i.is_return and reason == UnknownReason.INDIRECT_JUMP:
if i.ret_indirect_type == RetIndirectType.CALL:
return [*jump_table_suggestion(), ("instruction", StateChange())]
elif i.ret_indirect_type == RetIndirectType.JUMP:
return [*jump_table_suggestion(), *unified_state_suggestion()]
else:
assert False
elif unsafe:
if i.subroutine.is_recursive and reason == UnknownReason.RECURSION:
return unified_state_suggestion()
elif i.operation == Op.PLP and reason == UnknownReason.STACK_MANIPULATION:
return [("instruction", StateChange())]
return []
if i.is_call and reason == UnknownReason.INDIRECT_JUMP:
return [*jump_table_suggestion(), ("instruction", StateChange())]
elif i.is_jump and reason == UnknownReason.INDIRECT_JUMP:
if i.subroutine.does_save_state_in_incipit:
return [*jump_table_suggestion(), ("subroutine", StateChange())]
else:
return [*jump_table_suggestion(), *unified_state_suggestion()]
elif i.is_return and reason == UnknownReason.STACK_MANIPULATION:
return unified_state_suggestion()
elif i.is_return and reason == UnknownReason.INDIRECT_JUMP:
if i.ret_indirect_type == RetIndirectType.CALL:
return [*jump_table_suggestion(), ("instruction", StateChange())]
elif i.ret_indirect_type == RetIndirectType.JUMP:
return [*jump_table_suggestion(), *unified_state_suggestion()]
else:
assert False
elif unsafe:
if i.subroutine.is_recursive and reason == UnknownReason.RECURSION:
return unified_state_suggestion()
elif i.operation == Op.PLP and reason == UnknownReason.STACK_MANIPULATION:
return [("instruction", StateChange())]
return []