/* * ----------------------- * Memory Buffer Factories * ----------------------- */ /// <summary> /// Finds an appropriate location where a <see cref="MemoryBuffer"/>; /// or other memory allocation could be performed. /// Note: Please see remarks for this function. /// </summary> /// <param name = "size" > The space in bytes that the specific <see cref="MemoryBuffer"/> would require to accomodate.</param> /// <param name="minimumAddress">The minimum absolute address to find a buffer in.</param> /// <param name="maximumAddress">The maximum absolute address to find a buffer in.</param> /// <param name="isPrivateBuffer">Defines whether the buffer type created is a shared or private buffer.</param> /// <remarks> /// WARNING: /// Using this in a multithreaded environment can be dangerous, be careful. /// It is possible to have a race condition on memory allocation. /// If you want to just allocate memory, please use the provided <see cref="Allocate"/> function instead. /// </remarks> public BufferAllocationProperties FindBufferLocation(int size, long minimumAddress, long maximumAddress, bool isPrivateBuffer = false) { if (minimumAddress <= 0) { throw new ArgumentException("Please do not set the minimum address to 0 or negative. It collides with the return values of Windows API functions" + "where e.g. 0 is returned on failure but you can also allocate successfully on 0."); } int bufferSize = GetBufferSize(size, isPrivateBuffer); // Search through the buffer cache first. if (_pageCache != null) { for (int x = 0; x < _pageCache.Length; x++) { var pointer = GetBufferPointerInPageRange(ref _pageCache[x], bufferSize, (IntPtr)minimumAddress, (IntPtr)maximumAddress); if (pointer != IntPtr.Zero) { // Page cache contains a page that can "work". Check if this page is still valid by running VirtualQuery on it // and rechecking the new page. var memoryBasicInformation = new MEMORY_BASIC_INFORMATION(); var result = _virtualQueryFunction(Process.Handle, pointer, ref memoryBasicInformation); if (result == (UIntPtr)0) { throw new Exception("VirtualQuery failed. Result is 0."); } var newPointer = GetBufferPointerInPageRange(ref memoryBasicInformation, bufferSize, (IntPtr)minimumAddress, (IntPtr)maximumAddress); if (newPointer != IntPtr.Zero) { return(new BufferAllocationProperties(newPointer, bufferSize)); } } } } // Not found in cache, get all real pages and try find appropriate spot. var memoryPages = MemoryPages.GetPages(Process).ToArray(); _pageCache = memoryPages; for (int x = 0; x < memoryPages.Length; x++) { var pointer = GetBufferPointerInPageRange(ref memoryPages[x], bufferSize, (IntPtr)minimumAddress, (IntPtr)maximumAddress); if (pointer != IntPtr.Zero) { return(new BufferAllocationProperties(pointer, bufferSize)); } } throw new Exception($"Unable to find memory location to fit MemoryBuffer of size {size} ({bufferSize}) between {minimumAddress.ToString("X")} and {maximumAddress.ToString("X")}."); }
/* * ----------------------- * Memory Buffer Factories * ----------------------- */ /// <summary> /// Finds an appropriate location where a <see cref="MemoryBuffer"/>; /// or other memory allocation could be performed. /// Note: Please see remarks for this function. /// </summary> /// <param name = "size" > The space in bytes that the specific <see cref="MemoryBuffer"/> would require to accomodate.</param> /// <param name="minimumAddress">The minimum absolute address to find a buffer in.</param> /// <param name="maximumAddress">The maximum absolute address to find a buffer in.</param> /// <param name="isPrivateBuffer">Defines whether the buffer type created is a shared or private buffer.</param> /// <remarks> /// WARNING: /// Using this in a multithreaded environment can be dangerous, be careful. /// It is possible to have a race condition on memory allocation. /// If you want to just allocate memory, please use the provided <see cref="Allocate"/> function instead. /// </remarks> public BufferAllocationProperties FindBufferLocation(int size, nuint minimumAddress, nuint maximumAddress, bool isPrivateBuffer = false) { if (minimumAddress <= 0) { throw new ArgumentException("Please do not set the minimum address to 0 or negative. It collides with the return values of Windows API functions" + "where e.g. 0 is returned on failure but you can also allocate successfully on 0."); } int bufferSize = GetBufferSize(size, isPrivateBuffer); // Not found in cache, get all real pages and try find appropriate spot. var memoryPages = MemoryPages.GetPages(Process); for (int x = 0; x < memoryPages.Count; x++) { var pointer = GetBufferPointerInPageRange(memoryPages[x], bufferSize, minimumAddress, maximumAddress); if (pointer != 0) { return(new BufferAllocationProperties(pointer, bufferSize)); } } throw new Exception($"Unable to find memory location to fit MemoryBuffer of size {size} ({bufferSize}) between {minimumAddress} and {maximumAddress}."); }