Python segfault

David Allen s2mdalle at titan.vcu.edu
Tue Jun 20 22:02:16 EDT 2000


If there is a better place to forward this 'bug report' to, please
forward it if you know of it.  

First, here's a few details, and some gdb output, followed by
the code that caused this to hopefully shed some light:

[x at foobar /home/x/code/python/Grumble]$ rpm -q python
python-1.5.2-13
[x at foobar /home/x/code/python/Grumble]$ rpm -q tkinter
tkinter-1.5.2-13

[x at foobar /home/x/code/python/Grumble]$ python mumble.py
Segmentation fault (core dumped)

Here's some really ugly GDB output from the dump.....
[x at foobar /home/x/code/python/Grumble]$ ls -l core
-rw-------    1 x        x         7438336 Jun 20 20:48 core

[x at foobar /home/x/code/python/Grumble]$ gdb `which python` core
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux"...
(no debugging symbols found)...
Core was generated by `python mumble.py'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libdl.so.2...done.
Reading symbols from /lib/libpthread.so.0...done.
Reading symbols from /lib/libm.so.6...done.
Reading symbols from /lib/libc.so.6...done.
Reading symbols from /lib/ld-linux.so.2...done.
Reading symbols from /usr/lib/python1.5/lib-dynload/selectmodule.so...done.
Reading symbols from /usr/lib/python1.5/lib-dynload/timemodule.so...done.
Reading symbols from /usr/lib/python1.5/lib-dynload/socketmodule.so...done.
Reading symbols from /usr/lib/python1.5/lib-dynload/stropmodule.so...done.
Reading symbols from /usr/lib/python1.5/lib-dynload/_tkinter.so...done.
Reading symbols from /usr/lib/libtix4.1.8.0.so...done.
Reading symbols from /usr/lib/libtk8.0.so...done.
Reading symbols from /usr/lib/libtcl8.0.so...done.
Reading symbols from /usr/X11R6/lib/libX11.so.6...done.
#0  0x400a95ae in chunk_alloc (ar_ptr=0xbfe0203c, nb=18086444) at malloc.c:2728
2728    malloc.c: No such file or directory.
(gdb) backtrace
#0  0x400a95ae in chunk_alloc (ar_ptr=0xbfe0203c, nb=18086444) at malloc.c:2728
#1  0x400a94be in malloc () at malloc.c:2181
#2  0x8072284 in PyString_FromString ()
#3  0x80593a8 in PyErr_SetString ()
#4  0x80516a6 in PyEval_EvalCode ()
#5  0x80541ab in PyEval_CallObjectWithKeywords ()
#6  0x8053dca in PyEval_CallObjectWithKeywords ()
#7  0x8065eab in PyInstance_New ()
#8  0x8053ed1 in PyEval_CallObjectWithKeywords ()
#9  0x8053dd8 in PyEval_CallObjectWithKeywords ()
#10 0x8059524 in PyErr_NormalizeException ()
#11 0x80595d3 in PyErr_NormalizeException ()
#12 0x80595d3 in PyErr_NormalizeException ()
#13 0x80595d3 in PyErr_NormalizeException ()
#14 0x80595d3 in PyErr_NormalizeException ()
#15 0x80595d3 in PyErr_NormalizeException ()
#16 0x80595d3 in PyErr_NormalizeException ()
#17 0x80595d3 in PyErr_NormalizeException ()
#18 0x80595d3 in PyErr_NormalizeException ()
#19 0x80595d3 in PyErr_NormalizeException ()
#20 0x80595d3 in PyErr_NormalizeException ()
#21 0x80595d3 in PyErr_NormalizeException ()
#22 0x80595d3 in PyErr_NormalizeException ()
#23 0x80595d3 in PyErr_NormalizeException ()
#24 0x80595d3 in PyErr_NormalizeException ()
#25 0x80595d3 in PyErr_NormalizeException ()
#26 0x80595d3 in PyErr_NormalizeException ()
#27 0x80595d3 in PyErr_NormalizeException ()
#28 0x80595d3 in PyErr_NormalizeException ()
#29 0x80595d3 in PyErr_NormalizeException ()
#30 0x80595d3 in PyErr_NormalizeException ()
#31 0x80595d3 in PyErr_NormalizeException ()
#32 0x80595d3 in PyErr_NormalizeException ()
#33 0x80595d3 in PyErr_NormalizeException ()
#34 0x80595d3 in PyErr_NormalizeException ()
#35 0x80595d3 in PyErr_NormalizeException ()
#36 0x80595d3 in PyErr_NormalizeException ()
#37 0x80595d3 in PyErr_NormalizeException ()
#38 0x80595d3 in PyErr_NormalizeException ()
#39 0x80595d3 in PyErr_NormalizeException ()
#40 0x80595d3 in PyErr_NormalizeException ()
#41 0x80595d3 in PyErr_NormalizeException ()
#42 0x80595d3 in PyErr_NormalizeException ()
#43 0x80595d3 in PyErr_NormalizeException ()
#44 0x80595d3 in PyErr_NormalizeException ()
#45 0x80595d3 in PyErr_NormalizeException ()
#46 0x80595d3 in PyErr_NormalizeException ()
#47 0x80595d3 in PyErr_NormalizeException ()
#48 0x80595d3 in PyErr_NormalizeException ()
#49 0x80595d3 in PyErr_NormalizeException ()
#50 0x80595d3 in PyErr_NormalizeException ()
#51 0x80595d3 in PyErr_NormalizeException ()
#52 0x80595d3 in PyErr_NormalizeException ()
#53 0x80595d3 in PyErr_NormalizeException ()
#54 0x80595d3 in PyErr_NormalizeException ()
#55 0x80595d3 in PyErr_NormalizeException ()
#56 0x80595d3 in PyErr_NormalizeException ()
#57 0x80595d3 in PyErr_NormalizeException ()
#58 0x80595d3 in PyErr_NormalizeException ()
#59 0x80595d3 in PyErr_NormalizeException ()
#60 0x80595d3 in PyErr_NormalizeException ()
#61 0x80595d3 in PyErr_NormalizeException ()
#62 0x80595d3 in PyErr_NormalizeException ()
#63 0x80595d3 in PyErr_NormalizeException ()
#64 0x80595d3 in PyErr_NormalizeException ()
#65 0x80595d3 in PyErr_NormalizeException ()
#66 0x80595d3 in PyErr_NormalizeException ()
#67 0x80595d3 in PyErr_NormalizeException ()
#68 0x80595d3 in PyErr_NormalizeException ()

(This just continues...I stopped scrolling at line #1053. 
They all say the same thing, i.e.
#1053 0x80595d3 in PyErr_NormalizeException ())

Now some code....a quick note on this, this uses Tkinter,
and all you need to do to replicate this, is go to the 
file menu, and choose the "Disconnect" option as the
very first thing you do, and it will segfault.  The disconnect
code is effectively trying to call a method "close()" on a 
object item that doesn't exist.  I think this is happening
at this line:

self.socket().close()

the socket() method fetches the socket item in the object.
At the point where this is happening, it doesn't exist.  But
python should spit out name error or no such attribute, not
die.  :)

Here's the code (there's more but to avoid burying you,
I'm cutting out the things that don't get called):

import select
import thread
import os
import time
import socket
import sys
import Pmw                      # Python Mega Widgets (for some GUI components)
import thread
import socket
import string
from types import *
from Tkinter import *
from GrumbleCommon import *
from GrumbleClient import *

class Mumble(GrumbleClient):
    def __init__(self):
        GrumbleClient.__init__(self)

        self.current_channel = None

        self.handlers = { "=cc"    : self.setCurrentChannel }

        self.window = Tk()
        self.frame = Frame(self.window)
        self.frame.pack(expand=1, fill='both')
        self.text = Pmw.ScrolledText(self.frame,
                                     hscrollmode = "dynamic",
                                     vscrollmode = "static")
       self.text.pack(side='top', fill='both', expand=1)
        self.bframe = Frame(self.frame)
        self.entry = Pmw.EntryField(self.bframe, command=self.insertData)
        self.OK = Button(self.bframe, text='Send', command=self.insertData)
        self.entry.pack(side='left', fill='both', expand=1)
        self.OK.pack(side='right')
        self.bframe.pack(side='bottom', fill='both', expand=1)

        self.make_menus()
        self.window.config(menu=self.menu)
    def make_menus(self):
        self.menu = Menu(self.frame)
        filemenu = Menu(self.menu)
        filemenu.add_command(label='Connect', command=self.new_connection)
        filemenu.add_command(label='Disconnect',
                             command=self.disconnect_wrapper)
        filemenu.add_command(label='Quit', command=self.quit)

        editmenu = Menu(self.menu)
        editmenu.add_command(label='Cut',   command=self.cut)
        editmenu.add_command(label='Copy',  command=self.copy)
        editmenu.add_command(label='Paste', command=self.paste)

        self.menu.add_cascade(label="File", menu=filemenu)
        self.menu.add_cascade(label="Edit", menu=editmenu)
    def copy(self):
        try:
            self.buffer = self.text.get(SEL_FIRST, SEL_LAST)
        except:
            pass
        return(None)

    def cut(self):
        try:
            self.buffer = self.text.get(SEL_FIRST, SEL_LAST)
            self.text.delete(SEL_FIRST, SEL_LAST)
        except:
            pass
        return(None)

    def insert(self, buffer, asis=None):
        if not buffer:
            return None
        # If asis is not true, then append a linebreak
        # if it is needed.  If asis is true, then leave it
        # 'as is'
        if not asis:
            try:
                if buffer[-1] != '\n' and buffer[-1] == '\r':
                    buffer = buffer + '\n'
            except:
                return None

        try:
            self.text.insert('end', buffer)
        except:
            print "Error inserting text into main widget!"
            pass
        return None

    def paste(self):
        if self.buffer != None and self.buffer != '':
            self.insert(self.buffer, 1)
            return(None)

    def quit(self):
        try:
            self.disconnect()
        except:
            pass
        self.window.destroy()
        sys.exit(0)
    def message(self, text):
        self.insert('\n****CLIENT:\n****' + text + '\n')
        return None

    def report_error(self, text):
        self.insert("\n****CLIENT ERROR:\n****" + text + '\n')
        return None
    def connect_wrapper(self, host=None, port=None, nick=None):
        self.message("Connecting to %s:%s..." % (host, port))
        self.connect(host, port, nick)

        thread.start_new_thread(self.reader, ())
        self.message('Connected to %s:%s' % (host, port))

    def insertData(self):
        text = self.entry.get()
        self.entry.setentry('')
        if text[0] == '=':
            retty = self.interpret(text)
            if retty:
                return None

        text = text + '\n'

        if self.current_channel:
            self.talk(self.current_channel, text)
        else:
            self.send(text)

x = Mumble()
mainloop() 

And here's the GrumbleClient.py file.  It segfaults when
self.disconnect() gets called, and that was inherited from
GrumbleClient:
import select
import thread
import os
import time
import socket
import sys
import string

from types import *

class GrumbleClient:
    GrumbleClientException = 'GrumbleClient'
    DEFAULT_BUFFER_LENGTH = 1024

    def __init__(self):
        self._socket    = None
        self._nick      = 'Guest'
        self._host      = 'localhost.localdomain'
        self._port      = 666
      self._connected = None
        return None

    def quit(self):
        return self.send_command('/quit')

    # Same as quit()
    def close(self):
        return self.quit()

    def part(self, channel):
        return self.send_command('/part %s' % channel)

    def change_nick(self, newnick):
        return self.send_command('/nick %s' % newnick)

    def topic(self, channel, newtopic=None):
        if newtopic:
            return self.send_command('/topic %s %s' % (channel, newtopic))
        else:
            return self.send_command('/topic %s' % channel)
        return None

    def join(self, channel):
        return self.send_command('/join %s' % channel)

    def kibitz(self, text):
        return self.send('kibitz!%s' % text)

    # Send a "talked" message (to a specific channel)
    def talk(self, channel, text):
        if (not channel) or not (type(channel) is StringType):
            err = 'Illegal channel argument to talk()'
            raise GrumbleClient.GrumbleClientException, err
        if (not text) or len(text) <= 0:
            return None
        return self.send('%s!%s\n' % (channel, text))

    # Read data off of the socket, up to len bytes
    def read(self, len=None):
        if len:
            return self.socket().recv(GrumbleClient.DEFAULT_BUFFER_LENGTH)
        else:
            return self.socket().recv(len)
        return None

    # Send data to the raw socket
    def send(self, data):
        try:
            self.socket().send(data)
        except socket.error, errstr:
            raise GrumbleClient.GrumbleClientException, errstr[1]
        return 1

    # SEGFAULT IS HAPPENING SOMEWHERE IN HERE
    def disconnect(self):
        self.quit()
        try:
            self.socket().close()
        except socket.error, errstr:
            e = 'Socket error: %s' % errstr[1]
            raise GrumbleClient.GrumbleClientException, e
        self.connected(None)
        return 1
    def socket(self, sock=None):
        if sock:
            self._socket = sock
        try:
            return self._socket
        except:
            raise GrumbleClient.GrumbleClientException, 'Socket undefined'

(lots of code clipped that isn't referenced by this bug)

I'm willing to send full source code to whoever wants/needs it.
I'm hoping that the code exerpts will be enough with the gdb
stuff to get at whatever is happening here.
While the coding isn't perfect, (this is a very early prototype,
and I'm a python beginner), I figure that the way it SHOULD be,
no matter HOW fucked up my programming is, segfaulting is
NEVER the correct response for the python interpreter.  From
the gdb output, it looks like the NormalizeException funciton
is calling itself until it croaks.
-- 
David Allen
http://opop.nols.com/




More information about the Python-list mailing list