Python Segfaults

by JS

Python is an interpreted language, and the interpreter is solid enough that you wouldn’t expect to encounter the following:

stober[~]{landmine}$ python test.py
Segmentation fault

Pretty scary stuff. So what was I running?

#!/lusr/bin/python
from opencv import highgui
from opencv import cv
 
writer = highgui.cvCreateVideoWriter("test.mpg", highgui.CV_FOURCC('m','p','g','1'), 30.0, cv.cvSize(100,100), True)

99.9% of the time the Python interpreter is not at fault, so you can safetly bet the problem has something to do with a library, preferably some library that is

  1. not in part of the standard libraries
  2. not written in pure Python.

The Python bindings for OpenCV fit both of these criteria perfectly. So the question now is, what do I do about it?

A major advantage of open source is that, if you are so inclined, you may be able to figure out a solution directly. If you spend all day in Python, you may have forgotten about an old friend from your distant past — gdb.

With a debuggable OpenCV library at my disposal, here what my gdb session looks like:

This GDB was configured as "i686-pc-linux-gnu".
(gdb) file python
Reading symbols from /lusr/bin/python...done.
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) break cvCreateVideoWriter
Function "cvCreateVideoWriter" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (cvCreateVideoWriter) pending.
(gdb) run test.py
Starting program: /lusr/bin/python test.py
[Thread debugging using libthread_db enabled]
[New Thread 0xb7dee6c0 (LWP 32307)]
Breakpoint 2 at 0xb65b1a50: file cvcap.cpp, line 250.
Pending breakpoint "cvCreateVideoWriter" resolved
[Switching to Thread 0xb7dee6c0 (LWP 32307)]
 
Breakpoint 2, cvCreateVideoWriter (filename=0xb7d85634 "test.mpg", fourcc=23556205, fps=30, frameSize={width = 100, height = 100}, is_color=1) at cvcap.cpp:250
250                                                 double fps, CvSize frameSize, int is_color )
Current language:  auto; currently c++
(gdb) n
256             if(!fourcc || !fps)
(gdb)
271                     result = cvCreateVideoWriter_FFMPEG(filename, fourcc, fps, frameSize, is_color);
(gdb) s
cvCreateVideoWriter_FFMPEG (filename=0xb7d85634 "test.mpg", fourcc=23556205, fps=30, frameSize={width = 100, height = 100}, isColor=1) at cvcap_ffmpeg.cpp:1274
1274                                               CvSize frameSize, int isColor )
(gdb) n
1276        CvVideoWriter_FFMPEG* writer = new CvVideoWriter_FFMPEG;
(gdb) n
692         CvVideoWriter_FFMPEG() { init(); }
(gdb)
1277        if( writer->open( filename, fourcc, fps, frameSize, isColor != 0 ))
(gdb) n
 
Program received signal SIGSEGV, Segmentation fault.
0xb76f3e9f in codec_get_id () from /u/robot/python/lib/libavformat.so.52
(gdb)

I’ll omit the circuitous debugging path that resulted. Some strategic breakpoint settings later, I found out that the expression

highgui.FOUR_CC('m','p','g','1')

led to the segfault. I never got to the root cause, but using the gdb session as intuition, and flipping through the code, I discovered that highgui has a

highgui.CV_FOURCC_DEFAULT

field which lets the function cvCreateVideoWriter select the proper encoding based on the filename.

With the workaround, here’s what I get:

stober[~]{landmine}$ python test.py
Output #0, mpeg, to 'test.mpg':
    Stream #0.0: Video: mpeg1video (hq), yuv420p, 100x100, q=2-31, 640 kb/s, 30.00 tb(c)
swig/python detected a memory leak of type 'CvVideoWriter *', no destructor found.

Still some line noise, but no segfault! So what are the takeaways?

  1. Well, if you do a lot of work with open source libraries, be sure you are comfortable building debuggable versions of those libraries.
  2. Also, become familiar with using gdb to debug dynamically loaded libraries. If you use Python with a lot of imported shared libraries, you’ll need to know how to do so eventually.
  3. Finally, have patience. I omitted the better part of an afternoon’s worth of faulty assumptions, misleading code paths, and general confusion in the above description. Learn to manage your frustration as you learn to navigate unfamiliar code. Both skills are invaluable.