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 Initializes the sound device. This must be called before any
calls are made to derived methods. 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 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, void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
EmulationTiming* emulationTiming) shared_ptr<const EmulationTiming> emulationTiming)
{ {
const string pre_about = myAboutString; const string pre_about = myAboutString;

View File

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

View File

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

View File

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

View File

@ -53,7 +53,7 @@ class Sound
Start the sound system, initializing it if necessary. This must be Start the sound system, initializing it if necessary. This must be
called before any calls are made to derived methods. 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 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. calls are made to derived methods.
*/ */
void open(shared_ptr<AudioQueue> audioQueue, void open(shared_ptr<AudioQueue> audioQueue,
EmulationTiming* emulationTiming) override shared_ptr<const EmulationTiming>) override
{ {
myEmulationTiming = emulationTiming;
Logger::debug("SoundLIBRETRO::open started ..."); Logger::debug("SoundLIBRETRO::open started ...");
audioQueue->ignoreOverflows(!myAudioSettings.enabled()); audioQueue->ignoreOverflows(!myAudioSettings.enabled());
@ -142,8 +140,6 @@ class SoundLIBRETRO : public Sound
shared_ptr<AudioQueue> myAudioQueue; shared_ptr<AudioQueue> myAudioQueue;
EmulationTiming* myEmulationTiming{nullptr};
Int16* myCurrentFragment{nullptr}; Int16* myCurrentFragment{nullptr};
bool myUnderrun{false}; bool myUnderrun{false};