mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-04-17 19:23:38 -05:00
Push and wait on WorkQueueThread items using PushBlocking. Previously we created a Common::Event sync_event on the caller's stack, called Wait on it, then had the WorkQueueThread call Set on the sync_event once the thread was done. In addition to being simpler the new way avoids a use-after-free that could happen in convoluted and unlikely yet possible thread scheduling sequences. One such case can be triggered as follows: * Set your audio backend to Cubeb * In CubebStream::SetVolume set a breakpoint at the call to Wait and at the call to cubeb_stream_set_volume. * Start a game. * Continue until the Cubeb Worker thread hits the cubeb_stream_set_volume breakpoint and Emuthread hits the Wait breakpoint, freezing each thread when it hits its breakpoint. * Unfreeze Cubeb Worker. * In Event::Set set a breakpoint at the end of the scope containing the lock_guard such that the guard has been constructed but not destructed when the breakpoint is hit. * Continue until that breakpoint is hit by Cubeb Worker. If other threads hit it first keep going. * Freeze Cubeb Worker. * For convenience remove the breakpoint in Event::Set so other threads don't trigger it. * In CubebStream::SetRunning set a breakpoint at the call to Wait. * Unfreeze Emuthread and continue until the breakpoint is hit. * In Cubeb Worker go to Event::Set and examine the values of m_mutex's member variables. In Visual Studio Debug these are locking_thread_id == 0xcccccc01 and ownership_levels == 0xcccccccc. This is the result of Visual Studio overwriting the memory used on the stack by sync_event in CubebStream::SetVolume with cc bytes to represent uninitialized memory on the stack (since that function already returned), and then allocating enough memory on the stack when calling AudioCommon::SetSoundStreamRunning and then CubebStream::SetRunning that it overwrote one byte of the memory formerly occupied by locking_thread_id. * If you unfreeze Cubeb Worker at this point it will trigger the lock guard's destructor which will then try to unlock m_mutex. Since m_mutex is no longer in scope this is a use-after-free, and in VS debug triggers a debug assert due to locking_thread_id not matching the current thread id. |
||
|---|---|---|
| .. | ||
| DSPHLE | ||
| DSPLLE | ||
| DVD | ||
| EXI | ||
| GCMemcard | ||
| HSP | ||
| SI | ||
| WiimoteCommon | ||
| WiimoteEmu | ||
| WiimoteReal | ||
| AddressSpace.cpp | ||
| AddressSpace.h | ||
| AudioInterface.cpp | ||
| AudioInterface.h | ||
| CPU.cpp | ||
| CPU.h | ||
| DSP.cpp | ||
| DSP.h | ||
| GBACore.cpp | ||
| GBACore.h | ||
| GBAPad.cpp | ||
| GBAPad.h | ||
| GBAPadEmu.cpp | ||
| GBAPadEmu.h | ||
| GCKeyboard.cpp | ||
| GCKeyboard.h | ||
| GCKeyboardEmu.cpp | ||
| GCKeyboardEmu.h | ||
| GCPad.cpp | ||
| GCPad.h | ||
| GCPadEmu.cpp | ||
| GCPadEmu.h | ||
| GPFifo.cpp | ||
| GPFifo.h | ||
| HW.cpp | ||
| HW.h | ||
| Memmap.cpp | ||
| Memmap.h | ||
| MemoryInterface.cpp | ||
| MemoryInterface.h | ||
| MMIO.cpp | ||
| MMIO.h | ||
| MMIOHandlers.h | ||
| ProcessorInterface.cpp | ||
| ProcessorInterface.h | ||
| Sram.cpp | ||
| Sram.h | ||
| StreamADPCM.cpp | ||
| StreamADPCM.h | ||
| SystemTimers.cpp | ||
| SystemTimers.h | ||
| VideoInterface.cpp | ||
| VideoInterface.h | ||
| WII_IPC.cpp | ||
| WII_IPC.h | ||
| Wiimote.cpp | ||
| Wiimote.h | ||
| WiiSave.cpp | ||
| WiiSave.h | ||
| WiiSaveStructs.h | ||