Exemplo n.º 1
0
def test_cfg_return_statement_inside_branch():
    fdump = f'stdin.dump.json'
    checker_warnings, rc = check_program(
        """
        FUNCTION test_return_nested : INT
        VAR i : INT; a : INT; END_VAR
        IF i = 0 THEN
          a := a + 1;
          RETURN;
          a := a + 2;
        END_IF;
        a := a + 3;
        END_FUNCTION
        """.replace('\n', ''))
    assert rc == 0
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
        assert len(scheme.functions) == 1
        assert len(scheme.cfgs) == 1
        cfg = scheme.cfgs[0]
        bbs = cfg.basic_blocks
        assert len(bbs) == 4
        # if
        # i = 0
        assert bbs[0].id == 0
        assert bbs[0].type == "BBEntry"
        assert bbs[0].preds == set()
        assert bbs[0].succs == {1, 3}
        # a := a + 1
        # RETURN
        assert bbs[1].id == 1
        assert bbs[1].type == "BBExit"
        assert bbs[1].preds == {0}
        assert bbs[1].succs == set()
        # a := a + 2
        assert bbs[2].id == 2
        assert bbs[2].type == "BB"
        assert bbs[2].preds == set()
        assert bbs[2].succs == {3}
        # a := a + 3
        assert bbs[3].id == 3
        assert bbs[3].type == "BBExit"
        assert bbs[3].preds == {0, 2}
        assert bbs[3].succs == set()
Exemplo n.º 2
0
def test_struct_types():
    fdump = f'stdin.dump.json'
    checker_warnings, rc = check_program("""
        TYPE
          Cooler: STRUCT
            Temp: INT;
            Cooling: TOF;
          END_STRUCT;
        END_TYPE
        """.replace('\n', ''))
    assert rc == 0
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
        assert len(scheme.types) == 1
        ty = scheme.types[0]
        assert ty.name == 'COOLER'
        assert ty.type == 'Struct'
Exemplo n.º 3
0
def test_cfa_multiple_pous():
    fdump = f'stdin.dump.json'
    warns, rc = check_program("""
        FUNCTION dead_code_after_return_1 : INT
          VAR some_var : INT; END_VAR
          RETURN;
          some_var := SQRT(16#42); (* UnreachableCode error *)
        END_FUNCTION

        FUNCTION dead_code_after_return_2 : INT
          VAR some_var : INT; END_VAR
          RETURN;
          some_var := SQRT(16#42); (* UnreachableCode error *)
        END_FUNCTION
        """.replace('\n', ''))
    assert rc == 0
    assert len(filter_warns(warns, 'PLCOPEN-CP2')) == 2
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
def test_array_initialized_list():
    fdump = f'stdin.dump.json'
    warns, rc = check_program("""
        TYPE BITS: ARRAY [1..2, 1..3] OF BOOL := [0,0,0,0,0,0,1,1,1]; END_TYPE
        PROGRAM test_p
          VAR
            ARR1: ARRAY [1..2, 1..3] OF BOOL := [0,0,0,0,0,0,1,1,1];
          END_VAR
          ARR1[1] := 19;
        END_PROGRAM
        """.replace('\n', ''))
    assert rc == 0
    assert len(warns) >= 2
    oob_warns = filter_warns(warns, 'OutOfBounds')
    assert len(oob_warns) == 2
    for w in oob_warns:
        assert w.id == 'OutOfBounds'
        assert '3 values will be lost' in w.msg
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
        assert len(scheme.types) == 1
Exemplo n.º 5
0
def test_cfa_dead_code_top_statements():
    fdump = f'stdin.dump.json'
    warns, rc = check_program("""
        FUNCTION test_dead_code_to_stmts : INT
          VAR
            counter : INT := 0;
            some_var : INT;
          END_VAR
          counter := counter + 1;
          counter := 2 + 2;
          RETURN;
          some_var := SQRT(16#42); (* UnreachableCode error *)
          some_var := 16#42; (* No additional warnings *)
          some_var := 19;
        END_FUNCTION
        """.replace('\n', ''))
    assert rc == 0
    assert len(warns) >= 1
    assert len(filter_warns(warns, 'PLCOPEN-CP2')) == 1
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
Exemplo n.º 6
0
def test_cfg_single_continue_in_the_first_bb():
    fdump = f'stdin.dump.json'
    checker_warnings, rc = check_program(
        """
        PROGRAM test_continue
        VAR a : INT; i : INT; END_VAR
        WHILE i < 10 DO
          IF i = 5 THEN
            CONTINUE;
          END_IF;
          i := i + 2;
        END_WHILE;
        i := 0;
        END_PROGRAM
        """.replace('\n', ''))
    assert rc == 0
    with DumpManager(fdump) as dm:
        bbs = dm.scheme.cfgs[0].basic_blocks
        assert len(bbs) == 5
        assert bbs[0].preds == {2, 3}
        assert bbs[2].succs == {0}
        assert len(bbs[2].stmt_ids) == 1
Exemplo n.º 7
0
def test_cfg_repeat_statement():
    fdump = f'stdin.dump.json'
    checker_warnings, rc = check_program(
        """
        PROGRAM test_repeat
        VAR j : INT := 0; END_VAR
        REPEAT
          j := j + 2;
          UNTIL j < 100
        END_REPEAT;
        j := 0;
        END_PROGRAM
        """.replace('\n', ''))
    assert rc == 0
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
        assert len(scheme.programs) == 1
        assert len(scheme.cfgs) == 1
        cfg = scheme.cfgs[0]
        bbs = cfg.basic_blocks
        assert len(bbs) == 3
        # repeat
        assert bbs[0].id == 0
        assert bbs[0].type == "BBEntry"
        assert bbs[0].preds == {1}
        assert bbs[0].succs == {1}
        # j := j + 2
        # until
        # j < 100
        assert bbs[1].id == 1
        assert bbs[1].type == "BB"
        assert bbs[1].preds == {0}
        assert bbs[1].succs == {0, 2}
        # j := 0
        assert bbs[2].id == 2
        assert bbs[2].type == "BBExit"
        assert bbs[2].preds == {1}
        assert bbs[2].succs == set()
Exemplo n.º 8
0
def test_cfg_for_statement():
    fdump = f'stdin.dump.json'
    checker_warnings, rc = check_program(
        """
        PROGRAM test_for
        VAR a : INT; i : INT; END_VAR
        FOR i := 0 TO 10 BY 2 DO
          a := a + i;
          a := a + 1;
        END_FOR;
        i := 0;
        END_PROGRAM
        """.replace('\n', ''))
    assert rc == 0
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
        assert len(scheme.programs) == 1
        assert len(scheme.cfgs) == 1
        cfg = scheme.cfgs[0]
        bbs = cfg.basic_blocks
        assert len(bbs) == 3
        # for
        # i := 0
        assert bbs[0].id == 0
        assert bbs[0].type == "BBEntry"
        assert bbs[0].preds == {1}
        assert bbs[0].succs == {1, 2}
        # a := a + i
        # a := a + 1
        assert bbs[1].id == 1
        assert bbs[1].type == "BB"
        assert bbs[1].preds == {0}
        assert bbs[1].succs == {0}
        # i := 0
        assert bbs[2].id == 2
        assert bbs[2].type == "BBExit"
        assert bbs[2].preds == {0}
        assert bbs[2].succs == set()
Exemplo n.º 9
0
def test_cfg_while_statement():
    fdump = f'stdin.dump.json'
    checker_warnings, rc = check_program(
        """
        PROGRAM test_while
        VAR a : INT; i : INT; END_VAR
        WHILE i <= 10 DO
          a := i + 2;
          i := i - 1;
        END_WHILE;
        i := 0;
        END_PROGRAM
        """.replace('\n', ''))
    assert rc == 0
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
        assert len(scheme.programs) == 1
        assert len(scheme.cfgs) == 1
        cfg = scheme.cfgs[0]
        bbs = cfg.basic_blocks
        assert len(bbs) == 3
        # while
        # i <= 10
        assert bbs[0].id == 0
        assert bbs[0].type == "BBEntry"
        assert bbs[0].preds == {1}
        assert bbs[0].succs == {1, 2}
        # a := i + 2
        # i := i - 1
        assert bbs[1].id == 1
        assert bbs[1].type == "BB"
        assert bbs[1].preds == {0}
        assert bbs[1].succs == {0}
        # i := 0
        assert bbs[2].id == 2
        assert bbs[2].type == "BBExit"
        assert bbs[2].preds == {0}
        assert bbs[2].succs == set()
Exemplo n.º 10
0
def test_cfg_single_return_statement():
    fdump = f'stdin.dump.json'
    checker_warnings, rc = check_program(
        """
        FUNCTION test_single_return : INT
        VAR A : INT; END_VAR
        RETURN;
        END_FUNCTION
        """.replace('\n', ''))
    assert rc == 0
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
        assert len(scheme.functions) == 1
        assert len(scheme.cfgs) == 1
        cfg = scheme.cfgs[0]
        bbs = cfg.basic_blocks
        assert len(bbs) == 1
        # RETURN
        assert bbs[0].id == 0
        assert bbs[0].type == "BBExit"
        assert bbs[0].preds == set()
        assert bbs[0].succs == set()
Exemplo n.º 11
0
def test_cfg_single_bb_has_exit_type():
    fdump = f'stdin.dump.json'
    checker_warnings, rc = check_program(
        """
        PROGRAM f
        VAR a : INT; END_VAR
        a := 1;
        END_PROGRAM
        """.replace('\n', ''))
    assert rc == 0
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
        assert len(scheme.programs) == 1
        assert len(scheme.cfgs) == 1
        cfg = scheme.cfgs[0]
        bbs = cfg.basic_blocks
        assert len(bbs) == 1
        # a := 1
        assert bbs[0].id == 0
        assert bbs[0].type == "BBExit"
        assert bbs[0].preds == set()
        assert bbs[0].succs == set()
Exemplo n.º 12
0
def test_cfg_no_condition_self_reference():
    fdump = f'stdin.dump.json'
    checker_warnings, rc = check_program(
        """
        PROGRAM p
        VAR a : INT; i : INT; END_VAR
        a := 1;
        IF a > 1 THEN
            i := 1;
        END_IF;
        a := 2;
        END_PROGRAM
        """.replace('\n', ''))
    assert rc == 0
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme and len(scheme.cfgs) == 1
        cfg = scheme.cfgs[0]
        bbs = cfg.basic_blocks
        assert len(bbs) == 3
        # a := 1
        # if ... then
        # a > 1
        assert bbs[0].preds == set()
Exemplo n.º 13
0
def test_use_define_array():
    fdump = f'stdin.dump.json'
    warns, rc = check_program("""
        PROGRAM test_arr_len
          VAR
            ARR1: ARRAY [1..2] OF BOOL;
          END_VAR
          ARR1[0] := 19; (* error *)
          ARR1[1] := 19; (* no false positive *)
          ARR1[2] := 19; (* no false positive *)
          ARR1[3] := 19; (* error *)
          ARR1[2,1] := 19; (* error *)
        END_PROGRAM
        """.replace('\n', ''))
    assert rc == 0
    assert len(warns) >= 3
    ws = filter_warns(warns, 'OutOfBounds')
    assert len(ws) == 3
    assert "index 0 is out" in ws[0].msg
    assert "index 3 is out" in ws[1].msg
    assert "addressed to 2 dimension" in ws[2].msg
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
Exemplo n.º 14
0
def test_cfg_exit_continue():
    fdump = f'stdin.dump.json'
    checker_warnings, rc = check_program(
        """
        PROGRAM test_exit_continue
        VAR a : INT; i : INT; END_VAR
        WHILE i <= 10 DO
          IF i = 5 THEN
            i := i + 1;
            EXIT;
          ELSIF i = 6 THEN
            CONTINUE;
            i := 3;
          END_IF;
          i := i + 2;
        END_WHILE;
        i := 0;
        END_PROGRAM
        """.replace('\n', ''))
    assert rc == 0
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
        assert len(scheme.programs) == 1
        assert len(scheme.cfgs) == 1
        cfg = scheme.cfgs[0]
        bbs = cfg.basic_blocks
        assert len(bbs) == 8
        # while
        # i <= 10
        assert bbs[0].id == 0
        assert bbs[0].type == "BBEntry"
        assert bbs[0].preds == {4, 6}
        assert bbs[0].succs == {1, 7}
        # if
        # i = 5
        assert bbs[1].id == 1
        assert bbs[1].type == "BB"
        assert bbs[1].preds == {0}
        assert bbs[1].succs == {2, 3}
        # i := i + 1
        # exit
        assert bbs[2].id == 2
        assert bbs[2].type == "BB"
        assert bbs[2].preds == {1}
        assert bbs[2].succs == {7}
        assert len(bbs[2].stmt_ids) == 2
        # elsif
        # i = 6
        assert bbs[3].id == 3
        assert bbs[3].type == "BB"
        assert bbs[3].preds == {1}
        assert bbs[3].succs == {4, 6}
        # continue
        assert bbs[4].id == 4
        assert bbs[4].type == "BB"
        assert bbs[4].preds == {3}
        assert bbs[4].succs == {0}
        # i := 3
        assert bbs[5].id == 5
        assert bbs[5].type == "BB"
        assert bbs[5].preds == set()
        assert bbs[5].succs == {6}
        # i := i + 2
        assert bbs[6].id == 6
        assert bbs[6].type == "BB"
        assert bbs[6].preds == {5, 3}
        assert bbs[6].succs == {0}
        # i := 0
        assert bbs[7].id == 7
        assert bbs[7].type == "BBExit"
        assert bbs[7].preds == {0, 2}
        assert bbs[7].succs == set()
Exemplo n.º 15
0
def test_cfg_case_statement():
    fdump = f'stdin.dump.json'
    checker_warnings, rc = check_program(
        """
        PROGRAM case_test
        VAR a : INT; END_VAR
        CASE a OF
          1 : a := 3;
          2 : a := 5;
          3,4 : a := 42;
        ELSE a := 19;
             a := 20;
        END_CASE;
        a := 0;
        END_PROGRAM
        """.replace('\n', ''))
    assert rc == 0
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
        assert len(scheme.programs) == 1
        assert len(scheme.cfgs) == 1
        cfg = scheme.cfgs[0]
        bbs = cfg.basic_blocks
        assert len(bbs) == 9
        # (switch) case .. of
        # a
        assert bbs[0].id == 0
        assert bbs[0].type == "BBEntry"
        assert bbs[0].preds == set()
        assert bbs[0].succs == {1}
        # (case) 1
        assert bbs[1].id == 1
        assert bbs[1].type == "BB"
        assert bbs[1].preds == {0}
        assert bbs[1].succs == {2, 3}
        # a := 3
        assert bbs[2].id == 2
        assert bbs[2].type == "BB"
        assert bbs[2].preds == {1}
        assert bbs[2].succs == {8}
        # (case) 2
        assert bbs[3].id == 3
        assert bbs[3].type == "BB"
        assert bbs[3].preds == {1}
        assert bbs[3].succs == {4, 5}
        # a := 5
        assert bbs[4].id == 4
        assert bbs[4].type == "BB"
        assert bbs[4].preds == {3}
        assert bbs[4].succs == {8}
        # (case) 3
        # (case) 4
        assert bbs[5].id == 5
        assert bbs[5].type == "BB"
        assert bbs[5].preds == {3}
        assert bbs[5].succs == {6, 7}
        # a := 42
        assert bbs[6].id == 6
        assert bbs[6].type == "BB"
        assert bbs[6].preds == {5}
        assert bbs[6].succs == {8}
        # (else)
        # a := 19
        # a := 20
        assert bbs[7].id == 7
        assert bbs[7].type == "BB"
        assert bbs[7].preds == {5}
        assert bbs[7].succs == {8}
        # a := 0
        assert bbs[8].id == 8
        assert bbs[8].type == "BBExit"
        assert bbs[8].preds == {2, 4, 6, 7}
        assert bbs[8].succs == set()
Exemplo n.º 16
0
def test_cfg_if_elsif():
    fdump = f'stdin.dump.json'
    checker_warnings, rc = check_program(
        """
        PROGRAM f
        VAR a : INT; i : INT; END_VAR
        a := 1;
        IF a > 1 THEN
            i := 1;
        ELSIF a > 2 THEN
            i := 2;
        ELSIF a > 3 THEN
            i := 3;
        END_IF;
        i := 0;
        END_PROGRAM
        """.replace('\n', ''))
    assert rc == 0
    with DumpManager(fdump) as dm:
        scheme = dm.scheme
        assert scheme
        assert len(scheme.programs) == 1
        assert len(scheme.cfgs) == 1
        cfg = scheme.cfgs[0]
        bbs = cfg.basic_blocks
        assert len(bbs) == 7
        # a := 1
        # if ... then
        # a > 1
        assert bbs[0].id == 0
        assert bbs[0].type == "BBEntry"
        assert bbs[0].preds == set()
        assert bbs[0].succs == {1, 2}
        # i := 1
        assert bbs[1].id == 1
        assert bbs[1].type == "BB"
        assert bbs[1].preds == {0}
        assert bbs[1].succs == {6}
        # elsif ... then
        # a > 2
        assert bbs[2].id == 2
        assert bbs[2].type == "BB"
        assert bbs[2].preds == {0}
        assert bbs[2].succs == {3, 4}
        # i := 2
        assert bbs[3].id == 3
        assert bbs[3].type == "BB"
        assert bbs[3].preds == {2}
        assert bbs[3].succs == {6}
        # elsif ... then
        # a > 3
        assert bbs[4].id == 4
        assert bbs[4].type == "BB"
        assert bbs[4].preds == {2}
        assert bbs[4].succs == {5, 6}
        # i := 3
        assert bbs[5].id == 5
        assert bbs[5].type == "BB"
        assert bbs[5].preds == {4}
        assert bbs[5].succs == {6}
        # i := 0
        assert bbs[6].id == 6
        assert bbs[6].type == "BBExit"
        assert bbs[6].preds == {1, 3, 4, 5}
        assert bbs[6].succs == set()