Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PyEval_SetTrace used in way that breaks sys.gettrace() #123

Closed
nedbat opened this issue Mar 20, 2011 · 2 comments
Closed

PyEval_SetTrace used in way that breaks sys.gettrace() #123

nedbat opened this issue Mar 20, 2011 · 2 comments
Labels
bug Something isn't working run

Comments

@nedbat
Copy link
Owner

nedbat commented Mar 20, 2011

Originally reported by Devin Jeanpierre (Bitbucket: devin.jeanpierre, GitHub: Unknown)


tl;dr: //sys.settrace(sys.gettrace())// breaks coverage by causing the trace function to raise an exception, and this is avoidable.

The (C extension) Tracer.c installs a trace function using PyEval_SetTrace, as opposed to the usual sys.settrace. This is problematic because unless PyEval_SetTrace is used in a very particular way (in particular, the way sys.settrace uses it), it will break sys.gettrace.

PyEval_SetTrace(func, self) is a C function that takes "func" and "self". "self" is passed as the first argument to func, which generally does something with it. With sys.settrace for example, self is a callable PyObject* that gets called by func. sys.gettrace is designed to work with sys.settrace, so sys.gettrace returns self.

coverage, however, takes "self" literally and passes the instance of Tracer, so that the tracer method involved with actually tracing execution can maintain state. So when sys.gettrace is called, it returns the instance of Tracer, which is not safe to pass back in to sys.settrace.

An executable example is attached, which fails when run under coverage, but succeeds when run normally.

There are two ways to fix this: either PyEval_SetTrace can be eschewed completely, in favor of sys.settrace, or else Tracer can be made callable appropriately. I'm not really familiar with the codebase of coverage (nor am I familiar with writing C extensions in general), but I think that making Tracer callable would be the simplest approach.

I'll probably work on a patch later, but first I want to investigate a bit more why doctest doesn't appear (at least with some minimal tests that I think I did a few days ago) to be bitten by this behavior: doctest gets the trace function with sys.gettrace(), and restores it later using sys.settrace(). Also, as I said before, I'm not incredibly familiar with the codebase or with writing C extensions.


@nedbat
Copy link
Owner Author

nedbat commented Mar 20, 2011

Original comment by Devin Jeanpierre (Bitbucket: devin.jeanpierre, GitHub: Unknown)


Alright, so I just looked into doctest. It turns out that only the most recent version of doctest does this, not the version included in 3.2. I'm not sure if coverage //ever// worked with doctest, though, so it's not like I can say "doctest will no longer work with coverage if you don't act soon!"

@nedbat
Copy link
Owner Author

nedbat commented Apr 27, 2011

Fixed in <<changeset ebca9c8e46a6 (bb)>>. Thanks!

@nedbat nedbat closed this as completed Apr 27, 2011
@nedbat nedbat added major bug Something isn't working run labels Jun 23, 2018
agronholm added a commit to agronholm/coveragepy that referenced this issue Aug 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working run
Projects
None yet
Development

No branches or pull requests

1 participant