Skip to content

Conversation

@xdegaye
Copy link
Contributor

@xdegaye xdegaye commented Feb 27, 2018

sys.settrace(None)
self.compare_jump_output([2, 3, 2, 3, 4], namespace["output"])

def test_no_jump_from_call(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could tests use the jump_test() decorator?

* Forbidding jumps from the 'call' event of a new frame is a side effect
* of allowing to set f_lineno only from trace functions. */
if (f->f_lasti == -1)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please left this brace on the same line as if to conform PEP 7.

/* The trace function is called with a 'return' trace event after the
* execution of a yield statement. */
assert(f->f_lasti != -1);
if (code[f->f_lasti] == YIELD_VALUE || code[f->f_lasti] == YIELD_FROM) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a need to check for RETURN_VALUE as in your original patch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only function called by _PyEval_EvalFrameDefault() that may allow a jump to another line is maybe_call_line_trace() because stack_pointer is saved on f->f_stacktop before the call and there is a JUMPTO(f->f_lasti) after the call. All the other trace functions called within _PyEval_EvalFrameDefault() are called with f->f_stacktop == NULL except after the handling of the YIELD_FROM and YIELD_VALUE opcodes. So by forbidding jumps in frame_setlineno() when f->f_stacktop == NULL we handle all the cases, including the RETURN_VALUE opcode, except the yield statements. The check for RETURN_VALUE in my original patch was overkill.

Fix also a bug in the previous implementation of the PR where
jumpFrom/jumpTo were systematically incremented by 1 by the
jump_test() decorator without taking into account that
JumpTracer allows now jumpFrom/jumpTo from within nested
functions.
@serhiy-storchaka
Copy link
Member

Thank you @xdegaye! This is very nice PR. I like how it fixes the non-trivial bug. I have learned something new when reading it.

But I don't like the complexity of the new implementation of the trace function and the fact that it breaks one existing test. This code looks complicated and fragile. I afraid that it will be hard to modify it for supporting new tests or fix it if some details of frames or code objects will be changed. If in some implementation list.append() is implemented in Python this will break tests since the tracer will be confused by new frames.

I suggest to use the following implementation:

    def trace(self, frame, event, arg):
        if self.done:
            return
        if (self.firstLine is None and frame.f_code == self.code and
                event == 'line'):
            self.firstLine = frame.f_lineno - 1
        if (event == self.event and self.firstLine and
                frame.f_lineno == self.firstLine + self.jumpFrom):
            f = frame
            while f is not None and f.f_code != self.code:
                f = f.f_back
            if f is not None:
                try:
                    frame.f_lineno = self.firstLine + self.jumpTo
                except TypeError:
                    frame.f_lineno = self.jumpTo
                self.done = True
        return self.trace

and in the constructor:

        self.firstLine = None if decorated else self.code.co_firstlineno

test_jump_forwards_out_of_with_block can be restored, and two new test should be written as:

    @jump_test(2, 3, [1], event='call', error=(ValueError, "can't jump from"
               " the 'call' trace event of a new frame"))
    def test_no_jump_from_call(output):
        output.append(1)
        def nested():
            output.append(3)
        nested()
        output.append(5)

    @jump_test(3, 2, [2], event='return', error=(ValueError,
               "can't jump from a yield statement"))
    def test_no_jump_from_yield(output):
        def gen():
            output.append(2)
            yield 3
        next(gen())
        output.append(5)

Line numbers are always relative to the first line of the testing function which is determined by the first executed line if decorated is true.

@xdegaye
Copy link
Contributor Author

xdegaye commented Mar 12, 2018

@serhiy-storchaka thanks, this is so much simpler. I have updated the PR with your suggestion.

Copy link
Member

@serhiy-storchaka serhiy-storchaka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @xdegaye!

I have removed comments for brevity in the example. Could you please restore the old comment about non-integer jumpTo? Or maybe even add new comments to non-trivial code?

@xdegaye
Copy link
Contributor Author

xdegaye commented Mar 12, 2018

@serhiy-storchaka comments have been restored in the last commit.

@serhiy-storchaka serhiy-storchaka merged commit e32bbaf into python:3.7 Mar 13, 2018
@serhiy-storchaka serhiy-storchaka added type-bug An unexpected behavior, bug, or error needs backport to 3.6 labels Mar 13, 2018
@miss-islington
Copy link
Contributor

Thanks @xdegaye for the PR, and @serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 3.6.
🐍🍒⛏🤖

@serhiy-storchaka
Copy link
Member

Great! Could you please create a backport to master?

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Mar 13, 2018
@bedevere-bot
Copy link

GH-6100 is a backport of this pull request to the 3.6 branch.

@miss-islington
Copy link
Contributor

Thanks @xdegaye for the PR, and @serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 2.7.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Sorry, @xdegaye and @serhiy-storchaka, I could not cleanly backport this to 2.7 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker e32bbaf376a09c149fa7c7f2919d7c9ce4e2a055 2.7

miss-islington added a commit that referenced this pull request Mar 13, 2018
@xdegaye xdegaye deleted the bpo-17288 branch March 13, 2018 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type-bug An unexpected behavior, bug, or error

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants