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");
}
[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?
SealedHeapSizeKB = 128 * 1024
});
_core = BizInvoker.GetInvoker<CoreImpl>(_exe, _exe);
_comm = (CommStruct*)_core.DllInit().ToPointer();
using (_exe.EnterExit())
{
_core = BizInvoker.GetInvoker<CoreImpl>(_exe, _exe);
_comm = (CommStruct*)_core.DllInit().ToPointer();
}
}
public void Dispose()

View File

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

View File

@ -54,6 +54,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
{
public object Sync;
private WeakReference LoadedRef = new WeakReference(null);
#if DEBUG
/// <summary>
/// recursive lock count
/// </summary>
public int LockCount;
#endif
public Swappable Loaded
{
get
@ -78,6 +84,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
public void Enter()
{
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 != null)
@ -93,6 +103,16 @@ namespace BizHawk.Emulation.Cores.Waterbox
/// </summary>
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);
}