[SOLVED] Crash in http connection thread

I’m getting an assertion (leading to a crash in debug builds) when I quit the host (Studio One) as my plugin is stopping its thread.

At some point earlier, that thread has used a URL object to make a GET to our server via the function createInputStream(). If I don’t make that function call, then there is no such assertion (and no crash).

I am calling stopThread(100) to terminate the thread.

The code that asserts is in Thread::stopThread(), after waiting and checking isThreadRunning() returns true.

Why is the thread unable to stop when it has at any point made a call via http(s)? I have long since deleted the returned stream object from createInputStream. How do I fix this?

(Using JUCE 5.3.2, btw.)

The reason the thread does not want to terminate is likely due to an unreleased resource hold by the thread. How do you proceed to execute the HTTP GET. Is there any HTTP request object or like so that would need to be unreleased?
Actually it s not easy to answer without having the code :frowning:

All I do (once, at some point after my worker thread has been created) is create a URL object, call createInputStream(), and call read() on the returned stream object to fill out a char array. Then I delete the stream object (as required). That’s it. If I skip making the call to createInputStream(), then there is no problem. Only if I make that call does my thread later hang when trying to close the plugin. This only happens the one time, and there are no other http calls anywhere. Can’t be much simpler to explain than that.

Here’s the code (redacted):

URL checkURL( "https://xxxxxxxxx.com/xxxxx" );
checkURL = checkURL.withParameter("aaa", a);
checkURL = checkURL.withParameter("bbb", b);
checkURL = checkURL.withParameter("ccc", c);
checkURL = checkURL.withParameter("ddd", v);
//
auto pStream = checkURL.createInputStream(false);
if (pStream != nullptr)
{
	//
	WebInputStream* pWebStream = dynamic_cast<WebInputStream*>(pStream);
	if (pWebStream != nullptr)
	{
		//
		char msg[512];
		auto bytesRead = pWebStream->read(msg, 511);
		if (bytesRead > 0)
		{
			String whole = String::fromUTF8(msg);
			
			// do something with the response here... 
		}
	}
	
	//
	delete pStream;
}

Here is the stack trace:

Thread 33 Crashed:: http connection
0   ???                           	0x00000001390eb43a 0 + 5252232250
1   ???                           	0x00000001390ed742 0 + 5252241218
2   ???                           	0x0000000139165e10 0 + 5252734480
3   ???                           	0x00000001390ec5be 0 + 5252236734
4   ???                           	0x00000001390eca85 0 + 5252237957
5   ???                           	0x000000013911246e 0 + 5252392046
6   libsystem_pthread.dylib       	0x00007fff745b2661 _pthread_body + 340
7   libsystem_pthread.dylib       	0x00007fff745b250d _pthread_start + 377
8   libsystem_pthread.dylib       	0x00007fff745b1bf9 thread_start + 13

By the way, although Pro Tools hits that same assert, it doesn’t crash when run outside the debugger. But Studio One crashes.

If I run from Terminal, I see this as well at the end of the run:

*** Leaked objects detected: 1 instance(s) of class URLConnectionState
JUCE Assertion failure in juce_LeakedObjectDetector.h:90
*** Leaked objects detected: 1 instance(s) of class WebInputStream
JUCE Assertion failure in juce_LeakedObjectDetector.h:90
*** Leaked objects detected: 1 instance(s) of class Pimpl
JUCE Assertion failure in juce_LeakedObjectDetector.h:90
*** Leaked objects detected: 2 instance(s) of class URL
JUCE Assertion failure in juce_LeakedObjectDetector.h:90
*** Leaked objects detected: 1 instance(s) of class InputStream
JUCE Assertion failure in juce_LeakedObjectDetector.h:90
*** Leaked objects detected: 3 instance(s) of class MemoryBlock
JUCE Assertion failure in juce_LeakedObjectDetector.h:90
*** Leaked objects detected: 1 instance(s) of class Thread
JUCE Assertion failure in juce_LeakedObjectDetector.h:90
*** Leaked objects detected: 2 instance(s) of class WaitableEvent
JUCE Assertion failure in juce_LeakedObjectDetector.h:90
*** Leaked objects detected: 1 instance(s) of class StringPairArray
JUCE Assertion failure in juce_LeakedObjectDetector.h:90
*** Leaked objects detected: 6 instance(s) of class StringArray
JUCE Assertion failure in juce_LeakedObjectDetector.h:90
Segmentation fault: 11

None of that appears if I don’t call the createInputStream() function.

Is there something more I need to do when I’m finished reading the response string besides delete the InputStream returned from createInputStream()?

The LeakDetector debugs occur in reverse order. Most likely all this stuff is owned by something leaked itself.
It is very advisable to add the JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR macro to your own classes, that way you find those if leaked as well.

N.B. there is no need to dynamic_cast to WebInputStream. read is a virtual method of InputStream, so the most specific override will be called automatically.

I cannot solve it from that snippet, but I think that the read loop never returns, and the whole class containing that snippet is leaking. But that is pure guessing.

Ah, that’s it, I bet. The URL I’m trying to reach doesn’t have its certificate yet, and the Mac isn’t allowing the clear-text http. The problem is that I didn’t specify a timeout in createInputStream(), which defaults to an infinite timeout, and thus the hang.

Thanks for that! I was pretty stumped!