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;
}
// 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
InitStateBuffers();
@ -150,8 +159,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64
Tracer = new GPGXTraceBuffer(this, MemoryDomains, this);
(ServiceProvider as BasicServiceProvider).Register<ITraceable>(Tracer);
_elf.Seal();
}
catch
{

View File

@ -155,6 +155,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
context.SyscallVtable = _syscallVtable = AllocVtable(340);
context.LdsoVtable = _ldsoVtable = AllocVtable(7);
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();
@ -382,7 +387,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
[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.NanoSeconds = 0;
@ -670,9 +675,14 @@ namespace BizHawk.Emulation.Cores.Waterbox
{
_sealedheap.Seal();
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)
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 List<Section> _sections = new List<Section>();
private Section _imports;
public string ModuleName { get; }
@ -65,6 +65,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
/// </summary>
public IntPtr DtorList { get; private set; }
// true if the imports have been set to readonly
private bool _importsSealed = false;
/*[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate bool DllEntry(IntPtr instance, int reason, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
@ -158,6 +161,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
_sections.Add(section);
_sectionsByName.Add(section.Name, section);
}
_sectionsByName.TryGetValue(".idata", out _imports);
Mount();
}
@ -263,7 +267,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
module = new Dictionary<string, IntPtr>();
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;
@ -296,6 +304,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
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;
if (ImportsByModule.TryGetValue(moduleName, out imports))
{
@ -305,6 +319,34 @@ namespace BizHawk.Emulation.Cores.Waterbox
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;
@ -323,6 +365,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
public void SaveStateBinary(BinaryWriter bw)
{
if (!_importsSealed)
throw new InvalidOperationException(".idata sections must be closed before saving state");
bw.Write(MAGIC);
bw.Write(_fileHash);
bw.Write(Memory.XorHash);
@ -341,6 +386,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
public void LoadStateBinary(BinaryReader br)
{
if (!_importsSealed)
throw new InvalidOperationException(".idata sections must be closed before loading state");
if (br.ReadUInt64() != MAGIC)
throw new InvalidOperationException("Magic not magic enough!");
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();
gpgx_clear_sram();
load_archive_cb = NULL; // don't hold onto load_archive_cb for longer than we need it for
return 1;
}