1

I have a [large] program which has suddenly started having an issue somewhere in an infinite loop. I cannot find this loop.

I did:

import pdb
pdb.run ( 'main()' )

So when the program enters the infinite loop, I hit control-C and...... it doesn't do anything. In fact, when I don't use pdb, control-C doesn't work either.

I'm not overriding the signals. Even if I do, control-C does nothing.

I ran this in lldb to see if the problem was somewhere in C++-land, and it's not - it's definitely frozen executing python crap (on thread #7 if that matters).

How do I get pdb to actually break on control-c?

iAdjunct
  • 2,739
  • 1
  • 18
  • 27
  • AFAIK, Ctrl-C should raise an interrupt in the main thread and won't affect thread #7 unless the whole program stops. I'm guessing the main thread has a `try ... except:` somewhere (that's a bare except with no exception class specified) that is catching the `KeyboardInterrupt`. – Alex Hall May 10 '16 at 18:26
  • Also, this is a multithreaded program. Are you sure it hasn't hit a deadlock? – Alex Hall May 10 '16 at 18:28
  • Thread 7 was running free and thread 1 was waiting for it to finish on a condition variable, so that explains why control-C didn't work. And yes: it wasn't at a deadlock (it was using 100% CPU). My first thought was "oh good, a loop - not a deadlock!" Then I couldn't debug it... – iAdjunct May 10 '16 at 20:07

2 Answers2

1

Here's a simple 'debugger' that counts the number of times each line is passed over and raises an error when a line is hit too many times. Hopefully it can help find the loop if there really is one.

from bdb import Bdb
from collections import Counter

class LoopDetector(Bdb):
    def __init__(self, maxhits):
        Bdb.__init__(self)
        self.counter = Counter()
        self.maxhits = maxhits

    def do_clear(self, arg):
        pass

    def user_line(self, frame):
        filename = frame.f_code.co_filename
        lineno = frame.f_lineno
        key = (filename, lineno)
        self.counter[key] += 1
        if self.counter[key] >= self.maxhits:
            raise ValueError('Too many hits at %s:%s' % key)

LoopDetector(1000).set_trace()

x = 1
y = x + 2
for i in range(200):
    y += i

while True:  # An exception gets raised here
    y -= 1

print 'Does not get here'

This has to be done once per thread since it only affects the current thread.

iAdjunct
  • 2,739
  • 1
  • 18
  • 27
Alex Hall
  • 34,833
  • 5
  • 57
  • 89
  • This wasn't the answer I was hoping for ("here's how you make `pdb` work!") but this absolutely worked - I found my loop, which ended up being just shy of infinite (starting at -1e32 and adding twopi until it became positive). – iAdjunct May 10 '16 at 20:08
0

Take a look in the PDB docs

You should add a breakpoint in you function (main in your example) using pdb.set_trace() Then you can run the function using the command line (e.g python myprog.py) and the program will stop where you set the breakpoint.

import pdb

def main():
    i = 0

    while i<10:
        print i
        if i == 8:
            pdb.set_trace()
        i += 1

In the example above the the program will stop for debugging when i==8

lsxliron
  • 540
  • 5
  • 11
  • 1
    OP's problem is that they don't know where the loop is. – Alex Hall May 10 '16 at 18:46
  • @AlexHall did some more reading and found this [question](http://stackoverflow.com/questions/10239760/interrupt-pause-running-python-program-in-pdb). Seems like it works only in python 3 – lsxliron May 10 '16 at 19:16
  • Well that doesn't help either because OP says Ctrl-C is never affecting the program anyway. And if it did help the place to post the comment would be on the question to ensure that OP was notified. – Alex Hall May 10 '16 at 19:21