Listeners crash in JUCE


#1

Hi,

I get this:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000596f5b in juce::ListenerList<juce::ButtonListener, juce::Array<juce::ButtonListener*, juce::DummyCriticalSection> >::callChecked<juce::Component::BailOutChecker, juce::Button*> (
    this=0xcec850, bailOutChecker=..., callbackFunction=&virtual table offset 24, param1=0xcec740) at ../../src/gui/components/buttons/../../../events/juce_ListenerList.h:173
173                 (iter.getListener()->*callbackFunction) (param1);
(gdb) bt
#0  0x0000000000596f5b in juce::ListenerList<juce::ButtonListener, juce::Array<juce::ButtonListener*, juce::DummyCriticalSection> >::callChecked<juce::Component::BailOutChecker, juce::Button*> (
    this=0xcec850, bailOutChecker=..., callbackFunction=&virtual table offset 24, param1=0xcec740) at ../../src/gui/components/buttons/../../../events/juce_ListenerList.h:173
#1  0x0000000000595912 in juce::Button::sendStateMessage (this=0xcec740) at ../../src/gui/components/buttons/juce_Button.cpp:388
#2  0x0000000000595477 in juce::Button::setState (this=0xcec740, newState=juce::Button::buttonDown) at ../../src/gui/components/buttons/juce_Button.cpp:271
#3  0x00000000005953ee in juce::Button::updateState (this=0xcec740, e=0x0) at ../../src/gui/components/buttons/juce_Button.cpp:254
#4  0x0000000000596392 in juce::Button::keyStateChanged (this=0xcec740) at ../../src/gui/components/buttons/juce_Button.cpp:598
#5  0x00000000005e6055 in juce::ComponentPeer::handleKeyUpOrDown (this=0xc20ea0, isKeyDown=true) at ../../src/gui/components/windows/juce_ComponentPeer.cpp:239
#6  0x0000000000603588 in juce::LinuxComponentPeer::handleWindowMessage(_XEvent*) ()
#7  0x00000000005f884c in juce::juce_windowMessageReceive (event=0x7fffffffe490) at ../../src/native/linux/juce_linux_Windowing.cpp:2765
#8  0x00000000005f713a in juce_dispatchNextXEvent () at ../../src/native/linux/juce_linux_Messaging.cpp:416
#9  0x00000000005f72f0 in juce::juce_dispatchNextMessageOnSystemQueue (returnIfNoPendingMessages=false) at ../../src/native/linux/juce_linux_Messaging.cpp:478
#10 0x00000000004fbfdc in juce::MessageManager::runDispatchLoopUntil (this=0xc27300, millisecondsToRunFor=-1) at ../../src/events/juce_MessageManager.cpp:160
#11 0x00000000004fbec7 in juce::MessageManager::runDispatchLoop (this=0xc27300) at ../../src/events/juce_MessageManager.cpp:137
#12 0x00000000004b3a04 in juce::JUCEApplication::main (commandLine=..., app=0xc15820) at ../../src/application/juce_Application.cpp:171
#13 0x00000000004b42ed in juce::JUCEApplication::main (argc=1, argv=0x7fffffffe7c8, newApp=0xc15820) at ../../src/application/juce_Application.cpp:301
#14 0x0000000000478b1b in main (argc=1, argv=0x7fffffffe7c8) at src/Application.cpp:102

This appears each time when typing Alt+F4.
This is strange as nothing seems corrupted when print’ing it:

(gdb) p iter
$1 = {list = @0xcec850, bailOutChecker = @0x7fffffffded0, index = 0}
(gdb) p callbackFunction
$2 = &virtual table offset 24
(gdb) p param1
$3 = (class juce::Button *) 0xcec740
(gdb) p *param1
$4 = {<juce::Component> = {<juce::MouseListener> = {_vptr.MouseListener = 0x756910}, <juce::MessageListener> = {_vptr.MessageListener = 0x756af8}, static currentlyFocusedComponent = 0xd2c9c0,
    componentName_ = {static empty = {static empty = <same as static member of an already seen type>, text = 0xbf6f50 L""}, text = 0xcec4c0 L"close"}, parentComponent_ = 0xc30ab0,
    componentUID = 289, bounds_ = {x = 1916, y = 4, w = 0, h = 0}, numDeepMouseListeners = 0, childComponentList_ = {data = {<juce::DummyCriticalSection> = {<No data fields>}, elements = {
          data = 0x0}, numAllocated = 0}, numUsed = 0}, lookAndFeel_ = 0x0, cursor_ = {cursorHandle = {referencedObject = 0xc22db0}}, effect_ = 0x0, bufferedImage_ = 0x0, mouseListeners_ = 0x0,
    keyListeners_ = 0x0, componentListeners = {listeners = {data = {<juce::DummyCriticalSection> = {<No data fields>}, elements = {data = 0xdb71d0}, numAllocated = 8}, numUsed = 1}},
    properties = {values = {data = {<juce::DummyCriticalSection> = {<No data fields>}, elements = {data = 0x0}, numAllocated = 0}, numUsed = 0}}, {componentFlags_ = 2, flags = {
        hasHeavyweightPeerFlag = false, visibleFlag = true, opaqueFlag = false, ignoresMouseClicksFlag = false, allowChildMouseClicksFlag = false, wantsFocusFlag = false,
        isFocusContainerFlag = false, dontFocusOnMouseClickFlag = false, alwaysOnTopFlag = false, bufferToImageFlag = false, bringToFrontOnClickFlag = false, repaintOnMouseActivityFlag = false,
        draggingFlag = false, mouseOverFlag = false, mouseInsideFlag = false, currentlyModalFlag = false, isDisabledFlag = false, childCompFocusedFlag = false,
        isInsidePaintCall = false}}}, <juce::SettableTooltipClient> = {<juce::TooltipClient> = {_vptr.TooltipClient = 0x756b20}, tooltipString = {static empty = {
        static empty = <same as static member of an already seen type>, text = 0xbf6f50 L""}, text = 0xbf6f50 L""}}, <juce::ApplicationCommandManagerListener> = {
    _vptr.ApplicationCommandManagerListener = 0x756b50}, <juce::Value::Listener> = {_vptr.Listener = 0x756b80}, <juce::KeyListener> = {_vptr.KeyListener = 0x756ba8}, shortcuts = {
    data = {<juce::DummyCriticalSection> = {<No data fields>}, elements = {data = 0xcee1d0}, numAllocated = 8}, numUsed = 1}, keySource = {<juce::ComponentListener> = {
      _vptr.ComponentListener = 0x70ed90}, comp = 0xc30ab0}, text = {static empty = {static empty = <same as static member of an already seen type>, text = 0xbf6f50 L""},
    text = 0xcec4c0 L"close"}, buttonListeners = {listeners = {data = {<juce::DummyCriticalSection> = {<No data fields>}, elements = {data = 0xde03d0}, numAllocated = 8}, numUsed = 1}},
  repeatTimer = {object = 0x0}, buttonPressTime = 4206903, lastTimeCallbackTime = 4206903, commandManagerToUse = 0x0, autoRepeatDelay = -1, autoRepeatSpeed = 0, autoRepeatMinimumDelay = -1,
  radioGroupId = 0, commandID = 0, connectedEdgeFlags = 0, buttonState = juce::Button::buttonDown, isOn = {value = {referencedObject = 0xceddb0}, listeners = {listeners = {
        data = {<juce::DummyCriticalSection> = {<No data fields>}, elements = {data = 0xcee010}, numAllocated = 8}, numUsed = 1}}}, lastToggleState = false, clickTogglesState = false,
  needsToRelease = false, needsRepainting = false, isKeyDown = true, triggerOnMouseDown = false, generateTooltip = false}

The other thread are sleeping (thread 4 is the timer thread), t 2 and 3 are socket client code waiting for event:

(gdb) i th
  4 Thread 0x7fffea6c0910 (LWP 3717)  0x00007ffff7bd020d in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib/libpthread.so.0
  3 Thread 0x7fffeb4f3910 (LWP 3716)  0x00007ffff7bd3131 in nanosleep () from /lib/libpthread.so.0
  2 Thread 0x7ffff089e910 (LWP 3715)  0x00007ffff7bd3131 in nanosleep () from /lib/libpthread.so.0
* 1 Thread 0x7ffff7ede740 (LWP 3712)  0x48e87d894810ec83 in ?? ()

The only thing that seems strange is the position of the program counter: 0x48E87…83 which seems totally broken.

I’ll try to reproduce this with the Juce demo.


#2

Ok, I think it has something to do with the window’s close buttons.
It doesn’t happen in the Juce demo.
So, I’ve tried to write the most simplistic code I could to reproduce this and here it is:

class MainWindow : public DocumentWindow
{
public:
MainWindow()
    : DocumentWindow (JUCE_T("My"),
                      Colours::azure,
                      DocumentWindow::closeButton,
                      true)
{

    setResizable (true, false); // resizability is a property of ResizableWindow
    setResizeLimits (720, 576, 8192, 8192);

    juce::Rectangle<int> rect = Desktop::getInstance().getMainMonitorArea(false);
    setBounds(rect); setVisible(true);
}

~MainWindow() {}
void closeButtonPressed() {JUCEApplication::getInstance()->systemRequestedQuit(); }
};

class MyApplication : public JUCEApplication
{
    MainWindow*         theMainWindow;

public:
    MyApplication()   : theMainWindow (0) {}
    ~MyApplication()   { }

    void initialise (const String& commandLine)
    {
        theMainWindow = new MainWindow();
        theMainWindow->setVisible (true);

        ImageCache::setCacheTimeout (30 * 1000);
    }
    void shutdown(){        deleteAndZero(theMainWindow);    }

    //==============================================================================
    void systemRequestedQuit()
    {
        if (theMainWindow != 0)
        {
            deleteAndZero (theMainWindow);
            quit();
        }
    }

    //==============================================================================
    const String getApplicationName()  {  return JUCE_T("My");   }
    const String getApplicationVersion() {  return JUCE_T("1.0.0");  }
    bool moreThanOneInstanceAllowed() { return true; }
};

START_JUCE_APPLICATION(MyApplication);

#3

Can’t reproduce it here.

From that weird memory address it looks like your compiler has misaligned some data… I’m running on 32-bit so that might not cause a problem, but if you’re running 64-bit then it could cause a fault. Very strange.


#4

Yes, it’s a debian Squeeze AMD64.
The compiler is fairly recent through: gcc version 4.4.3 20100108

I’m trying to figure out more about this, might require a compiler option or something…


#5

The idea that it could be misaligned data also fits with your strange valgrind “invalid read of 8 bytes” report. It seems like it’s packed the DocumentWindow structure, using 1 byte for each of the bools in it, and misaligned the pointers that follow them. Maybe try re-ordering the DocumentWindow members to put all the pointers first, and see if that makes any difference…?


#6

Ok, you were right (as always?), there was alignment issue.
I’ve sent you a patch.

Edit: I’ve spoken too fast. The application now crash in

#0  0x00007ffff5456229 in XLockDisplay () from /usr/lib/libX11.so.6
#1  0x00000000005f675d in ScopedXLock (this=0x7fffffffe59f) at ../../src/native/linux/juce_linux_Messaging.cpp:44
#2  0x00000000005f9bee in juce::juce_deleteMouseCursor (cursorHandle=0x600020) at ../../src/native/linux/juce_linux_Windowing.cpp:3087
#3  0x00000000005dbf9d in juce::SharedMouseCursorInternal::~SharedMouseCursorInternal() ()
#4  0x0000000000495c5f in juce::ReferenceCountedObject::decReferenceCount() ()
#5  0x00000000005dc10d in juce::ReferenceCountedObjectPtr<juce::SharedMouseCursorInternal>::~ReferenceCountedObjectPtr() ()
#6  0x00000000005dbbd6 in ~MouseCursor (this=0xcee690, __in_chrg=<value optimized out>) at ../../src/gui/components/mouse/juce_MouseCursor.cpp:127
#7  0x000000000041808b in juce::deleteAndZero<juce::MouseCursor*> (pointer=@0xbf6a78) at components/../include/../include/../../juce/src/core/juce_Memory.h:215

So they might still be some unaligned stuff around. I’ll take a look.


#7

Ok, I’m dumb. I’m using a mouse cursor that is statically allocated, and it’s deleted after the GUI is closed.
I’ll make sure it’s cleaned on exit.