waterbox: When compiled in debug mode, forcibly evict self at every opportunity. This can be used to catch bugs using pointers past their valid time. Catch and fix two such bugs in the libsnes wrapper.

This commit is contained in:
nattthebear 2017-06-11 07:47:16 -04:00
parent 91e239e11f
commit fa9dcfae35
5 changed files with 67 additions and 28 deletions

View File

@ -458,6 +458,14 @@ namespace BizHawk.Common
{ {
DeleteFileW(path + ":Zone.Identifier"); DeleteFileW(path + ":Zone.Identifier");
} }
[DllImport("kernel32.dll")]
static extern bool IsDebuggerPresent();
public static bool IsDebuggerReallyPresent()
{
return IsDebuggerPresent();
}
} }
} }

View File

@ -62,9 +62,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
PlainHeapSizeKB = 2 * 1024, // TODO: wasn't there more in here? PlainHeapSizeKB = 2 * 1024, // TODO: wasn't there more in here?
SealedHeapSizeKB = 128 * 1024 SealedHeapSizeKB = 128 * 1024
}); });
using (_exe.EnterExit())
_core = BizInvoker.GetInvoker<CoreImpl>(_exe, _exe); {
_comm = (CommStruct*)_core.DllInit().ToPointer(); _core = BizInvoker.GetInvoker<CoreImpl>(_exe, _exe);
_comm = (CommStruct*)_core.DllInit().ToPointer();
}
} }
public void Dispose() public void Dispose()

View File

@ -2,6 +2,7 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using BizHawk.Emulation.Common; using BizHawk.Emulation.Common;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Nintendo.SNES namespace BizHawk.Emulation.Cores.Nintendo.SNES
{ {
@ -13,40 +14,46 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
public byte[] CloneSaveRam() public byte[] CloneSaveRam()
{ {
byte* buf = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM); using (Api.EnterExit())
var size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
if (buf == null)
{ {
buf = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.SGB_CARTRAM); byte* buf = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.SGB_CARTRAM); var size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
} if (buf == null)
{
buf = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.SGB_CARTRAM);
size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.SGB_CARTRAM);
}
var ret = new byte[size]; var ret = new byte[size];
Marshal.Copy((IntPtr)buf, ret, 0, size); Marshal.Copy((IntPtr)buf, ret, 0, size);
return ret; return ret;
}
} }
public void StoreSaveRam(byte[] data) public void StoreSaveRam(byte[] data)
{ {
byte* buf = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM); using (Api.EnterExit())
var size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
if (buf == null)
{ {
buf = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.SGB_CARTRAM); byte* buf = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.SGB_CARTRAM); var size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
} if (buf == null)
{
buf = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.SGB_CARTRAM);
size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.SGB_CARTRAM);
}
if (size == 0) if (size == 0)
{ {
return; return;
} }
if (size != data.Length) if (size != data.Length)
{ {
throw new InvalidOperationException("Somehow, we got a mismatch between saveram size and what bsnes says the saveram size is"); throw new InvalidOperationException("Somehow, we got a mismatch between saveram size and what bsnes says the saveram size is");
} }
Marshal.Copy(data, 0, (IntPtr)buf, size); Marshal.Copy(data, 0, (IntPtr)buf, size);
}
} }
} }
} }

View File

@ -734,8 +734,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
_syscalls.Init(); _syscalls.Init();
Console.WriteLine("About to enter unmanaged code"); Console.WriteLine("About to enter unmanaged code");
if (System.Diagnostics.Debugger.IsAttached) if (Win32Hacks.IsDebuggerReallyPresent() && !System.Diagnostics.Debugger.IsAttached)
{ {
// this means that GDB or another unconventional debugger is attached.
// if that's the case, and it's observing this core, it probably wants a break
System.Diagnostics.Debugger.Break(); System.Diagnostics.Debugger.Break();
} }

View File

@ -54,6 +54,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
{ {
public object Sync; public object Sync;
private WeakReference LoadedRef = new WeakReference(null); private WeakReference LoadedRef = new WeakReference(null);
#if DEBUG
/// <summary>
/// recursive lock count
/// </summary>
public int LockCount;
#endif
public Swappable Loaded public Swappable Loaded
{ {
get get
@ -78,6 +84,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
public void Enter() public void Enter()
{ {
Monitor.Enter(_currentLockInfo.Sync); Monitor.Enter(_currentLockInfo.Sync);
#if DEBUG
if (_currentLockInfo.LockCount++ != 0 && _currentLockInfo.Loaded != this)
throw new InvalidOperationException("Woops!");
#endif
if (_currentLockInfo.Loaded != this) if (_currentLockInfo.Loaded != this)
{ {
if (_currentLockInfo.Loaded != null) if (_currentLockInfo.Loaded != null)
@ -93,6 +103,16 @@ namespace BizHawk.Emulation.Cores.Waterbox
/// </summary> /// </summary>
public void Exit() public void Exit()
{ {
#if DEBUG
// when debugging, if we're releasing the lock then deactivate
if (_currentLockInfo.LockCount-- == 1)
{
if (_currentLockInfo.Loaded != this)
throw new InvalidOperationException("Woops!");
DeactivateInternal();
_currentLockInfo.Loaded = null;
}
#endif
Monitor.Exit(_currentLockInfo.Sync); Monitor.Exit(_currentLockInfo.Sync);
} }