internal override void UnprotectPageRange(byte *start, ulong size, bool force = false)
        {
            if (size == 0)
            {
                return;
            }

            if (UsePageProtection || force)
            {
                Win32MemoryProtectMethods.MEMORY_BASIC_INFORMATION memoryInfo1 = new Win32MemoryProtectMethods.MEMORY_BASIC_INFORMATION();
                int vQueryFirstOutput = Win32MemoryProtectMethods.VirtualQuery(start, &memoryInfo1, new UIntPtr(size));
                int vQueryFirstError  = Marshal.GetLastWin32Error();

                Win32MemoryProtectMethods.MemoryProtection oldProtection;
                bool status = Win32MemoryProtectMethods.VirtualProtect(start, new UIntPtr(size), Win32MemoryProtectMethods.MemoryProtection.READWRITE, out oldProtection);
                if (!status)
                {
                    int vProtectError = Marshal.GetLastWin32Error();

                    Win32MemoryProtectMethods.MEMORY_BASIC_INFORMATION memoryInfo2 = new Win32MemoryProtectMethods.MEMORY_BASIC_INFORMATION();
                    int vQuerySecondOutput = Win32MemoryProtectMethods.VirtualQuery(start, &memoryInfo2, new UIntPtr(size));
                    int vQuerySecondError  = Marshal.GetLastWin32Error();
                    Debugger.Break();
                }
            }
        }
        public static void Free(byte *p)
        {
            var remaining         = (int)((long)p % 4096);
            var firstWritablePage = p - remaining;

            for (int i = 0; i < remaining; i++)
            {
                if (firstWritablePage[i] != 0xED)
                {
                    throw new InvalidOperationException("Invalid memory usage, you killed Ed!");
                }
            }
            Win32MemoryProtectMethods.MemoryProtection protect;
            var address = firstWritablePage - 4096;

            // this will access the memory, which will error if this was already freed
            if (Win32MemoryProtectMethods.VirtualProtect(address, (UIntPtr)4096, Win32MemoryProtectMethods.MemoryProtection.READWRITE, out protect) ==
                false)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to VirtualProtect (ElectricFence) at address=" + new IntPtr(address));
            }
            var dwSize = *(int *)address;

            // decommit, not release, they are not available for reuse again, any
            // future access will throw
            if (Win32MemoryProtectMethods.VirtualFree(address, (UIntPtr)dwSize, Win32MemoryProtectMethods.FreeType.MEM_DECOMMIT) == false)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to VirtualFree (ElectricFence) at address=" + new IntPtr(address));
            }
        }
        public static byte *Allocate(int size)
        {
            var remaining   = size % 4096;
            var sizeInPages = (size / 4096) + (remaining == 0 ? 0 : 1);

            var allocatedSize = ((sizeInPages + 2) * 4096);
            var virtualAlloc  = Win32MemoryProtectMethods.VirtualAlloc(null, (UIntPtr)allocatedSize, Win32MemoryProtectMethods.AllocationType.COMMIT,
                                                                       Win32MemoryProtectMethods.MemoryProtection.READWRITE);

            if (virtualAlloc == null)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to VirtualAlloc (ElectricFence) size=" + size);
            }

            *(int *)virtualAlloc = allocatedSize;

            Win32MemoryProtectMethods.MemoryProtection protect;
            if (Win32MemoryProtectMethods.VirtualProtect(virtualAlloc, (UIntPtr)(4096), Win32MemoryProtectMethods.MemoryProtection.NOACCESS,
                                                         out protect) == false)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to VirtualProtect (ElectricFence) at address=" + new IntPtr(virtualAlloc));
            }

            if (Win32MemoryProtectMethods.VirtualProtect(virtualAlloc + (sizeInPages + 1) * 4096, (UIntPtr)(4096), Win32MemoryProtectMethods.MemoryProtection.NOACCESS,
                                                         out protect) == false)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to VirtualProtect (ElectricFence) at address=" + new IntPtr(virtualAlloc + (sizeInPages + 1) * 4096));
            }

            var firstWritablePage = virtualAlloc + 4096;

            Win32UnmanagedMemory.Set(firstWritablePage, 0xED, 4096 * sizeInPages); // don't assume zero'ed mem
            if (remaining == 0)
            {
                return(firstWritablePage);
            }
            // give the memory out so its end would be at the 2nd guard page
            return(firstWritablePage + (4096 - remaining));
        }