Skip to content

LOAD_GLOBAL instruction with wrong source position #91409

Closed

Description

@15r10nk
mannequin
BPO 47253
Nosy @15r10nk
Files
  • test3.py: code which shows the problem
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2022-04-07.21:05:52.344>
    labels = ['type-bug', '3.11']
    title = 'LOAD_GLOBAL instruction with wrong source position'
    updated_at = <Date 2022-04-07.21:05:52.344>
    user = 'https://github.com/15r10nk'

    bugs.python.org fields:

    activity = <Date 2022-04-07.21:05:52.344>
    actor = '15r10nk'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = []
    creation = <Date 2022-04-07.21:05:52.344>
    creator = '15r10nk'
    dependencies = []
    files = ['50727']
    hgrepos = []
    issue_num = 47253
    keywords = []
    message_count = 1.0
    messages = ['416945']
    nosy_count = 1.0
    nosy_names = ['15r10nk']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = None
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue47253'
    versions = ['Python 3.11']

    Activity

    1. 15r10nk commented on Apr 7, 2022

      15r10nkmannequin
      MannequinAuthor

      The LOAD_GLOBAL instruction has a different/wrong source position if it refers the name of an imported module.

    2. added
      3.11only security fixes
      type-bugAn unexpected behavior, bug, or error
      on Apr 7, 2022
    3. transferred this issue fromon Apr 10, 2022
    4. terryjreedy commented on Apr 15, 2022

      @terryjreedy
      Member

      You should have pasted in the actual position tuples you saw that show the presumed bug.
      With 3.11.0a7, released 10 days ago, just before your report, the positions are identical (on Win 10).

      >>> import dis
      >>> dix=dis
      >>> def f():
      ...     dis.b()
      ...     dix.b()
      ...
      >>> for i in dis.Bytecode(f):
      ...     if i.opname == "LOAD_GLOBAL":
      ...         print(i.starts_lines, i.positions)
      ...   
      2 Positions(lineno=2, end_lineno=2, col_offset=4, end_col_offset=7)
      3 Positions(lineno=2, end_lineno=2, col_offset=4, end_col_offset=7)
      

      I don't know why the Positions.lineno does not match starts_lines, but your report is about columns. Here they match.
      I am presuming that you used an earlier alpha and that the OS does not matter and that this was recently discovered and fixed.
      Reopen if I missed something

    5. 15r10nk commented on Jul 16, 2022

      @15r10nk
      ContributorAuthor

      @terryjreedy The problem seems is be back in 3.11.0b4 (on ubuntu)

      import dis
      
      dix = 5
      
      
      def f():
          dis.b()  # wrong source range
          dix.b()  # correct source range
      
      
      d = [bc for bc in dis.Bytecode(f) if bc.opname == "LOAD_GLOBAL"]
      
      print(d)
      
      assert len(d) == 2
      
      # LOAD_GLOBAL has a wrong end column if the global value is an imported module
      assert d[0].positions[2:] == d[1].positions[2:] == (4, 7)

      output:

      [Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='dis', argrepr='NULL + dis', offset=2, starts_line=7, is_jump_target=False, positions=Positions(lineno=7, end_lineno=7, col_offset=4, end_col_offset=9))
      , Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='dix', argrepr='dix', offset=40, starts_line=8, is_jump_target=False, positions=Positions(lineno=8, end_lineno=8, col_offset=4, end_col_offset=7))]
      Traceback (most recent call last):
        File "/home/frank/projects/executing/test2.py", line 18, in <module>
          assert d[0].positions[2:] == d[1].positions[2:] == (4, 7)
      AssertionError
      

      can we open this issue again?

    6. terryjreedy commented on Jul 16, 2022

      @terryjreedy
      Member

      You changed from 'global name is an imported module name' to 'global object is an imported module. I revised by example to cover both and ran with freshly updated and compiled 'main' and '3.11' and installed 3.11.0b4'.

      import dis
      dix = dis
      dum = 5
      def f(): dis, dix, dum
      
      for i in dis.Bytecode(f):
          if i.opname == "LOAD_GLOBAL":
              print(i.positions)
      

      Output on Win 10:

      Positions(lineno=4, end_lineno=4, col_offset=9, end_col_offset=12)
      Positions(lineno=4, end_lineno=4, col_offset=14, end_col_offset=17)
      Positions(lineno=4, end_lineno=4, col_offset=19, end_col_offset=22)
      

      For all 3 names, end - start == 3. Same with each on separate line.

      Please run a pasted copy of the code above on your machine. If output is different, paste a copy.
      If same but minimal editing gives anomaly, paste code and output.

    7. 15r10nk commented on Jul 17, 2022

      @15r10nk
      ContributorAuthor

      I got the same results like you and there are no problems if we only lookup the global variable.
      Sorry for my wording error. I hope this Example will make it clear what I mean.

      The source range extends to the name of the called function if we call an function on a imported module.

      import dis
      dix = dis
      dum = 5
      def f():
          dis.a()
          dis.abc()
          dis.a
          dis
          dix.a()
          dum.abc()
      
      for i in dis.Bytecode(f):
          if i.opname == "LOAD_GLOBAL":
              print(i.positions)

      output:

      Positions(lineno=5, end_lineno=5, col_offset=4, end_col_offset=9)
      Positions(lineno=6, end_lineno=6, col_offset=4, end_col_offset=11)
      Positions(lineno=7, end_lineno=7, col_offset=4, end_col_offset=7)
      Positions(lineno=8, end_lineno=8, col_offset=4, end_col_offset=7)
      Positions(lineno=9, end_lineno=9, col_offset=4, end_col_offset=7)
      Positions(lineno=10, end_lineno=10, col_offset=4, end_col_offset=7)
      

      you can see that the method name gets included in the range. This should be not the case in my opinion. Or are there any reasons for this Behaviour? There is also no Problem for attribute lookups like dis.a.

      I also bisected the bahavior change down to 3011a097bd. Maybe this helps.

    8. terryjreedy commented on Jul 17, 2022

      @terryjreedy
      Member

      @markshannon @pablogsal LOAD_GLOBAL of a name bound by import has an erroneous end_col_offset if followed by LOAD_METHOD and calls. OP bisected to #31933, 3011a097bd. (15... Thanks for doing that.)

      Tests in additional to those already posted above:

      import dis, abc
      import ast as art
      dix = dis
      ast = art
      
      def f():
          dix.a()  # Is first name affected if not bound name? (No.)
          dis.a()  # Is bound-file name affected if not first? (Yes.)
          abc.a()  # Are names other than 'dis' affected?  (Yes.)
          art.a()  # Is bound name not file name affected? (Yes.)
          ast.a()  # Is file name not bound name affected?  (No.)
      
      for i in dis.Bytecode(f):
          if i.opname == "LOAD_GLOBAL":
              print(f'{i.opname:12s}', i.positions)
      

      outputs

      LOAD_GLOBAL  Positions(lineno=8, end_lineno=8, col_offset=4, end_col_offset=7)
      LOAD_GLOBAL  Positions(lineno=9, end_lineno=9, col_offset=4, end_col_offset=9)
      LOAD_GLOBAL  Positions(lineno=10, end_lineno=10, col_offset=4, end_col_offset=9)
      LOAD_GLOBAL  Positions(lineno=11, end_lineno=11, col_offset=4, end_col_offset=9)
      LOAD_GLOBAL  Positions(lineno=12, end_lineno=12, col_offset=4, end_col_offset=7)
      
    9. self-assigned this
      on Jul 20, 2022
    10. added 3 commits that reference this issue on Jul 20, 2022
    11. terryjreedy commented on Jul 20, 2022

      @terryjreedy
      Member

      Thank you Brandt for the nice fix and tests.
      @15r10nk Thank you for persisting through the fog so we fixed a real bug which would surely have bitten someone if released.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    Labels

    3.11only security fixes3.12only security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions