Esempio n. 1
0
    def _generate_cfg_slice(self, slice_instrs):
        block_map = {} # function block number : slice block number
        slice_func = FunctionBlock(self.func.label)

        for block in self.sorted_blocks:
            # Get all instructions in this block that are in the slice.
            linenos = block.get_instruction_linenos().intersection(slice_instrs)

            # Create a copy of the block.
            if not block_map:
                curr_bloc = slice_func
            else:
                curr_bloc = Block()
            block_map[block.label] = curr_bloc

            # Copy instructions in the block to block copy.
            for lineno in linenos:
                instruction = block.get_instruction(lineno)
                curr_bloc.add_instruction(instruction)

            # Copy the block's successors.
            for successor in block.successors:
                if successor in block_map:
                    curr_bloc.add_successor(block_map[successor])

            # Copy the block's predecessors.
            for predecessor in block.predecessors:
                if predecessor in block_map:
                    curr_bloc.add_predecessor(block_map[predecessor])

        return slice_func
Esempio n. 2
0
    def _visit_loop(self, instr_type, conditional_nodes, conditional_lineno, body):
        start_block = self.current_block
        prev_control = self.current_control
        prev_guard_block = self.guard_block
        prev_after_block = self.after_block

        guard_block = Block()
        start_body_block = Block()
        after_block = Block()

        # Add successors/predcessors.
        start_block.add_successor(guard_block)
        guard_block.add_successor(start_body_block)
        guard_block.add_successor(after_block)

        # Add conditional to guard block.
        self.current_block = guard_block
        for node in conditional_nodes:
            self._visit_item(node)
        self._add_instruction_info(lineno=conditional_lineno, instr_type=instr_type)
        self.current_control = conditional_lineno

        # Add body to body block.
        self.current_block = start_body_block
        self.guard_block = guard_block
        self.after_block = after_block

        self._visit_item(body)

        self.guard_block = prev_guard_block
        self.after_block = prev_after_block
        self._add_successor(self.current_block, guard_block)

        self.current_control = prev_control
        self.current_block = after_block
Esempio n. 3
0
    def visit_If(self, node):
        prev_control = self.current_control
        start_block = self.current_block

        # Add conditional to current block.
        self._visit_item(node.test)
        self.current_control = node.test.lineno

        # Add body to if block.
        start_if_block = Block()
        start_block.add_successor(start_if_block)
        self.current_block = start_if_block

        self._visit_item(node.body)
        end_if_block = self.current_block

        # Add orelse to else block.
        if node.orelse:
            start_else_block = Block()
            start_block.add_successor(start_else_block)
            self.current_block = start_else_block

            # If else block then add instruction type ELSE as a placeholder.
            if not isinstance(node.orelse[0], _ast.If):
                # Gets line number of else.
                lineno = node.orelse[0].lineno - 1
                while (lineno in self.tokens.comments or
                       lineno in self.tokens.blank_lines):
                    lineno -= 1

                # Adds ELSE instruction.
                self._add_instruction_info(lineno, instr_type=InstructionType.ELSE)
                self.current_control = lineno

            self._visit_item(node.orelse)
            end_else_block = self.current_block
        else:
            end_else_block = start_block

        # Add after block if all paths don't have a return.
        if end_if_block or end_else_block:
            after_block = Block()
            self._add_successor(end_if_block, after_block)
            self._add_successor(end_else_block, after_block)
            self.current_block = after_block
        self.current_control = prev_control
Esempio n. 4
0
    def _visit_exception(self, lineno, body, handlers):
        prev_control = self.current_control
        start_block = self.current_block
        end_except_block = None

        # Add TRY statement to current block.
        self._add_instruction_info(lineno, instr_type=InstructionType.TRY)
        self.current_control = lineno

        # Add body to try block.
        start_try_block = Block()
        start_block.add_successor(start_try_block)
        self.current_block = start_try_block

        self._visit_item(body)
        end_try_block = self.current_block

        # Add except data.
        for handler in handlers:
            # Add body to except block.
            start_except_block = Block()
            start_block.add_successor(start_except_block)
            self.current_block = start_except_block

            # Visit handler header (ex. except Exception as e).
            if isinstance(handler.name, str):
                self._add_instruction_info(handler.lineno, var='e', action=TypeVariable.STORE)
            else:
                self._visit_item(handler.name)
            self._visit_item(handler.type)
            self._add_instruction_info(handler.lineno, instr_type=InstructionType.EXCEPT)
            self.current_control = handler.lineno

            # Visit handler body.
            self._visit_item(handler.body)
            end_except_block = self.current_block

        # Add after block if all paths don't have a return.
        if end_try_block or end_except_block:
            after_block = Block()
            self._add_successor(end_try_block, after_block)
            self._add_successor(end_except_block, after_block)
            self.current_block = after_block
        self.current_control = prev_control
Esempio n. 5
0
    def test_to_string(self):
        result = ('func1 | \n'
                  '      | successors()\n'
                  '      | predecessors()\n\n')
        self.assertEqual(str(self.func_block1), result)

        block = Block()
        self.func_block1.add_successor(block)

        label = block.label
        spaces = ' ' * len(label)
        result = ('func1 | \n'
                  '      | successors({})\n'
                  '      | predecessors()\n\n'
                  '{} | \n'
                  '{} | successors()\n'
                  '{} | predecessors(func1)\n\n').format(
                      label, label, spaces, spaces)
        self.assertEqual(str(self.func_block1), result)
Esempio n. 6
0
    def visit_FunctionDef(self, node):
        prev_block = self.current_block

        # Create FunctionBlock.
        self.func_block = self.current_block = FunctionBlock(node.name)
        self._add_instruction_info(node.lineno, instr_type=InstructionType.FUNCTION_HEADER)

        # Create exit block.
        self.exit_block = Block()
        self.block_list.add(self.current_block)

        # Visit function information.
        self.generic_visit(node)
        self._add_successor(self.current_block, self.exit_block)

        # Add blank linenos and comments.
        linenos = set(range(node.lineno, self.last_lineno+1))
        self.func_block.blank_lines = linenos.intersection(self.tokens.blank_lines)
        self.func_block.comments = linenos.intersection(self.tokens.comments)
        self.func_block.unimportant |= self.func_block.blank_lines
        self.func_block.unimportant |= self.func_block.comments
        self.current_block = prev_block
Esempio n. 7
0
 def setUp(self):
     self.block1 = Block()
     self.block2 = Block()
     self.block3 = Block()
     self.block4 = Block()
Esempio n. 8
0
class TestBlock(unittest.TestCase):
    def setUp(self):
        self.block1 = Block()
        self.block2 = Block()
        self.block3 = Block()
        self.block4 = Block()

    def assertSuccessorsEqual(self, block, successors):
        actual = set(block.successors.keys())
        if successors is None:
            self.assertFalse(actual)
        else:
            expected = [successor.label for successor in successors]
            self.assertEqual(actual, set(expected))

    def assertPredecessorsEqual(self, block, predecessors):
        actual = set(block.predecessors.keys())
        if predecessors is None:
            self.assertFalse(actual)
        else:
            expected = [predecessor.label for predecessor in predecessors]
            self.assertEqual(actual, set(expected))

    def test_to_string(self):
        instr = Instruction(lineno=1)
        instr.referenced.add('varA')
        instr.defined.add('varB')
        self.block1.add_instruction(instr)

        label = self.block1.label
        spaces = ' ' * len(label)
        result = ('{} | \n'
                  '{} | successors()\n'
                  '{} | predecessors()\n'
                  '\t#1 | REF(varA) DEF(varB)\n').format(
                      label, spaces, spaces)
        self.assertEqual(str(self.block1), result)

    def test_labels(self):
        block_label1 = int(self.block1.label[1:])
        block_label2 = int(self.block2.label[1:])
        self.assertEqual(block_label2 - block_label1, 1)

        # Ensure error when trying to reset label.
        with self.assertRaises(ValueError) as context:
            self.block1.label = 'error_label'

    def test_equals(self):
        self.block2.add_predecessor(self.block1)
        self.block3.add_predecessor(self.block1)
        self.block2.add_successor(self.block4)
        self.block3.add_successor(self.block4)

        self.assertFalse(self.block2 == None)
        self.assertFalse(self.block2 == 1)
        self.assertFalse(self.block2 == self.block3)
        self.assertTrue(self.block2.equals(self.block3))

        instrA = Instruction(lineno=1)
        instrB = Instruction(lineno=1)
        instrB.referenced.add('varA')
        self.block2.add_instruction(instrA)
        self.block3.add_instruction(instrB)
        self.assertFalse(self.block2.equals(self.block3))

    def test_check_successor_equality(self):
        # Checks block with less than 2 successors.
        self.assertTrue(self.block1.check_successor_equality())
        self.block1.add_successor(self.block2)
        self.assertTrue(self.block1.check_successor_equality())

        # Checks block with successors.
        self.block1.add_successor(self.block3)
        self.block1.add_successor(self.block4)
        self.assertTrue(self.block1.check_successor_equality())

        # Checks block with different successors.
        instr = Instruction(lineno=1)
        self.block4.add_instruction(instr)
        self.assertFalse(self.block1.check_successor_equality())

    def test_add_reference(self):
        self.block1.add_reference(lineno=1, variable='varA')
        self.assertEqual(self.block1._instructions[1].referenced,
                         set(['varA']))
        self.assertFalse(self.block1._instructions[1].defined)
        self.assertEqual(len(self.block1.get_instructions()), 1)
        self.assertEqual(set(self.block1._instructions.keys()), set([1]))

        self.block1.add_reference(lineno=2, variable='varA')
        self.block1.add_reference(lineno=2, variable='varB')
        self.assertEqual(self.block1._instructions[2].referenced,
                         set(['varA', 'varB']))
        self.assertFalse(self.block1._instructions[2].defined)
        self.assertEqual(len(self.block1.get_instructions()), 2)
        self.assertEqual(set(self.block1._instructions.keys()), set([1, 2]))

    def test_add_definition(self):
        self.block1.add_definition(lineno=1, variable='varB')
        self.assertFalse(self.block1._instructions[1].referenced)
        self.assertEqual(self.block1._instructions[1].defined, set(['varB']))
        self.assertEqual(len(self.block1.get_instructions()), 1)
        self.assertEqual(set(self.block1._instructions.keys()), set([1]))

        self.block1.add_definition(lineno=2, variable='varA')
        self.block1.add_definition(lineno=2, variable='varC')
        self.assertFalse(self.block1._instructions[2].referenced)
        self.assertEqual(self.block1._instructions[2].defined,
                         set(['varA', 'varC']))
        self.assertEqual(len(self.block1.get_instructions()), 2)
        self.assertEqual(set(self.block1._instructions.keys()), set([1, 2]))

    def test_add_instruction_type(self):
        self.block1.add_reference(lineno=1, variable='varA')
        self.assertEqual(self.block1._instructions[1].referenced,
                         set(['varA']))
        self.assertEqual(self.block1._instructions[1].instruction_type, None)

        self.block1.add_instruction_type(
            lineno=1, instruction_type=InstructionType.RETURN)
        self.assertEqual(self.block1._instructions[1].instruction_type,
                         InstructionType.RETURN)

    def test_add_instr_control(self):
        self.block1.add_reference(lineno=1, variable='varA')
        self.block1.add_reference(lineno=2, variable='varA')
        self.assertEqual(self.block1._instructions[1].referenced,
                         set(['varA']))
        self.assertEqual(self.block1._instructions[2].referenced,
                         set(['varA']))
        self.assertEqual(self.block1._instructions[2].control, None)

        self.block1.add_instr_control(lineno=2, control=1)
        self.assertEqual(self.block1._instructions[2].control, 1)

    def test_add_instr_indent(self):
        self.block1.add_reference(lineno=1, variable='varA')
        self.block1.add_reference(lineno=2, variable='varA')
        self.assertEqual(self.block1._instructions[1].referenced,
                         set(['varA']))
        self.assertEqual(self.block1._instructions[2].referenced,
                         set(['varA']))
        self.assertEqual(self.block1._instructions[2].indentation, None)

        self.block1.add_instr_indent(lineno=2, indentation=1)
        self.assertEqual(self.block1._instructions[2].indentation, 1)

    def test_method_add_instruction(self):
        instr = Instruction(lineno=1)
        instr.referenced.add('varA')
        instr.defined.add('varB')
        self.block1.add_instruction(instr)
        self.assertEqual(len(self.block1.get_instructions()), 1)
        self.assertEqual(set(self.block1._instructions.keys()), set([1]))

    def test_add_multiline_instructions(self):
        instr = Instruction(lineno=1)
        self.block1.add_instruction(instr)
        self.assertFalse(self.block1._instructions[1].multiline)

        self.block1.add_multiline_instructions(lineno=1, linenos=[2, 3])
        self.assertEqual(self.block1._instructions[1].multiline, set([1, 2,
                                                                      3]))

    def test_add_successor(self):
        self.block1.add_successor(self.block1)
        self.block1.add_successor(self.block2)
        self.block1.add_successor(self.block3)
        self.assertSuccessorsEqual(self.block1, [self.block2, self.block3])
        self.assertPredecessorsEqual(self.block2, [self.block1])
        self.assertPredecessorsEqual(self.block3, [self.block1])

    def test_add_predecessor(self):
        self.block1.add_predecessor(self.block1)
        self.block1.add_predecessor(self.block2)
        self.block1.add_predecessor(self.block3)
        self.assertPredecessorsEqual(self.block1, [self.block2, self.block3])
        self.assertSuccessorsEqual(self.block2, [self.block1])
        self.assertSuccessorsEqual(self.block3, [self.block1])

    def test_set_successors(self):
        self.block1.add_successor(self.block1)
        self.block1.add_successor(self.block2)
        self.block1.add_successor(self.block3)
        self.assertSuccessorsEqual(self.block1, [self.block2, self.block3])
        self.assertPredecessorsEqual(self.block2, [self.block1])
        self.assertPredecessorsEqual(self.block3, [self.block1])

        self.block1.set_successors([self.block1, self.block2])
        self.assertSuccessorsEqual(self.block1, [self.block2])
        self.assertPredecessorsEqual(self.block2, [self.block1])
        self.assertPredecessorsEqual(self.block3, None)

        self.block1.set_successors([self.block3])
        self.assertSuccessorsEqual(self.block1, [self.block3])
        self.assertPredecessorsEqual(self.block2, None)
        self.assertPredecessorsEqual(self.block3, [self.block1])

        self.block1.set_successors([])
        self.assertSuccessorsEqual(self.block1, None)
        self.assertPredecessorsEqual(self.block2, None)
        self.assertPredecessorsEqual(self.block3, None)

    def test_replace_successor(self):
        self.block1.add_successor(self.block1)
        self.block1.add_successor(self.block2)
        self.assertSuccessorsEqual(self.block1, [self.block2])
        self.assertPredecessorsEqual(self.block2, [self.block1])
        self.assertPredecessorsEqual(self.block3, None)

        self.block1.replace_successor(self.block2, self.block3)
        self.assertSuccessorsEqual(self.block1, [self.block3])
        self.assertPredecessorsEqual(self.block2, None)
        self.assertPredecessorsEqual(self.block3, [self.block1])

        self.block1.replace_successor(self.block3, self.block1)
        self.assertSuccessorsEqual(self.block1, None)
        self.assertPredecessorsEqual(self.block2, None)
        self.assertPredecessorsEqual(self.block3, None)

        # Ensure error when trying to replace non-existant successor.
        with self.assertRaises(ValueError) as context:
            self.block1.replace_successor(self.block3, self.block1)

        # Before: Block 1 --> Block2 --> Block3
        # After: Block1 --> Block3 and Block2 --> Block3
        self.block1.add_successor(self.block2)
        self.block2.add_successor(self.block3)
        self.block1.replace_successor(self.block2, self.block3)
        self.assertSuccessorsEqual(self.block1, [self.block3])
        self.assertPredecessorsEqual(self.block2, None)
        self.assertSuccessorsEqual(self.block2, [self.block3])
        self.assertPredecessorsEqual(self.block3, [self.block1, self.block2])

    def test_replace_predecessor(self):
        self.block1.add_predecessor(self.block1)
        self.block1.add_predecessor(self.block2)
        self.assertPredecessorsEqual(self.block1, [self.block2])
        self.assertSuccessorsEqual(self.block2, [self.block1])
        self.assertSuccessorsEqual(self.block3, None)

        self.block1.replace_predecessor(self.block2, self.block3)
        self.assertPredecessorsEqual(self.block1, [self.block3])
        self.assertSuccessorsEqual(self.block2, None)
        self.assertSuccessorsEqual(self.block3, [self.block1])

        self.block1.replace_predecessor(self.block3, self.block1)
        self.assertPredecessorsEqual(self.block1, None)
        self.assertSuccessorsEqual(self.block2, None)
        self.assertSuccessorsEqual(self.block3, None)

        # Ensure error when trying to replace non-existant predecessor.
        with self.assertRaises(ValueError) as context:
            self.block1.replace_predecessor(self.block3, self.block1)

        # Before: Block 1 <-- Block2 <-- Block3
        # After: Block1 <-- Block3 and Block2 <-- Block3
        self.block1.add_predecessor(self.block2)
        self.block2.add_predecessor(self.block3)
        self.block1.replace_predecessor(self.block2, self.block3)
        self.assertPredecessorsEqual(self.block1, [self.block3])
        self.assertSuccessorsEqual(self.block2, None)
        self.assertPredecessorsEqual(self.block2, [self.block3])
        self.assertSuccessorsEqual(self.block3, [self.block1, self.block2])

    def test_remove_successor(self):
        self.block1.add_successor(self.block1)
        self.block1.add_successor(self.block2)
        self.block1.add_successor(self.block3)
        self.assertSuccessorsEqual(self.block1, [self.block2, self.block3])
        self.assertPredecessorsEqual(self.block2, [self.block1])
        self.assertPredecessorsEqual(self.block3, [self.block1])

        self.block1.remove_successor(self.block2)
        self.assertSuccessorsEqual(self.block1, [self.block3])
        self.assertPredecessorsEqual(self.block2, None)
        self.assertPredecessorsEqual(self.block3, [self.block1])

        self.block1.remove_successor(self.block1)
        self.assertSuccessorsEqual(self.block1, [self.block3])
        self.assertPredecessorsEqual(self.block2, None)
        self.assertPredecessorsEqual(self.block3, [self.block1])

        self.block1.remove_successor(self.block3)
        self.assertSuccessorsEqual(self.block1, None)
        self.assertPredecessorsEqual(self.block2, None)
        self.assertPredecessorsEqual(self.block3, None)

    def test_remove_predecessor(self):
        self.block1.add_predecessor(self.block1)
        self.block1.add_predecessor(self.block2)
        self.block1.add_predecessor(self.block3)
        self.assertPredecessorsEqual(self.block1, [self.block2, self.block3])
        self.assertSuccessorsEqual(self.block2, [self.block1])
        self.assertSuccessorsEqual(self.block3, [self.block1])

        self.block1.remove_predecessor(self.block2)
        self.assertPredecessorsEqual(self.block1, [self.block3])
        self.assertSuccessorsEqual(self.block2, None)
        self.assertSuccessorsEqual(self.block3, [self.block1])

        self.block1.remove_predecessor(self.block1)
        self.assertPredecessorsEqual(self.block1, [self.block3])
        self.assertSuccessorsEqual(self.block2, None)
        self.assertSuccessorsEqual(self.block3, [self.block1])

        self.block1.remove_predecessor(self.block3)
        self.assertPredecessorsEqual(self.block1, None)
        self.assertSuccessorsEqual(self.block2, None)
        self.assertSuccessorsEqual(self.block3, None)

    def test_destroy(self):
        self.block1.set_successors([self.block2, self.block3])
        self.block2.add_successor(self.block4)
        self.block3.add_successor(self.block4)

        self.block3.destroy()
        self.assertSuccessorsEqual(self.block1, [self.block2])
        self.assertPredecessorsEqual(self.block3, None)
        self.assertSuccessorsEqual(self.block3, None)
        self.assertPredecessorsEqual(self.block4, [self.block2])

        self.block2.destroy()
        self.assertSuccessorsEqual(self.block1, None)
        self.assertPredecessorsEqual(self.block3, None)
        self.assertSuccessorsEqual(self.block3, None)
        self.assertPredecessorsEqual(self.block4, None)

    def test_get_instruction(self):
        instr = Instruction(lineno=1)
        instr.referenced.add('varA')
        instr.defined.add('varB')
        self.block1.add_instruction(instr)

        result = self.block1.get_instruction(lineno=1)
        self.assertEqual(result.lineno, instr.lineno)
        self.assertEqual(result.referenced, instr.referenced)
        self.assertEqual(result.defined, instr.defined)
        self.assertFalse(self.block1.get_instruction(lineno=2))

    def test_get_instruction_linenos(self):
        self.assertFalse(self.block1.get_instruction_linenos())
        self.block1.add_definition(lineno=1, variable='varB')
        self.block1.add_definition(lineno=2, variable='varA')
        self.assertEqual(self.block1.get_instruction_linenos(), set([1, 2]))

    def test_get_instructions(self):
        self.block1.add_reference(lineno=2, variable='varA')
        self.block1.add_definition(lineno=1, variable='varA')

        instructions = self.block1.get_instructions()
        self.assertEqual(instructions[0].lineno, 1)
        self.assertEqual(instructions[1].lineno, 2)

    def test_get_last_instruction(self):
        self.assertFalse(self.block1.get_instruction_linenos())
        self.block1.add_definition(lineno=1, variable='varB')
        self.block1.add_definition(lineno=2, variable='varA')
        self.assertEqual(self.block1.get_last_instruction(), 2)

    def test_get_first_successor(self):
        self.block1.set_successors([self.block2, self.block3])
        successor = self.block1.get_first_successor()
        self.assertEqual(successor, self.block2)

        self.block1.remove_successor(successor)
        successor = self.block1.get_first_successor()
        self.assertEqual(successor, self.block3)

        self.block1.remove_successor(successor)
        successor = self.block1.get_first_successor()
        self.assertEqual(successor, None)

    def test_get_first_predecessor(self):
        self.block1.add_predecessor(self.block2)
        self.block1.add_predecessor(self.block3)
        predecessor = self.block1.get_first_predecessor()
        self.assertEqual(predecessor, self.block2)

        self.block1.remove_predecessor(predecessor)
        predecessor = self.block1.get_first_predecessor()
        self.assertEqual(predecessor, self.block3)

        self.block1.remove_predecessor(predecessor)
        predecessor = self.block1.get_first_predecessor()
        self.assertEqual(predecessor, None)