classification
Title: Problem with socket.gethostbyaddr() and KeyboardInterrupt
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.0, Python 2.6
process
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: Nosy List: ggenellina, vstinner
Priority: normal Keywords:

Created on 2007-07-17 10:07 by vstinner, last changed 2008-11-27 01:43 by ggenellina. This issue is now closed.

Files
File name Uploaded Description Edit
hostname.py vstinner, 2008-11-23 23:52
bug1755388.py ggenellina, 2008-11-24 09:25 A short program showing the bug
Messages (8)
msg32522 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2007-07-17 10:07
Hi,

I wrote a small function to translate an IP to a hostname (eg. 212.27.33.225 => "linuxfr.org").

---------------------------------------------
from socket import gethostbyaddr, herror as socket_host_error

def ip2name(addr):
    try:
        if addr in ip2name.cache:
            return ip2name.cache[addr]
        name = gethostbyaddr(addr)[0]
    except (socket_host_error, KeyboardInterrupt, ValueError):
        name = addr
    ip2name.cache[addr] = name
    return name
ip2name.cache = {}
---------------------------------------------

Problem: sometimes gethostbyaddr() takes 5 seconds to answer "unknown host" so I hit CTRL+c to interrupt hit. But the "try/except" block doesn't catch the interruption. I found a workaround: use double try/except (try: gethostbyaddr() except KeyboardInterrupt: raise).

Last version of my function
---------------------------------------------
def ip2name(addr):
    if not ip2name.resolve:
        return addr
    try:
        if addr in ip2name.cache:
            return ip2name.cache[addr]
        # FIXME: Workaround Python bug
        # Need double try/except to catch the bug
        try:
            name = gethostbyaddr(addr)[0]
        except KeyboardInterrupt:
            raise
    except (socket_host_error, ValueError):
        name = addr
    except (socket_host_error, KeyboardInterrupt, ValueError):
        ip2name.resolve = False
        name = addr
    ip2name.cache[addr] = name
    return name
ip2name.cache = {}
ip2name.resolve = True
---------------------------------------------

I'm using Python 2.5.1 on Ubuntu Feisty (Linux kernel 2.6.20).

To reproduce my error, try "10.0.0.1" or "192.168.0.1" (or any other IP).
msg32523 - (view) Author: Gabriel Genellina (ggenellina) Date: 2007-07-19 21:37
I can reproduce the bug on Windows XP SP2, a simpler program is attached.

First run, I did not press Ctrl-C:

c:\temp>python bug1.py
enter test, gethostbyname('e.p.l.w.d.com')
Yo can press Ctrl-C
inner try
<type 'type'> <class 'socket.gaierror'> False
outer try
<type 'type'> <class 'socket.gaierror'> False
exit test

The inner try/except catches the exception as expected.

Second run, I *did* press Ctrl-C:

c:\temp>python bug1.py
enter test, gethostbyname('s.g.s.w.s.com')
Yo can press Ctrl-C
outer try
<type 'type'> <type 'exceptions.KeyboardInterrupt'> True
exit test

The inner try/except didn't catch the exception, and it propagates to the outer one. I don't understand why; even if the gethostbyname call is blocking, and Ctrl-C is not detected until it returns, there IS an exception raised (either KeyboardInterrupt or socket.gaierror) in the inner block that should be handled by the inner except clause.
msg32524 - (view) Author: Gabriel Genellina (ggenellina) Date: 2007-07-19 21:48
I don't see any Attach button (?), code showing the bug is at <http://pastebin.com/f7e02983d>
msg72849 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2008-09-09 12:02
Using gdb, I dig the problem:
 * when CTRL+c is pressed, signal_handler (sig_num=2) 
at ./Modules/signalmodule.c:175 is called
 * signal_handler() stores the signal has a "pending call"
 * Linux kernel interrupts its name resolution (it looks like it's the 
read() syscall?) and return the error ETIMEDOUT (110)
 * back to socket_gethostbyaddr(): result=110, h=NULL
 * gethost_common() set an error using set_herror(1)
 * socket_gethostbyaddr() return NULL

Later, Py_MakePendingCalls() will call signal_default_int_handler() 
which raises the KeyboardInterrupt.
msg76283 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2008-11-23 23:52
I don't know how to fix the bug and it looks like nobody cares about 
it. So I prefer to close it. Reopen it if you get the same error.
msg76313 - (view) Author: Gabriel Genellina (ggenellina) Date: 2008-11-24 09:25
I think that closing it as wontfix is not the proper thing to do. It 
is a real bug; closing it will hide it from anybody that could 
potentially fix it. Also it won't appear on bug listings unless you 
explicitely ask for closed ones. 

Setting the right categories might help.
msg76314 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2008-11-24 10:01
@gagenellina: It's a bug! Python does raise a KeyboardInterrupt 
exception, but too late. The exception is raised during the 
gethostbyaddr() so I expect to get a KeyboardInterrupt just after 
gethostbyaddr().
msg76490 - (view) Author: Gabriel Genellina (ggenellina) Date: 2008-11-27 01:43
Yes, I know it's a bug, and certainly closing this report won't help 
solve it. I can't reopen this.
History
Date User Action Args
2008-11-27 01:43:01ggenellinasetmessages: + msg76490
2008-11-24 10:01:16vstinnersetmessages: + msg76314
2008-11-24 09:34:41ggenellinasetcomponents: + Library (Lib), - Interpreter Core
2008-11-24 09:25:38ggenellinasetfiles: + bug1755388.py
type: behavior
messages: + msg76313
components: + Interpreter Core, - Extension Modules
versions: + Python 2.6, Python 3.0, - Python 2.5
2008-11-23 23:52:40vstinnersetstatus: open -> closed
resolution: wont fix
2008-11-23 23:52:27vstinnersetfiles: + hostname.py
messages: + msg76283
2008-09-09 12:02:55vstinnersetmessages: + msg72849
2007-07-17 10:07:41vstinnercreate