kjo
kjo

Reputation: 35331

Python's debugger's step-through and free-running modes follow different execution paths

If I run the script

import sys
if sys.gettrace():
    print 'OK'
else:
    assert False, 'good grief'

...like this

% python -mpdb bugdemo.py

...(Python v. 2.7.8) I first see a prompt like this:

-> import sys
(Pdb)

If at this point, I repeatedly enter s to step through the script, I see something like this:

> <path-to-script>/bugdemo.py(2)<module>()
-> if sys.gettrace():
(Pdb) s
> <path-to-script>/bugdemo.py(3)<module>()
-> print "OK"
(Pdb) s
OK
--Return--
> <path-to-script>/bugdemo.py(3)<module>()->None
-> print "OK"
(Pdb)

But, if instead of stepping through the code, at the first debugger prompt I just enter c (short for cont, i.e. continue), the code's execution follows a different path:

% python -mpdb bugdemo.py
> <path-to-script>/bugdemo.py(1)<module>()
-> import sys
(Pdb) c
Traceback (most recent call last):
  File "/Users/yt/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pdb.py", line 1314, in main
    pdb._runscript(mainpyfile)
  File "/Users/yt/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pdb.py", line 1233, in _runscript
    self.run(statement)
  File "/Users/yt/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/bdb.py", line 387, in run
    exec cmd in globals, locals
  File "<string>", line 1, in <module>
  File "bugdemo.py", line 1, in <module>
    import sys
AssertionError: good grief
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
> <path-to-script>/bugdemo.py(1)<module>()
-> import sys
(Pdb)

Does anyone know what's going on here? Is this a bug1 that I should report? Or is there a way to rationalize it?


1If this is a bug, it is a whopper of a bug: a debugger that follows different execution paths in step-through and free-run is worse than useless.

Upvotes: 0

Views: 365

Answers (2)

ivan_pozdeev
ivan_pozdeev

Reputation: 36096

lib\bdb.py:227

def set_continue(self):
    # Don't stop except at breakpoints or when finished
    self._set_stopinfo(self.botframe, None, -1)
    if not self.breaks:
        # no breakpoints; run without debugger overhead
        sys.settrace(None)
        frame = sys._getframe().f_back
        while frame and frame is not self.botframe:
            del frame.f_trace
            frame = frame.f_back

I.e. pdb removes the trace function in some circumstances which is its private business. You try to outsmart it by checking its presence and thus shoot yourself in the foot. Congratulations on that.

Upvotes: 5

Jason C
Jason C

Reputation: 22087

The documentation for settrace and gettrace pretty clearly state the they are intended to be used to implement debuggers. Presumably pdb is using settrace, and when pdb isn't run beforehand, I would assume that gettrace returns None.

What were you expecting to happen? That pdb would set up an environment that would perfectly hide from you the fact that a debugger is there, even when you explicitly use functions that are intended as hooks for a debugger? I really don't think this is a bug. The docs linked above even say: (emphasis mine)

CPython implementation detail: The settrace() function is intended only for implementing debuggers, profilers, coverage tools and the like. Its behavior is part of the implementation platform, rather than part of the language definition, and thus may not be available in all Python implementations.

gettrace and settrace are odd little corners of the language intended for "magic" uses, like debuggers. If you don't know what they do, just don't call them.

Upvotes: 2

Related Questions