Lichen

Changeset

904:938887b82033
2019-06-02 Paul Boddie raw files shortlog changelog graph Prevent "null" usage of assigned names from escaping via the exception handler.
common.py (file) internal_tests/branches.py (file)
     1.1 --- a/common.py	Mon May 27 11:54:56 2019 +0200
     1.2 +++ b/common.py	Sun Jun 02 23:10:26 2019 +0200
     1.3 @@ -563,6 +563,8 @@
     1.4          self.next_temporary()
     1.5          t2 = self.get_temporary_name()
     1.6          self.next_temporary()
     1.7 +        t3 = self.get_temporary_name()
     1.8 +        self.next_temporary()
     1.9  
    1.10          node = compiler.ast.Stmt([
    1.11  
    1.12 @@ -583,9 +585,10 @@
    1.13              # try:
    1.14              #     while True:
    1.15              #         try:
    1.16 -            #             <var>... = <t2>()
    1.17 +            #             <t3> = <t2>()
    1.18              #         except StopIteration:
    1.19              #             raise LoopExit
    1.20 +            #         <var>... = <t3>
    1.21              #         {n.body}
    1.22              # except LoopExit:
    1.23              #     {n.else_}
    1.24 @@ -601,13 +604,16 @@
    1.25                      compiler.ast.Stmt([
    1.26                          compiler.ast.TryExcept(
    1.27                              compiler.ast.Assign(
    1.28 -                                [n.assign],
    1.29 +                                [compiler.ast.AssName(t3, "OP_ASSIGN")],
    1.30                                  compiler.ast.CallFunc(
    1.31                                      compiler.ast.Name(t2),
    1.32                                      [])),
    1.33                              [(compiler.ast.Name("StopIteration"), None,
    1.34                                compiler.ast.Raise(compiler.ast.Name("LoopExit")))],
    1.35                              None),
    1.36 +                        compiler.ast.Assign(
    1.37 +                            [n.assign],
    1.38 +                            compiler.ast.Name(t3)),
    1.39                          n.body]),
    1.40                      None),
    1.41                  [(compiler.ast.Name("LoopExit"), None, n.else_ or compiler.ast.Pass())],
     2.1 --- a/internal_tests/branches.py	Mon May 27 11:54:56 2019 +0200
     2.2 +++ b/internal_tests/branches.py	Sun Jun 02 23:10:26 2019 +0200
     2.3 @@ -687,4 +687,77 @@
     2.4      bt.get_assignment_positions_for_branches("a", ar)
     2.5  names.append(bt.assignments["a"])
     2.6  
     2.7 +# This demonstrates why the assignment in a "for" loop construct must appear
     2.8 +# outside the inner "try" body: null usage escapes the loop via the exception
     2.9 +# handler and the raise statement, even though the assignment would only be
    2.10 +# valid otherwise.
    2.11 +
    2.12 +# Equivalent to...
    2.13 +#
    2.14 +# try:
    2.15 +#   while ...:
    2.16 +#     try:
    2.17 +#       a = ...
    2.18 +#     except:
    2.19 +#       raise ...
    2.20 +#     a.p
    2.21 +# except:
    2.22 +#   pass
    2.23 +
    2.24 +bt = branching.BranchTracker()
    2.25 +bt.new_branchpoint()                # begin (try)
    2.26 +bt.new_branchpoint(True)            # begin (while)
    2.27 +bt.new_branch(True)                 # while ...
    2.28 +bt.new_branchpoint()                # begin (try)
    2.29 +a = bt.assign_names(["a"])
    2.30 +bt.resume_abandoned_branches()      # except
    2.31 +bt.abandon_branch()                 # raise
    2.32 +bt.shelve_branch()
    2.33 +bt.new_branch()                     # (null)
    2.34 +bt.shelve_branch()
    2.35 +bt.merge_branches()                 # end (try)
    2.36 +ap = bt.use_attribute("a", "p")
    2.37 +bt.resume_continuing_branches()
    2.38 +bt.shelve_branch(True)
    2.39 +bt.new_branch()                     # (null)
    2.40 +bt.shelve_branch()
    2.41 +bt.merge_branches()                 # end (while)
    2.42 +bt.resume_broken_branches()
    2.43 +bt.resume_abandoned_branches()      # except
    2.44 +bt.shelve_branch()
    2.45 +bt.new_branch()                     # (null)
    2.46 +bt.shelve_branch()
    2.47 +bt.merge_branches()                 # end (try)
    2.48 +
    2.49 +print simple_usage(a) == \
    2.50 +    {'a' : set([('p',), ()])}, simple_usage(a)
    2.51 +print bt.get_assignment_positions_for_branches("a", ap) == [0], \
    2.52 +    bt.get_assignment_positions_for_branches("a", ap)
    2.53 +names.append(bt.assignments["a"])
    2.54 +
    2.55 +# Equivalent to...
    2.56 +#
    2.57 +# b = ...
    2.58 +# while ...:
    2.59 +#   a = ...
    2.60 +#   a.p
    2.61 +
    2.62 +bt = branching.BranchTracker()
    2.63 +bt.new_branchpoint(True)            # begin
    2.64 +b = bt.assign_names(["b"])
    2.65 +bt.new_branch(True)                 # while ...
    2.66 +a = bt.assign_names(["a"])
    2.67 +ap = bt.use_attribute("a", "p")
    2.68 +bt.resume_continuing_branches()
    2.69 +bt.shelve_branch(True)
    2.70 +bt.new_branch()                     # (null)
    2.71 +bt.shelve_branch()
    2.72 +bt.merge_branches()                 # end
    2.73 +
    2.74 +print simple_usage(a) == \
    2.75 +    {'a' : set([('p',)])}, simple_usage(a)
    2.76 +print bt.get_assignment_positions_for_branches("a", ap) == [0], \
    2.77 +    bt.get_assignment_positions_for_branches("a", ap)
    2.78 +names.append(bt.assignments["a"])
    2.79 +
    2.80  # vim: tabstop=4 expandtab shiftwidth=4