16.8 Debugging Dynamically Loaded C Extensions with gdbCredit: Joseph VanAndel, Michael Aivazis 16.8.1 ProblemA dynamically loaded C/C++ Python extension is giving you trouble on Unix or a Unix-like platform, and you would like to use the interactive debugger gdb to find out more about what's wrong. 16.8.2 Solution
One way to find the cause of
% gdb /usr/bin/python2.1 (gdb) br _PyImport_LoadDynamicModule (gdb) cont # Repeat until your extension is loaded (gdb) finish # to load your extension (gdb) br wrap_myfunction # the entry point in your code (gdb) disable 1 # don't want to break for more modules being loaded (gdb) continue 16.8.3 Discussion
If a dynamically loaded C/C++ extension is causing Python to core dump, or
This technique works. However, if you often do this kind of thing, the process of stepping through all the modules, as Python loads them at startup, can easily become
The key idea of this handier alternative is to add a do-nothing function somewhere in the body of code that Python loads immediately. Specifically, you can edit the Modules/main.c file to include one new function:
void Py_DebugTrap(void) { }
In whatever extension you're debugging, add a call to Py_DebugTrap right where you want to break into the code. The Py_DebugTrap symbol is immediately available when you start gdb , because the symbol lives in main.c . So you can immediately set a breakpoint there when you are at the gdb prompt, then continue. This even works in parallel under MPI. 16.8.4 See AlsoThe gdb online documentation (just type help at the interactive prompt), manpages, and online manual (http://www.gnu.org/manual/gdb-4.17/gdb.html). |
16.9 Debugging Memory ProblemsCredit: Will Ware 16.9.1 ProblemYou're developing C extensions, and you experience memory problems. You suspect mismanagement of reference counts and want to check whether your C extension code is managing reference counts correctly. 16.9.2 SolutionTo chase these problems optimally, you need to alter Python's sources and rebuild Python. Specifically, add this function in Objects/object.c immediately before the _Py_PrintReferences function:
void
_Py_CountReferences(FILE *fp)
{
int n;
PyObject *op;
for (n = 0, op = refchain._ob_next;
op != &refchain;
op = op->_ob_next, n += op->ob_refcnt)
{ }
fprintf(fp, "%d refs\n", n);
}
I place in the following macros in my C extension:
#if defined(Py_DEBUG) defined(DEBUG)
extern void _Py_CountReferences(FILE*);
#define CURIOUS(x) { fprintf(stderr, _ _FILE_ _ ":%d ", _ _LINE_ _); x; }
#else
#define CURIOUS(x)
#endif
#define MARKER( ) CURIOUS(fprintf(stderr, "\n"))
#define DESCRIBE(x) CURIOUS(fprintf(stderr, " " #x "=%d\n", x))
#define DESCRIBE_HEX(x) CURIOUS(fprintf(stderr, " " #x "=%08x\n", x))
#define COUNTREFS( ) CURIOUS(_Py_CountReferences(stderr))
To debug, I rebuild Python using make OPT="-DPy_DEBUG" , which causes the code under Py_TRACE_REFS to be built. My own makefile for my extensions does the same trick by including these lines:
debug:
make clean; make OPT="-g -DPy_DEBUG" all
CFLAGS = $(OPT) -fpic -O2 -I/usr/local/include -I/usr/include/python1.5
16.9.3 Discussion
If I'm developing C extensions and I run into memory problems, I find that the typical cause is mismanagement of reference counts, particularly
Unlike
_Py_PrintReferences
, this recipe's function will print only the total of all the reference counts in the system, so it can be used safely in
So when I suspect that one of my functions is responsible for memory problems, I liberally sprinkle the suspect function with calls to the
COUNTREFS
macro. This allows me to keep track of exactly how many references are being created or
16.9.4 See AlsoThe only documentation in this case is the source code ("Use the source, Luke!"). |