Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mini Dump segment size might be bigger than Int32 can fit #990

Merged
merged 1 commit into from
Apr 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 19 additions & 14 deletions src/Microsoft.Diagnostics.Runtime/src/Windows/AWEBasedCacheEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public override long PageOutData()
CachePage<UIntPtr> page = _pages[i];
if (page != null)
{
uint pagesToUnMap = (uint)(page.DataExtent / SystemPageSize) + (uint)((page.DataExtent % SystemPageSize) != 0 ? 1 : 0);
uint pagesToUnMap = (uint)(page.DataExtent / (ulong)SystemPageSize) + (uint)((page.DataExtent % (ulong)SystemPageSize) != 0 ? 1 : 0);

// We need to unmap the physical memory from this VM range and then free the VM range
bool unmapPhysicalPagesResult = CacheNativeMethods.AWE.MapUserPhysicalPages(page.Data, pagesToUnMap, pageArray: UIntPtr.Zero);
Expand All @@ -89,7 +89,7 @@ public override long PageOutData()
continue;
}

sizeRemoved += page.DataExtent;
sizeRemoved += (long)page.DataExtent;

bool virtualFreeRes = CacheNativeMethods.Memory.VirtualFree(page.Data, sizeToFree: UIntPtr.Zero, CacheNativeMethods.Memory.VirtualFreeType.Release);
if (!virtualFreeRes)
Expand Down Expand Up @@ -132,15 +132,15 @@ public override long PageOutData()
return sizeRemoved;
}

protected unsafe override uint InvokeCallbackWithDataPtr(CachePage<UIntPtr> page, Func<UIntPtr, uint, uint> callback)
protected unsafe override uint InvokeCallbackWithDataPtr(CachePage<UIntPtr> page, Func<UIntPtr, ulong, uint> callback)
{
return callback(page.Data, page.DataExtent);
}

protected override uint CopyDataFromPage(CachePage<UIntPtr> page, IntPtr buffer, uint inPageOffset, uint byteCount)
protected override uint CopyDataFromPage(CachePage<UIntPtr> page, IntPtr buffer, ulong inPageOffset, uint byteCount)
{
// Calculate how much of the requested read can be satisfied by the page
uint sizeRead = Math.Min(page.DataExtent - inPageOffset, byteCount);
uint sizeRead = (uint)Math.Min(page.DataExtent - inPageOffset, byteCount);

unsafe
{
Expand All @@ -150,24 +150,24 @@ protected override uint CopyDataFromPage(CachePage<UIntPtr> page, IntPtr buffer,
return sizeRead;
}

protected override (UIntPtr Data, uint DataExtent) GetPageDataAtOffset(uint pageAlignedOffset)
protected override (UIntPtr Data, ulong DataExtent) GetPageDataAtOffset(ulong pageAlignedOffset)
{
// NOTE: The caller ensures this method is not called concurrently

uint readSize;
if ((pageAlignedOffset + EntryPageSize) <= (uint)_segmentData.Size)
ulong readSize;
if (pageAlignedOffset + EntryPageSize <= _segmentData.Size)
{
readSize = EntryPageSize;
}
else
{
readSize = (uint)_segmentData.Size - pageAlignedOffset;
readSize = _segmentData.Size - pageAlignedOffset;
}

if (HeapSegmentCacheEventSource.Instance.IsEnabled())
HeapSegmentCacheEventSource.Instance.PageInDataStart((long)(_segmentData.VirtualAddress + pageAlignedOffset), readSize);
HeapSegmentCacheEventSource.Instance.PageInDataStart((long)(_segmentData.VirtualAddress + pageAlignedOffset), (long)readSize);

int startingMemoryPageNumber = (int)(pageAlignedOffset / AWEBasedCacheEntry.SystemPageSize);
ulong startingMemoryPageNumber = (pageAlignedOffset / (ulong)AWEBasedCacheEntry.SystemPageSize);

try
{
Expand All @@ -181,10 +181,15 @@ protected override (UIntPtr Data, uint DataExtent) GetPageDataAtOffset(uint page
if (vmPtr == UIntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());

uint numberOfPages = readSize / (uint)AWEBasedCacheEntry.SystemPageSize + (((readSize % AWEBasedCacheEntry.SystemPageSize) == 0) ? 0u : 1u);
ulong numberOfPages = readSize / (uint)AWEBasedCacheEntry.SystemPageSize + (((readSize % (ulong)AWEBasedCacheEntry.SystemPageSize) == 0) ? 0u : 1u);

// Map one VirtualAlloc sized page of our physical memory into the VM space, we have to adjust the pageFrameArray pointer as MapUserPhysicalPages only takes a page count and a page frame array starting point
bool mapPhysicalPagesResult = CacheNativeMethods.AWE.MapUserPhysicalPages(vmPtr, numberOfPages, _pageFrameArray + (startingMemoryPageNumber * UIntPtr.Size));
bool mapPhysicalPagesResult = CacheNativeMethods.AWE.MapUserPhysicalPages(
vmPtr,
numberOfPages,
new UIntPtr((ulong)_pageFrameArray + (startingMemoryPageNumber * (ulong)UIntPtr.Size))
);

if (!mapPhysicalPagesResult)
throw new Win32Exception(Marshal.GetLastWin32Error());

Expand Down Expand Up @@ -216,7 +221,7 @@ protected override void Dispose(bool disposing)
{
// NOTE: While VirtualAllocPageSize SHOULD be a multiple of SystemPageSize there is no guarantee I can find that says that is true always and everywhere
// so to be safe I make sure we don't leave any straggling pages behind if that is true.
uint numberOfPages = (uint)(page.DataExtent / SystemPageSize) + ((page.DataExtent % SystemPageSize) == 0 ? 0U : 1U);
uint numberOfPages = (uint)(page.DataExtent / (ulong)SystemPageSize) + ((page.DataExtent % (ulong)SystemPageSize) == 0 ? 0U : 1U);

// We need to unmap the physical memory from this VM range and then free the VM range
bool unmapPhysicalPagesResult = CacheNativeMethods.AWE.MapUserPhysicalPages(page.Data, numberOfPages, pageArray: UIntPtr.Zero);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,30 +43,30 @@ public override long PageOutData()
}
while (Interlocked.CompareExchange(ref _entrySize, newCurrent, oldCurrent) != oldCurrent);

return data.DataRemoved;
return (long)data.DataRemoved;
}

protected override uint EntryPageSize => SystemPageSize;

protected override (byte[] Data, uint DataExtent) GetPageDataAtOffset(uint pageAlignedOffset)
protected override (byte[] Data, ulong DataExtent) GetPageDataAtOffset(ulong pageAlignedOffset)
{
// NOTE: The caller ensures this method is not called concurrently

if (HeapSegmentCacheEventSource.Instance.IsEnabled())
HeapSegmentCacheEventSource.Instance.PageInDataStart((long)(_segmentData.VirtualAddress + pageAlignedOffset), EntryPageSize);

uint readSize;
if ((pageAlignedOffset + EntryPageSize) <= (uint)_segmentData.Size)
if (pageAlignedOffset + EntryPageSize <= _segmentData.Size)
{
readSize = EntryPageSize;
}
else
{
readSize = (uint)_segmentData.Size - pageAlignedOffset;
readSize = (uint)(_segmentData.Size - pageAlignedOffset);
}

bool pageInFailed = false;
using (MemoryMappedViewAccessor view = _mappedFile.CreateViewAccessor((long)_segmentData.FileOffset + pageAlignedOffset, size: (long)readSize, MemoryMappedFileAccess.Read))
using (MemoryMappedViewAccessor view = _mappedFile.CreateViewAccessor((long)_segmentData.FileOffset + (long)pageAlignedOffset, size: readSize, MemoryMappedFileAccess.Read))
{
try
{
Expand Down Expand Up @@ -119,7 +119,7 @@ protected override (byte[] Data, uint DataExtent) GetPageDataAtOffset(uint pageA
}
}

protected override uint InvokeCallbackWithDataPtr(CachePage<byte[]> page, Func<UIntPtr, uint, uint> callback)
protected override uint InvokeCallbackWithDataPtr(CachePage<byte[]> page, Func<UIntPtr, ulong, uint> callback)
{
unsafe
{
Expand All @@ -130,10 +130,10 @@ protected override uint InvokeCallbackWithDataPtr(CachePage<byte[]> page, Func<U
}
}

protected override uint CopyDataFromPage(CachePage<byte[]> page, IntPtr buffer, uint inPageOffset, uint byteCount)
protected override uint CopyDataFromPage(CachePage<byte[]> page, IntPtr buffer, ulong inPageOffset, uint byteCount)
{
// Calculate how much of the requested read can be satisfied by the page
uint sizeRead = Math.Min(page.DataExtent - inPageOffset, byteCount);
uint sizeRead = (uint)Math.Min(page.DataExtent - inPageOffset, byteCount);

unsafe
{
Expand All @@ -157,10 +157,10 @@ protected override void Dispose(bool disposing)
}
}

private (uint DataRemoved, uint ItemsSkipped) TryRemoveAllPagesFromCache(bool disposeLocks)
private (ulong DataRemoved, uint ItemsSkipped) TryRemoveAllPagesFromCache(bool disposeLocks)
{
// Assume we will be able to evict all non-null pages
uint dataRemoved = 0;
ulong dataRemoved = 0;
uint itemsSkipped = 0;

for (int i = 0; i < _pages.Length; i++)
Expand Down
35 changes: 18 additions & 17 deletions src/Microsoft.Diagnostics.Runtime/src/Windows/CacheEntryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ internal CacheEntryBase(MinidumpSegment segmentData, int derivedMinSize, Action<
_segmentData = segmentData;

int pageCount = (int)((_segmentData.End - _segmentData.VirtualAddress) / EntryPageSize);
if (((uint)(_segmentData.End - _segmentData.VirtualAddress) % EntryPageSize) != 0)

if ((_segmentData.End - _segmentData.VirtualAddress) % EntryPageSize != 0)
pageCount++;

_pages = new CachePage<T>[pageCount];
Expand Down Expand Up @@ -86,15 +87,15 @@ public override void GetDataForAddress(ulong address, uint byteCount, IntPtr buf
{
ThrowIfDisposed();

uint offset = (uint)(address - _segmentData.VirtualAddress);
ulong offset = address - _segmentData.VirtualAddress;

int bytesRemaining = (int)byteCount;

// NOTE: Seems silly to cache this here but it is a read of an abstract property and this method (and more specifically, ReadPageFromOffset who we pass this to) is the hottest
// of hot methods for perf in this class.
uint entryPageSize = EntryPageSize;

uint localBytesRead;
ulong localBytesRead;
do
{
ReadPageDataFromOffset(offset, buffer, (uint)bytesRemaining, entryPageSize, out localBytesRead);
Expand Down Expand Up @@ -148,7 +149,7 @@ protected void ThrowIfDisposed()
throw new ObjectDisposedException(GetType().Name);
}

private void ReadPageDataFromOffset(uint segmentOffset, IntPtr buffer, uint byteCount, uint entryPageSize, out uint bytesRead)
private void ReadPageDataFromOffset(ulong segmentOffset, IntPtr buffer, uint byteCount, uint entryPageSize, out ulong bytesRead)
{
int pageIndex = (int)(segmentOffset / entryPageSize);

Expand All @@ -159,24 +160,24 @@ private void ReadPageDataFromOffset(uint segmentOffset, IntPtr buffer, uint byte
return;
}

uint pageSegmentOffset = (uint)pageIndex * entryPageSize;
ulong pageSegmentOffset = (ulong)pageIndex * entryPageSize;

uint inPageOffset = (segmentOffset - pageSegmentOffset);
ulong inPageOffset = segmentOffset - pageSegmentOffset;

bytesRead = ReadPageDataFromOffset(pageIndex, inPageOffset, byteCount, buffer, dataReader: null);
}

protected abstract uint InvokeCallbackWithDataPtr(CachePage<T> page, Func<UIntPtr, uint, uint> callback);
protected abstract uint InvokeCallbackWithDataPtr(CachePage<T> page, Func<UIntPtr, ulong, uint> callback);

protected abstract uint CopyDataFromPage(CachePage<T> page, IntPtr buffer, uint inPageOffset, uint byteCount);
protected abstract uint CopyDataFromPage(CachePage<T> page, IntPtr buffer, ulong inPageOffset, uint byteCount);

protected abstract (T Data, uint DataExtent) GetPageDataAtOffset(uint pageAlignedOffset);
protected abstract (T Data, ulong DataExtent) GetPageDataAtOffset(ulong pageAlignedOffset);

private uint ReadPageDataFromOffset(int pageIndex, uint inPageOffset, uint byteCount, IntPtr buffer, Func<UIntPtr, uint, uint> dataReader)
private ulong ReadPageDataFromOffset(int pageIndex, ulong inPageOffset, uint byteCount, IntPtr buffer, Func<UIntPtr, ulong, uint> dataReader)
{
bool notifyCacheOfSizeUpdate = false;

uint sizeRead = 0;
ulong sizeRead = 0;
int addedSize = 0;

ReaderWriterLockSlim pageLock = _pageLocks[pageIndex];
Expand Down Expand Up @@ -212,9 +213,9 @@ private uint ReadPageDataFromOffset(int pageIndex, uint inPageOffset, uint byteC
// the write lock)
if (_pages[pageIndex] == null)
{
uint dataRange;
ulong dataRange;
T data;
(data, dataRange) = GetPageDataAtOffset((uint)pageIndex * EntryPageSize);
(data, dataRange) = GetPageDataAtOffset((ulong)pageIndex * EntryPageSize);

_pages[pageIndex] = new CachePage<T>(data, dataRange);

Expand Down Expand Up @@ -308,16 +309,16 @@ private bool ReadPageDataFromOffsetUntil(uint segmentOffset, byte[] terminatingS
// we are done, if not we have to copy the trailing bytes to the output (bytesRead) and skip the ones we added to check for a terminator when we start reading this page. The act of doing
// this could cascade and cause THIS page to also have 'trailing bytes', so we must continue this little adventure until the string terminates.
private static unsafe uint ProcessPageForSequenceTerminatingRead(UIntPtr data,
uint dataLength,
uint inPageOffset,
ulong dataLength,
ulong inPageOffset,
byte[] terminatingSequence,
List<byte> bytesRead,
ref List<byte> trailingBytes,
ref bool sawTerminatingSequence)
{
uint dataRead = 0;

uint availableDataOnPage = dataLength - inPageOffset;
ulong availableDataOnPage = dataLength - inPageOffset;
uint startOffsetAdjustment = 0;

if (trailingBytes != null && trailingBytes.Count != 0)
Expand Down Expand Up @@ -358,7 +359,7 @@ private static unsafe uint ProcessPageForSequenceTerminatingRead(UIntPtr data,

// If we will have left over bytes (i.e. the amount to read mod the length of the terminating sequence is not 0), then copy then to the trailingBytes buffer so we can
// process them on the next go around if we don't complete the read on this page.
uint leftoverByteCount = ((availableDataOnPage - startOffsetAdjustment) % (uint)terminatingSequence.Length);
ulong leftoverByteCount = ((availableDataOnPage - startOffsetAdjustment) % (uint)terminatingSequence.Length);
if (leftoverByteCount != 0)
{
// We will have straggling bytes if we don't complete the read on this page, so copy them to the trailingBytes list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ internal static bool AllocateUserPhysicalPages(ref uint numberOfPages, UIntPtr p
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AllocateUserPhysicalPages(IntPtr processHandle, ref UIntPtr numberOfPages, UIntPtr pageArray);

internal static bool MapUserPhysicalPages(UIntPtr virtualAddress, uint numberOfPages, UIntPtr pageArray)
internal static bool MapUserPhysicalPages(UIntPtr virtualAddress, ulong numberOfPages, UIntPtr pageArray)
{
UIntPtr numberOfPagesToMap = new UIntPtr(numberOfPages);
return MapUserPhysicalPages(virtualAddress, numberOfPagesToMap, pageArray);
Expand Down
4 changes: 2 additions & 2 deletions src/Microsoft.Diagnostics.Runtime/src/Windows/CachePage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ namespace Microsoft.Diagnostics.Runtime.Windows
{
internal class CachePage<T>
{
internal CachePage(T data, uint dataExtent)
internal CachePage(T data, ulong dataExtent)
{
Data = data;
DataExtent = dataExtent;
}

public T Data { get; }

public uint DataExtent { get; }
public ulong DataExtent { get; }
}
}