AAX - Memory becomes unavailable before method finishes

Hi All,

This is working fine for me in VST - but in AAX when I do this:

void AudioPluginAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    serverThread.startThread();    
}

Where serverThread is an instance of juce::Thread that has a run() method that does this:

server.start([this](unsigned long port){
     cout << "Inside Server Callback" << port << endl;
     *_serverStarted = true; //<-- atomic bool
});

The method is never able to finish before the plugin crashes with EXC_BAD_ACCESS (it’s supposed to start a web socket server). In the debugger at that point variables show <invalid address> and <read from memory xxx failed ... >. Anyone know anything about what’s going on with the host here and why it seems to be making these addresses unavailable? I tried calling the new thread in the constructor as well as with a WaitableEvent (to keep the calling method from returning), but same issue. This is the websocket library for reference: Ole Christian Eidheim / Simple-WebSocket-Server · GitLab

Any thoughts super appreciated!
Many Thanks

Only thing that comes to mind is perhaps try doing this as a call to MessageManager::callAsync. Protools tends to make calls from other threads when compared to vst/au and that has always fixed said issue for me in the past.

Your server thread needs to be stopped in the destructor of the plugin, since it captures this.
The host is allowed to create a throw-away instance of the plugin to check some stuff. I don’t know if that’s what ProTools is doing here, but you need to be prepared for that.

If the construction and destruction is happening on the same (preferrably message) thread, making it safe for concurrency is slightly easier.

Creating a thread just to start the server thread and return doesn’t make much sense IMHO.

1 Like

Thanks All!

Sadly this doesn’t help

The thread that starts the server I don’t think returns once the server is successfully started. Here’s a more minimal example that has the same issue:

void AudioPluginAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    
    WsServer server;
    auto &sendPoint = server.endpoint["^/send/?$"];
    thread testThread([]{
      server.config.port = 2000;
      sendPoint.on_message = [](shared_ptr<WsServer::Connection> connection, shared_ptr<WsServer::InMessage> in_message) { 
          cout << "Message Received" << in_message->string() << endl;
      };
                      
      server.start([](unsigned long port){ 
          cout << "Server Now Started" << port << endl;
      });
    });

   testThread.detach();

}

Yes I’ve tried to call this from a few places including after a Timer::callAfterDelay in the constructor (so It would not be started by a plugin scan), but with same results.

What are some ways things can be made safe for concurrency?

Many thanks!

There are a few more problems in your code. First is, you are taking a reference to a local variable, i.e. server. Once this method finishes, the server is destroyed calling the destructor of WsServer.
I don’t know the implementation, but I assume the reference sendPoint becomes dangling here.

I am surprised that this code compiles, how is server known inside the lambdas?
But even if they are, the server was destroyed as we established before.

About your concurrency question:
Whenever you access a shared variable, you need to guard that with a CriticalSection and ideally a ScopedLock around to make sure, it is not destroyed while it is being accessed. Same goes for altering operations, i.e. anything non-const.

My code issues not withstanding, it seems like this was actually solved by downgrading to an older version of asio.

Understood - many thanks!