Strange 'error' on shutdown using InterprocessConnection


#1

I’m building an app that communicates with another app (game), using an InterprocessConnection. For simplicity right now, I’m actually testing both ends wtihin the same process. this is where someone might say “duh, what do you expect?”, though i can’t think of any reason for it to cause a real problem.

When debugging the app, if I close it while the connections are open (even if i make sure i call ‘disconnect’ manually on both ends in closeButtonPressed()), visual studio pops up a warning window, and my output has the following message:

HEAP: Free Heap block 3465dc0 modified at 3465df0 after it was freed

It doesn’t happen if i don’t activate both ends… I considered that maybe my message stream classes were doing something naughty, but i stripped out any actual communications (i.e. no messages are sent at all) and it still happens.

Any ideas? or is this one of those “oh yeah, that’s fine don’t worry”. If I click ‘continue’ on the warning message, it just ends otherwise without complaint.

EDIT: using the tip :slight_smile:


#2

Sounds like something worth investigating. Can you reproduce it with some code that I could try?


#3

when i get a sec i’ll knock something up :slight_smile:


#4

I think i figured it out.

FWIW, here’s some test reproduction code [you can test it by replacing the contents of Main.cpp in the HelloWorld project.

#include "../JuceLibraryCode/JuceHeader.h"
#include "MainComponent.h"

class TestPipe	:	public InterprocessConnection
{
public:
	void connectionMade () {}
	void connectionLost () {}
	void messageReceived (const MemoryBlock &message) {}
};

class MainComp	:	public Component
{
public:

	TestPipe pipe1;
	TestPipe pipe2;

	MainComp ()
	{
		setSize (500,500);

		pipe1.createPipe (T("Test"));
		pipe2.connectToPipe (T("Test"));
		//pipe2.disconnect ();
		//pipe1.disconnect ();
	}
};

class HelloWorldWindow  : public DocumentWindow
{
public:


    //==============================================================================
    HelloWorldWindow()
        : DocumentWindow (T("JUCE Hello World!"),
                          Colours::lightgrey,
                          DocumentWindow::allButtons,
                          true)
    {
        MainComp* const contentComponent = new MainComp();
        setContentComponent (contentComponent, true, true);
        centreWithSize (getWidth(), getHeight());
        setVisible (true);
    }

    ~HelloWorldWindow() { }

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

//==============================================================================
class JUCEHelloWorldApplication : public JUCEApplication
{
    HelloWorldWindow* helloWorldWindow;

public:
    //==============================================================================
    JUCEHelloWorldApplication() : helloWorldWindow (0) { }
    ~JUCEHelloWorldApplication() { }
    //==============================================================================
    void initialise (const String& commandLine)
    {
        helloWorldWindow = new HelloWorldWindow();
    }

    void shutdown()
    {
        if (helloWorldWindow != 0)
            delete helloWorldWindow;
    }

    //==============================================================================
    const String getApplicationName() { return T("Hello World for JUCE"); }
    const String getApplicationVersion() { return ProjectInfo::versionString; }
    bool moreThanOneInstanceAllowed() { return true; }
    void anotherInstanceStarted (const String& commandLine) {}
};

//==============================================================================
START_JUCE_APPLICATION (JUCEHelloWorldApplication)

Run the app, and close the windoow, and you see the error.

I figured that the ‘disconnect()’ in the destructor of InterprocessConnection would take care of the pipes. Yet, unless I call them explicitly, I get the weird error. [uncomment the disconnect() lines, and it closes fine].

However, if you swap the order of the ‘TestPipe’ members then everything works fine. I guess it’s to do with the order in which they are destroyed, and which one created the pipe. So, it looks like it’s not something to worry about [two member pipe connections in the same object communicating with each other? WHAT KIND OF IDIOT WOULD TRY THAT??]. I doubt there’s much to be done to ‘fix’ it, but it probably doesn’t matter anyway.

I’m just glad i figured out wtf was going on.


#5

It seems a little odd that it’d cause a heap error… I’ll take a look when I get chance. Which OS are you using?


#6

Well, I’ll let you guess the name of the OS from the forum this post is in :wink: but the versions I’ve tried it on (and it happens in both) are 7 and XP.


#7

Doh!


#8

Now i’m really confused.

I took the test ‘server’ connection out of my client app like a good boy, and made a separate app to connect to. My client only tries to connect to a pipe, and not create one itself.

I connect fine. I communicate fine. When I close my client, I get the error.

The error appears even if I’ve disconnected the client before attempting to close.
[to make sure, i put code in ‘closeButtonPressed’ that equates to “if connected, disconnect, else quit”, so it takes two clicks to close. same deal, even if i wait between clicks].

However, the error doesn’t occur if I never connect my client.

I’ve stripped out all calls to sendMessage on both ends to make sure I’m not doing any dodgy comms, and I get the same thing. If I’ve connected to a pipe at all, and I attempt to close the app whilst the pipe still exists (it was created by the test server app), i experience THE ERROR.

It is now doing my head in!


#9

Hmm… also, if (on a bare client, single pipe version of the code i pasted above) i connect -> disconnect -> connect -> disconnect, the error happens eventually [i.e. not on shutdown - while the app is running].

something is seriously screwed.

i forgot to mention that i’m running 64 bit windows 7 here at home, but i was getting the error on my 32bit xp work machine.


#10

reproduced with the Juce demo.
run one instance set to named pipe (listening).

Launch another instance (with the debugger), and set it to named pipe (connect to existing pipe). Change back to disconnected, and pOOf.


#11

I’m a bit busy at the moment to debug that, as it might take some time to investigate… Will look asap but keep me posted if you get any clues.


#12

Seems like it might be thread-related; I have set breakpoints in both ~NamedPipe and ~NamedPipeInternal destructors, it hits those when closing the connection and then continues happily afterwards (no matter how many times i open/close connection). If I remove at least one of those breakpoints, the error comes up. The horrible schroedinger’s cat of debugging, where the errorcat is dead depending on when you look.


#13

Well, I managed to stop it happening!

I put a CriticalSection member in NamedPipe;
Plonk a ScopedLock on it at the top of NamedPipe::close() and NamedPipe::read(), and it seems to have fixed it. I can open and close the connection willy nilly, with no error. and I can successfully send messages.


#14

Hmm, sounds ok, but I think that close() would need to call cancelPendingReads() before locking. Otherwise if you called close() to interrupt a thread that’s waiting in the read() method, it’d deadlock.


#15

you know better than me :slight_smile: just tried that and the universe didn’t explode, so all is well.