Fix use-after-free on the audio thread when Console is destroyed.

This commit is contained in:
Christian Speckner 2024-08-11 10:57:47 +02:00
parent 647263aed7
commit 93fd9a2e2b
7 changed files with 17 additions and 19 deletions

View File

@ -57,7 +57,7 @@ class SoundNull : public Sound
Initializes the sound device. This must be called before any
calls are made to derived methods.
*/
void open(shared_ptr<AudioQueue>, EmulationTiming*) override { }
void open(shared_ptr<AudioQueue>, shared_ptr<const EmulationTiming>) override { }
/**
Sets the sound mute state; sound processing continues. When turned

View File

@ -144,7 +144,7 @@ void SoundSDL2::setEnabled(bool enable)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
EmulationTiming* emulationTiming)
shared_ptr<const EmulationTiming> emulationTiming)
{
const string pre_about = myAboutString;

View File

@ -59,7 +59,7 @@ class SoundSDL2 : public Sound
calls are made to derived methods.
*/
void open(shared_ptr<AudioQueue> audioQueue,
EmulationTiming* emulationTiming) override;
shared_ptr<const EmulationTiming> emulationTiming) override;
/**
Sets the sound mute state; sound processing continues. When enabled,
@ -164,7 +164,7 @@ class SoundSDL2 : public Sound
shared_ptr<AudioQueue> myAudioQueue;
unique_ptr<Resampler> myResampler;
EmulationTiming* myEmulationTiming{nullptr};
shared_ptr<const EmulationTiming> myEmulationTiming;
Int16* myCurrentFragment{nullptr};
bool myUnderrun{false};

View File

@ -120,6 +120,7 @@ Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
myCart{std::move(cart)},
myAudioSettings{audioSettings}
{
myEmulationTiming = make_shared<EmulationTiming>();
myCart->setProperties(&myProperties);
// Create subsystems for the console
@ -752,7 +753,7 @@ FBInitStatus Console::initializeVideo(bool full)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::initializeAudio()
{
myEmulationTiming
(*myEmulationTiming)
.updatePlaybackRate(myAudioSettings.sampleRate())
.updatePlaybackPeriod(myAudioSettings.fragmentSize())
.updateAudioQueueExtraFragments(myAudioSettings.bufferSize())
@ -765,7 +766,7 @@ void Console::initializeAudio()
myTIA->setAudioQueue(myAudioQueue);
myTIA->setAudioRewindMode(myOSystem.state().mode() != StateManager::Mode::Off);
myOSystem.sound().open(myAudioQueue, &myEmulationTiming);
myOSystem.sound().open(myAudioQueue, myEmulationTiming);
}
/* Original frying research and code by Fred Quimby.
@ -879,8 +880,8 @@ void Console::setTIAProperties()
myTIA->setAdjustVSize(myOSystem.settings().getInt("tia.vsizeadjust"));
myTIA->setVcenter(vcenter);
myEmulationTiming.updateFrameLayout(myTIA->frameLayout());
myEmulationTiming.updateConsoleTiming(myConsoleTiming);
myEmulationTiming->updateFrameLayout(myTIA->frameLayout());
myEmulationTiming->updateConsoleTiming(myConsoleTiming);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -890,8 +891,8 @@ void Console::createAudioQueue()
|| myProperties.get(PropType::Cart_Sound) == "STEREO";
myAudioQueue = make_shared<AudioQueue>(
myEmulationTiming.audioFragmentSize(),
myEmulationTiming.audioQueueCapacity(),
myEmulationTiming->audioFragmentSize(),
myEmulationTiming->audioQueueCapacity(),
useStereo
);
}

View File

@ -185,7 +185,7 @@ class Console : public Serializable, public ConsoleIO
/**
Retrieve emulation timing provider.
*/
EmulationTiming& emulationTiming() { return myEmulationTiming; }
EmulationTiming& emulationTiming() { return *myEmulationTiming; }
/**
Toggle left and right controller ports swapping
@ -497,8 +497,9 @@ class Console : public Serializable, public ConsoleIO
ConsoleTiming myConsoleTiming{ConsoleTiming::ntsc};
// Emulation timing provider. This ties together the timing of the core emulation loop
// and the parameters that govern audio synthesis
EmulationTiming myEmulationTiming;
// and the parameters that govern audio synthesis. It is used on the audio thread,
// so we make it a shared pointer.
shared_ptr<EmulationTiming> myEmulationTiming;
// The audio settings
AudioSettings& myAudioSettings;

View File

@ -53,7 +53,7 @@ class Sound
Start the sound system, initializing it if necessary. This must be
called before any calls are made to derived methods.
*/
virtual void open(shared_ptr<AudioQueue>, EmulationTiming*) = 0;
virtual void open(shared_ptr<AudioQueue>, shared_ptr<const EmulationTiming>) = 0;
/**
Sets the sound mute state; sound processing continues. When turned

View File

@ -63,10 +63,8 @@ class SoundLIBRETRO : public Sound
calls are made to derived methods.
*/
void open(shared_ptr<AudioQueue> audioQueue,
EmulationTiming* emulationTiming) override
shared_ptr<const EmulationTiming>) override
{
myEmulationTiming = emulationTiming;
Logger::debug("SoundLIBRETRO::open started ...");
audioQueue->ignoreOverflows(!myAudioSettings.enabled());
@ -142,8 +140,6 @@ class SoundLIBRETRO : public Sound
shared_ptr<AudioQueue> myAudioQueue;
EmulationTiming* myEmulationTiming{nullptr};
Int16* myCurrentFragment{nullptr};
bool myUnderrun{false};