Example #1
0
        /// <summary>
        /// Adds a protection to the list of protections.
        /// </summary>
        /// <param name="address">Address of the protected region</param>
        /// <param name="size">Size of the protected region in bytes</param>
        /// <param name="permission">Memory permissions of the region</param>
        private void AddProtection(ulong address, ulong size, MemoryPermission permission)
        {
            ulong endAddress = address + size;
            var   overlaps   = Array.Empty <IntervalTreeNode <ulong, MemoryPermission> >();
            int   count;

            lock (_protections)
            {
                count = _protections.Get(address, endAddress, ref overlaps);

                if (count == 1 &&
                    overlaps[0].Start <= address &&
                    overlaps[0].End >= endAddress &&
                    overlaps[0].Value == permission)
                {
                    return;
                }

                ulong startAddress = address;

                for (int index = 0; index < count; index++)
                {
                    var protection = overlaps[index];

                    ulong            protAddress    = protection.Start;
                    ulong            protEndAddress = protection.End;
                    MemoryPermission protPermission = protection.Value;

                    _protections.Remove(protection);

                    if (protection.Value == permission)
                    {
                        if (startAddress > protAddress)
                        {
                            startAddress = protAddress;
                        }

                        if (endAddress < protEndAddress)
                        {
                            endAddress = protEndAddress;
                        }
                    }
                    else
                    {
                        if (startAddress > protAddress)
                        {
                            _protections.Add(protAddress, startAddress, protPermission);
                        }

                        if (endAddress < protEndAddress)
                        {
                            _protections.Add(endAddress, protEndAddress, protPermission);
                        }
                    }
                }

                _protections.Add(startAddress, endAddress, permission);
            }
        }
        /// <summary>
        /// Unmaps the specified range of memory and marks it as mapped internally.
        /// </summary>
        /// <remarks>
        /// Since this marks the range as mapped, the expectation is that the range will be mapped after calling this method.
        /// </remarks>
        /// <param name="location">Memory address to unmap and mark as mapped</param>
        /// <param name="size">Size of the range in bytes</param>
        public void UnmapAndMarkRangeAsMapped(IntPtr location, IntPtr size)
        {
            ulong startAddress = (ulong)location;
            ulong unmapSize    = (ulong)size;
            ulong endAddress   = startAddress + unmapSize;

            var overlaps = Array.Empty <IntervalTreeNode <ulong, byte> >();
            int count    = 0;

            lock (_mappings)
            {
                count = _mappings.Get(startAddress, endAddress, ref overlaps);
            }

            for (int index = 0; index < count; index++)
            {
                var overlap = overlaps[index];

                // Tree operations might modify the node start/end values, so save a copy before we modify the tree.
                ulong overlapStart = overlap.Start;
                ulong overlapEnd   = overlap.End;
                ulong overlapValue = overlap.Value;

                _mappings.Remove(overlap);

                ulong unmapStart = Math.Max(overlapStart, startAddress);
                ulong unmapEnd   = Math.Min(overlapEnd, endAddress);

                if (overlapStart < startAddress)
                {
                    startAddress = overlapStart;
                }

                if (overlapEnd > endAddress)
                {
                    endAddress = overlapEnd;
                }

                ulong currentAddress = unmapStart;
                while (currentAddress < unmapEnd)
                {
                    WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)currentAddress, 2);
                    currentAddress += PageSize;
                }
            }

            _mappings.Add(startAddress, endAddress, 0);
        }
Example #3
0
        /// <summary>
        /// Unreserves a range of memory that has been previously reserved with <see cref="ReserveRange"/>.
        /// </summary>
        /// <param name="address">Start address of the region to unreserve</param>
        /// <param name="size">Size in bytes of the region to unreserve</param>
        /// <exception cref="WindowsApiException">Thrown when the Windows API returns an error unreserving the memory</exception>
        public void UnreserveRange(ulong address, ulong size)
        {
            ulong endAddress = address + size;

            var overlaps = Array.Empty <IntervalTreeNode <ulong, ulong> >();
            int count;

            lock (_mappings)
            {
                count = _mappings.Get(address, endAddress, ref overlaps);

                for (int index = 0; index < count; index++)
                {
                    var overlap = overlaps[index];

                    if (IsMapped(overlap.Value))
                    {
                        if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)overlap.Start, 2))
                        {
                            throw new WindowsApiException("UnmapViewOfFile2");
                        }
                    }

                    _mappings.Remove(overlap);
                }
            }

            if (count > 1)
            {
                CheckFreeResult(WindowsApi.VirtualFree(
                                    (IntPtr)address,
                                    (IntPtr)size,
                                    AllocationType.Release | AllocationType.CoalescePlaceholders));
            }

            RemoveProtection(address, size);
        }
Example #4
0
        /// <summary>
        /// Splits a larger placeholder, slicing at the start and end address, for a new memory mapping.
        /// </summary>
        /// <param name="address">Address to split</param>
        /// <param name="size">Size of the new region</param>
        /// <param name="backingOffset">Offset in the shared memory that will be mapped</param>
        private void SplitForMap(ulong address, ulong size, ulong backingOffset)
        {
            ulong endAddress = address + size;

            var overlaps = Array.Empty <IntervalTreeNode <ulong, ulong> >();

            lock (_mappings)
            {
                int count = _mappings.Get(address, endAddress, ref overlaps);

                Debug.Assert(count == 1);
                Debug.Assert(!IsMapped(overlaps[0].Value));

                var overlap = overlaps[0];

                // Tree operations might modify the node start/end values, so save a copy before we modify the tree.
                ulong overlapStart = overlap.Start;
                ulong overlapEnd   = overlap.End;
                ulong overlapValue = overlap.Value;

                _mappings.Remove(overlap);

                bool overlapStartsBefore = overlapStart < address;
                bool overlapEndsAfter    = overlapEnd > endAddress;

                if (overlapStartsBefore && overlapEndsAfter)
                {
                    CheckFreeResult(WindowsApi.VirtualFree(
                                        (IntPtr)address,
                                        (IntPtr)size,
                                        AllocationType.Release | AllocationType.PreservePlaceholder));

                    _mappings.Add(overlapStart, address, overlapValue);
                    _mappings.Add(endAddress, overlapEnd, AddBackingOffset(overlapValue, endAddress - overlapStart));
                }
                else if (overlapStartsBefore)
                {
                    ulong overlappedSize = overlapEnd - address;

                    CheckFreeResult(WindowsApi.VirtualFree(
                                        (IntPtr)address,
                                        (IntPtr)overlappedSize,
                                        AllocationType.Release | AllocationType.PreservePlaceholder));

                    _mappings.Add(overlapStart, address, overlapValue);
                }
                else if (overlapEndsAfter)
                {
                    ulong overlappedSize = endAddress - overlapStart;

                    CheckFreeResult(WindowsApi.VirtualFree(
                                        (IntPtr)overlapStart,
                                        (IntPtr)overlappedSize,
                                        AllocationType.Release | AllocationType.PreservePlaceholder));

                    _mappings.Add(endAddress, overlapEnd, AddBackingOffset(overlapValue, overlappedSize));
                }

                _mappings.Add(address, endAddress, backingOffset);
            }
        }