waterbox: Add special handling for imports in XorStates. Fix a few other instances where managed pointers were leaking out into XorStates

This commit is contained in:
nattthebear 2017-05-27 20:38:28 -04:00
parent 7071d74416
commit ef8264a8b0
4 changed files with 74 additions and 7 deletions

View File

@ -123,6 +123,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
Region = VsyncNumerator / VsyncDenominator > 55 ? DisplayType.NTSC : DisplayType.PAL; Region = VsyncNumerator / VsyncDenominator > 55 ? DisplayType.NTSC : DisplayType.PAL;
} }
// when we call Seal, ANY pointer passed from managed code must be 0.
// this is so the initial state is clean
// the only two pointers set so far are LoadCallback, which the core zeroed itself,
// and CdCallback
Core.gpgx_set_cdd_callback(null);
_elf.Seal();
Core.gpgx_set_cdd_callback(cd_callback_handle);
// compute state size // compute state size
InitStateBuffers(); InitStateBuffers();
@ -150,8 +159,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
Tracer = new GPGXTraceBuffer(this, MemoryDomains, this); Tracer = new GPGXTraceBuffer(this, MemoryDomains, this);
(ServiceProvider as BasicServiceProvider).Register<ITraceable>(Tracer); (ServiceProvider as BasicServiceProvider).Register<ITraceable>(Tracer);
_elf.Seal();
} }
catch catch
{ {

View File

@ -155,6 +155,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
context.SyscallVtable = _syscallVtable = AllocVtable(340); context.SyscallVtable = _syscallVtable = AllocVtable(340);
context.LdsoVtable = _ldsoVtable = AllocVtable(7); context.LdsoVtable = _ldsoVtable = AllocVtable(7);
context.PsxVtable = _psxVtable = AllocVtable(5); context.PsxVtable = _psxVtable = AllocVtable(5);
// ctx comes from the native stack, where it could have any garbage in uninited fields
context.SysIdx = 0;
context.LibcIdx = 0;
context.DoGlobalCtors = IntPtr.Zero;
context.DoGlobalDtors = IntPtr.Zero;
ReloadVtables(); ReloadVtables();
@ -382,7 +387,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
} }
[BizExport(CallingConvention.Cdecl, EntryPoint = "n228")] [BizExport(CallingConvention.Cdecl, EntryPoint = "n228")]
public int SysClockGetTime(int which, [In,Out] TimeSpec time) public int SysClockGetTime(int which, [In, Out] TimeSpec time)
{ {
time.Seconds = 1495889068; time.Seconds = 1495889068;
time.NanoSeconds = 0; time.NanoSeconds = 0;
@ -670,9 +675,14 @@ namespace BizHawk.Emulation.Cores.Waterbox
{ {
_sealedheap.Seal(); _sealedheap.Seal();
foreach (var h in _heaps) foreach (var h in _heaps)
h.Memory.SaveXorSnapshot(); {
if (h != _invisibleheap) // TODO: if we have more non-savestated heaps, refine this hack
h.Memory.SaveXorSnapshot();
}
foreach (var pe in _modules) foreach (var pe in _modules)
pe.Memory.SaveXorSnapshot(); {
pe.SealImportsAndTakeXorSnapshot();
}
} }
} }

View File

@ -39,7 +39,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
private readonly Dictionary<string, Section> _sectionsByName = new Dictionary<string, Section>(); private readonly Dictionary<string, Section> _sectionsByName = new Dictionary<string, Section>();
private readonly List<Section> _sections = new List<Section>(); private readonly List<Section> _sections = new List<Section>();
private Section _imports;
public string ModuleName { get; } public string ModuleName { get; }
@ -65,6 +65,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
/// </summary> /// </summary>
public IntPtr DtorList { get; private set; } public IntPtr DtorList { get; private set; }
// true if the imports have been set to readonly
private bool _importsSealed = false;
/*[UnmanagedFunctionPointer(CallingConvention.Winapi)] /*[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate bool DllEntry(IntPtr instance, int reason, IntPtr reserved); private delegate bool DllEntry(IntPtr instance, int reason, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Winapi)] [UnmanagedFunctionPointer(CallingConvention.Winapi)]
@ -158,6 +161,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
_sections.Add(section); _sections.Add(section);
_sectionsByName.Add(section.Name, section); _sectionsByName.Add(section.Name, section);
} }
_sectionsByName.TryGetValue(".idata", out _imports);
Mount(); Mount();
} }
@ -263,7 +267,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
module = new Dictionary<string, IntPtr>(); module = new Dictionary<string, IntPtr>();
ImportsByModule.Add(import.DLL, module); ImportsByModule.Add(import.DLL, module);
} }
module.Add(import.Name, Z.US(Start + import.Thunk)); var dest = Start + import.Thunk;
if (_imports == null || dest >= _imports.Start + _imports.Size || dest < _imports.Start)
throw new InvalidOperationException("Import record outside of .idata!");
module.Add(import.Name, Z.US(dest));
} }
Section midipix; Section midipix;
@ -296,6 +304,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
public void ConnectImports(string moduleName, IImportResolver module) public void ConnectImports(string moduleName, IImportResolver module)
{ {
// this is called once internally when bootstrapping, and externally
// when we need to restore a savestate from another run. so imports might or might not be sealed
if (_importsSealed && _imports != null)
Memory.Protect(_imports.Start, _imports.Size, MemoryBlock.Protection.RW);
Dictionary<string, IntPtr> imports; Dictionary<string, IntPtr> imports;
if (ImportsByModule.TryGetValue(moduleName, out imports)) if (ImportsByModule.TryGetValue(moduleName, out imports))
{ {
@ -305,6 +319,34 @@ namespace BizHawk.Emulation.Cores.Waterbox
Marshal.Copy(valueArray, 0, kvp.Value, 1); Marshal.Copy(valueArray, 0, kvp.Value, 1);
} }
} }
if (_importsSealed && _imports != null)
Memory.Protect(_imports.Start, _imports.Size, _imports.Prot);
}
public void SealImportsAndTakeXorSnapshot()
{
if (_importsSealed)
throw new InvalidOperationException("Imports already sealed!");
// save import values, then zero them all (for hash purposes), then take our snapshot, then load them again,
// then set the .idata area to read only
if (_imports != null)
{
var data = new byte[_imports.Size];
Marshal.Copy(Z.US(_imports.Start), data, 0, (int)_imports.Size);
WaterboxUtils.ZeroMemory(Z.US(_imports.Start), (long)_imports.Size);
Memory.SaveXorSnapshot();
Marshal.Copy(data, 0, Z.US(_imports.Start), (int)_imports.Size);
_imports.W = false;
Memory.Protect(_imports.Start, _imports.Size, _imports.Prot);
}
else
{
Memory.SaveXorSnapshot();
}
_importsSealed = true;
} }
private bool _disposed = false; private bool _disposed = false;
@ -323,6 +365,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
public void SaveStateBinary(BinaryWriter bw) public void SaveStateBinary(BinaryWriter bw)
{ {
if (!_importsSealed)
throw new InvalidOperationException(".idata sections must be closed before saving state");
bw.Write(MAGIC); bw.Write(MAGIC);
bw.Write(_fileHash); bw.Write(_fileHash);
bw.Write(Memory.XorHash); bw.Write(Memory.XorHash);
@ -341,6 +386,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
public void LoadStateBinary(BinaryReader br) public void LoadStateBinary(BinaryReader br)
{ {
if (!_importsSealed)
throw new InvalidOperationException(".idata sections must be closed before loading state");
if (br.ReadUInt64() != MAGIC) if (br.ReadUInt64() != MAGIC)
throw new InvalidOperationException("Magic not magic enough!"); throw new InvalidOperationException("Magic not magic enough!");
if (!br.ReadBytes(_fileHash.Length).SequenceEqual(_fileHash)) if (!br.ReadBytes(_fileHash.Length).SequenceEqual(_fileHash))

View File

@ -581,6 +581,8 @@ GPGX_EX int gpgx_init(const char *feromextension, ECL_ENTRY int (*feload_archive
update_viewport(); update_viewport();
gpgx_clear_sram(); gpgx_clear_sram();
load_archive_cb = NULL; // don't hold onto load_archive_cb for longer than we need it for
return 1; return 1;
} }