Skip to content

Refactor PEFile and PEHeader to use ReadOnlySpan exclusively with zero-copy buffer sharing#2317

Merged
brianrob merged 21 commits into
mainfrom
copilot/refactor-pefile-and-peheader
Nov 11, 2025
Merged

Refactor PEFile and PEHeader to use ReadOnlySpan exclusively with zero-copy buffer sharing#2317
brianrob merged 21 commits into
mainfrom
copilot/refactor-pefile-and-peheader

Conversation

Copilot AI commented Oct 10, 2025

Copy link
Copy Markdown
Contributor

Overview

This PR completely refactors PEFile and PEHeader to use ReadOnlySpan<byte> exclusively instead of raw unsafe pointers, providing automatic bounds checking to prevent reading outside allocated buffers. The implementation uses zero-copy buffer sharing for optimal performance and eliminates all dual-path logic for a cleaner, more maintainable codebase.

Motivation

The existing implementation uses unsafe pointers (byte*, void*) to read PE file headers, which has several risks:

  • No automatic bounds validation when accessing memory
  • Potential to read beyond allocated buffer boundaries
  • Difficult to diagnose out-of-bounds access issues
  • Cannot handle PE files with imageHeaderOffset > 512 bytes (arbitrary limit in old implementation)
  • Cannot handle PE files with headers larger than 1024 bytes (arbitrary limit in old implementation)

Using ReadOnlySpan<byte> provides:

  • Built-in bounds checking at the span level
  • Clear, immediate exceptions when attempting out-of-bounds access
  • Modern .NET memory safety patterns
  • Better diagnostic error messages
  • Support for PE files with arbitrarily large headers and offsets

Key Design Pattern - Progressive Reads

  1. PEFile initially reads 1024 bytes
  2. PEHeader constructor validates only what it reads (DOS header, NT header)
  3. PEHeader calculates m_sectionsOffset for use by PEHeaderSize property
  4. PEFile checks if Header.PEHeaderSize > 1024 and re-reads with correct size if needed
  5. ReadOnlySpan bounds checking provides safety when sections are actually accessed

Safety Guarantees

  • All memory reads use ReadOnlySpan with automatic bounds checking
  • Invalid PE files with corrupt section counts will throw when sections are accessed
  • No possibility of reading beyond buffer boundaries
  • Clear error messages on out-of-bounds access

Performance

  • Zero-copy buffer sharing between PEBufferedReader and PEHeader via PEBufferedSlice struct
  • No unnecessary memory allocations
  • Efficient progressive reading for large headers

Compatibility

  • PEFile public API completely unchanged
  • All existing code continues to work
  • Breaking changes only to internal PEHeader APIs (removed pointer-based constructor)

Testing

Comprehensive Test Suite

Added 10 comprehensive tests in src/TraceEvent/TraceEvent.Tests/Utilities/PEFileTests.cs:

  • Basic PE file reading and managed assembly detection
  • Machine type detection (x86, x64, ARM, etc.)
  • PE32/PE64 handling
  • Data directory access
  • RVA to file offset conversion
  • Bounds checking validation
  • Error handling for invalid files
  • Multiple sequential reads
  • Comparison tests: Embeds original pointer-based implementation and validates identical results for both managed assemblies and native binaries (kernel32.dll)

All tests pass (9/10 on Linux, all 10 on Windows)

Test Applications - Demonstrating the Improvement

Added standalone test applications in src/TestApps/LargePEHeaderTest/ that clearly demonstrate the limitations of the old implementation:

Generated PE File Characteristics

  • PE header offset (imageHeaderOffset): 520 bytes - Exceeds the old implementation's 512-byte limit
  • Total header size: 1584 bytes - Exceeds the old implementation's 1024-byte limit
  • 20 sections - Demonstrates handling of many sections

Test Results

Running TestBothImplementations.csproj:

Old Implementation (OldPEFile.cs):

❌ FAILED to load with OLD implementation
Exception: System.InvalidOperationException: Bad PE Header.
   at OldPEFile.PEHeader..ctor(Void* startOfPEFile) in OldPEFile.cs:line 365

Fails the check: if (!(sizeof(IMAGE_DOS_HEADER) <= imageHeaderOffset && imageHeaderOffset <= 512))

New Implementation (PEFile with ReadOnlySpan):

✓ SUCCESS: File loaded with NEW implementation
PE Header Size: 1584 bytes
Number of Sections: 20
Machine: I386  
imageHeaderOffset: 520 bytes
All properties accessible, RVA conversion works correctly

Running the Tests

cd src/TestApps/LargePEHeaderTest
dotnet run --project LargePEHeaderGenerator.csproj
cd Tester && dotnet run --project TestBothImplementations.csproj ../LargeHeaderTest.exe

The test applications clearly demonstrate that:

  1. ❌ Old implementation rejects valid PE files with imageHeaderOffset > 512 bytes
  2. ✓ New implementation correctly handles these files
  3. ❌ Old implementation rejects valid PE files with headers > 1024 bytes
  4. ✓ New implementation supports arbitrarily large headers

Implementation Details

PEBufferedReader (renamed from PEBuffer)

  • Added FetchSpan(int filePos, int size) returning ReadOnlySpan<byte>
  • Added EnsureRead(int filePos, int size) returning PEBufferedSlice struct for zero-copy construction
  • Retained original Fetch() method returning byte* for backward compatibility

PEBufferedSlice (new struct)

  • Encapsulates buffer slice information with Buffer, Offset, Length properties
  • Provides AsSpan() method returning ReadOnlySpan<byte>

PEHeader (fully span-based)

  • Removed pointer-based constructor PEHeader(void*)
  • Removed pointer-based fields (dosHeader, ntHeader, sections)
  • Single internal constructor: PEHeader(PEBufferedSlice slice) for zero-allocation performance
  • Uses MemoryMarshal.Read<T>() and MemoryMarshal.Cast<T>() exclusively for safe structure access
  • Added GetBufferSpan(int offset, int length) helper for bounds-checked span slicing
  • All properties use span-based accessors with bounds validation
  • Removed arbitrary size limits (512 bytes for image header offset, 1024 bytes for sections offset)

PEFile (public API unchanged)

  • Modified constructor to use EnsureRead() and zero-copy PEHeader constructor
  • All public methods and properties maintain exact same signatures
  • Maintains backward compatibility for all consumers
Original prompt

PEFile.cs contains a PEFile reader. The reader uses unsafe to pass around a pointer a buffer that contains some of the PEFile that has been read into memory. I'd like to experiment with the possibility of using ReadOnlySpan instead to ensure that we don't attempt to read outside of the buffer. Please see if you can adjust the internals of PEFile and PEHeader to do this. It is OK to change the signature of methods in PEHeader, but do not change any of the public method signatures in PEFile.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor PEFile and PEHeader to use ReadOnlySpan<byte> Refactor PEFile and PEHeader to use ReadOnlySpan<byte> for bounds-checked memory access Oct 10, 2025
Copilot AI requested a review from brianrob October 10, 2025 18:37

@brianrob brianrob left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please address this comment.

Comment thread src/TraceEvent/TraceUtilities/PEFile.cs Outdated
public PEHeader(ReadOnlySpan<byte> peFileData)
{
// We need to copy the span data to a byte array since we can't store spans as fields
m_buffer = peFileData.ToArray();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to avoid copying the buffer here. Would it make more sense to fold PEHeader into PEFile so that the copy doesn't need to occur?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed by eliminating the buffer copy. Added an internal PEHeader(byte[] buffer, int offset, int length) constructor that references PEBuffer's existing byte array without copying. PEFile now uses PEBuffer.GetBufferInfo() to get the buffer parameters and constructs PEHeader with zero allocation overhead. The public PEHeader(ReadOnlySpan<byte>) constructor remains available for external callers that provide their own buffers. (commit fbbf797)

Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com>

Copilot AI commented Oct 10, 2025

Copy link
Copy Markdown
Contributor Author

@copilot please address this comment.

Addressed the buffer copy concern in commit 675ff78. PEHeader now references PEBuffer's existing byte array instead of copying it, eliminating unnecessary memory allocation.

Copilot AI changed the title Refactor PEFile and PEHeader to use ReadOnlySpan<byte> for bounds-checked memory access Refactor PEFile and PEHeader to use ReadOnlySpan with zero-copy buffer sharing Oct 10, 2025
Copilot AI requested a review from brianrob October 10, 2025 18:50

@brianrob brianrob left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please address these comments.


// Internal method to get buffer parameters for zero-copy PEHeader construction
internal void GetBufferInfo(int filePos, int size, out byte[] buffer, out int offset, out int length)
{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename this to EnsureRead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to EnsureRead in commit ec49a3a.

}
return &m_buffPtr[filePos - m_buffPos];
}
public ReadOnlySpan<byte> FetchSpan(int filePos, int size)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename PEBuffer to PEBufferedReader.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to PEBufferedReader in commit ec49a3a.


// Internal method to get buffer parameters for zero-copy PEHeader construction
internal void GetBufferInfo(int filePos, int size, out byte[] buffer, out int offset, out int length)
{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than returning 3 out parameters, please return a struct called PEBufferedSlice that contains properties for Buffer, Offset and Length. Please also add a method to the struct called AsSpan() that returns a ReadOnlySpan<byte> representing the slice.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created PEBufferedSlice struct with Buffer, Offset, Length properties and AsSpan() method in commit ec49a3a.

Comment thread src/TraceEvent/TraceUtilities/PEFile.cs Outdated
/// <summary>
/// Returns a PEHeader for ReadOnlySpan of bytes in memory. Validates buffer bounds.
/// </summary>
public PEHeader(ReadOnlySpan<byte> peFileData)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constructor is unused. Please remove it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the unused constructor in commit ec49a3a.

Comment thread src/TraceEvent/TraceUtilities/PEFile.cs Outdated
/// <summary>
/// Returns a PEHeader that references an existing buffer without copying. Validates buffer bounds.
/// </summary>
internal PEHeader(byte[] buffer, int offset, int length)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should take the new struct as a parameter. Then, just save the struct instead of m_buffer, m_bufferOffset, and m_bufferLength.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to take PEBufferedSlice and store it directly in commit ec49a3a.

Comment thread src/TraceEvent/TraceUtilities/PEFile.cs Outdated
}

IMAGE_DOS_HEADER dosHdr;
fixed (byte* bufferPtr = m_buffer)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to call AsSpan() here and then operate with the ReadOnlySpan instead of using unsafe here. That will ensure that we don't read off the end of the buffer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to use AsSpan() and MemoryMarshal.Read instead of unsafe pointer access in commit ec49a3a.

…PEBufferedReader, use AsSpan

Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com>

Copilot AI commented Oct 10, 2025

Copy link
Copy Markdown
Contributor Author

@copilot please address these comments.

All feedback addressed in commit ec49a3a. Created PEBufferedSlice struct, renamed to PEBufferedReader, renamed method to EnsureRead, removed unused constructor, and updated to use AsSpan() with MemoryMarshal.Read.

Copilot AI requested a review from brianrob October 10, 2025 23:23
Comment thread src/TraceEvent/TraceUtilities/PEFile.cs Outdated
throw new InvalidOperationException("GetDirectory only available with span-based PEHeader.");
}

private IMAGE_DOS_HEADER* dosHeader;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot, we shouldn't have two different paths with different fields that only work based on the constructor that was used. Instead, please move everything to be span based and remove the constructor that takes a raw pointer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed all dual-path logic in commit 7f1edfe. Eliminated the pointer-based constructor and all pointer fields (dosHeader, ntHeader, sections). Everything now uses the span-based approach exclusively with PEBufferedSlice and MemoryMarshal for safe, bounds-checked access.

…out PEHeader

Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com>
Copilot AI changed the title Refactor PEFile and PEHeader to use ReadOnlySpan with zero-copy buffer sharing Refactor PEFile and PEHeader to use ReadOnlySpan exclusively with zero-copy buffer sharing Oct 10, 2025
Copilot AI requested a review from brianrob October 10, 2025 23:45
@brianrob

Copy link
Copy Markdown
Member

@copilot, please add some tests to TraceEvent.Tests to validate that the changes in the PEFile class work.

Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com>
mitchellvette pushed a commit to mitchellvette/zenvizor that referenced this pull request Jul 1, 2026
Updated
[Microsoft.Diagnostics.Tracing.TraceEvent](https://github.com/Microsoft/perfview)
from 3.1.16 to 3.2.4.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Diagnostics.Tracing.TraceEvent's
releases](https://github.com/Microsoft/perfview/releases)._

## 3.2.4

## Security
This release contains security hardening fixes for a number of
malformed-input parsing and path-traversal vulnerabilities:
- Bounds-checking for malformed event payloads in the BPerf ULZ777
decompressor and event-record parser
- Bounds-checking for malformed metadata in the GCDynamic,
RegisteredTraceEventParser (TDH), Dynamic, and EventPipe V3 parsers
- Bounds-checking for malformed PE CodeView and Resource directory
entries
- Path containment hardening for PDB extraction (zipped ETL + container
PDBs), DiagSession resource extraction, R2R perf map writes, PdbScope
module paths, and dynamic manifest writes
- Path-traversal and command-execution hardening for Source Server
lookups

## What's Changed
* Update CsWin32 Package Version by @​brianrob in
microsoft/perfview#2425
* Fix incorrect field offsets when parsing ETW events with fixed-count
array fields by @​Copilot in
microsoft/perfview#2427
* Retarget Native Profiler Builds To VS 2026 V145 Toolset by @​brianrob
in microsoft/perfview#2428
* Stabilize XamlMessageBox UI-thread dispatch test by @​brianrob in
microsoft/perfview#2430

**Full Changelog**:
microsoft/perfview@v3.2.3...v3.2.4


## 3.2.3

## What's Changed
* Upgrade Microsoft.Windows.CsWin32 to 0.3.209 (GHSA-ghhp-997w-qr28) by
@​Copilot in microsoft/perfview#2409
* Enable Spectre mitigations and linker optimizations for EtwClrProfiler
by @​danmoseley in microsoft/perfview#2410
* Fix 'unhanded' / 'occured' typos in UnhandledExceptionDialog body text
by @​SAY-5 in microsoft/perfview#2413
* Fix GCStats failures on dotnet trace gc-verbose collections (#​2414)
by @​cincuranet in microsoft/perfview#2415
* C entrypoint fixes by @​zachcmadsen in
microsoft/perfview#2421

## New Contributors
* @​SAY-5 made their first contribution in
microsoft/perfview#2413

**Full Changelog**:
microsoft/perfview@v3.2.2...v3.2.3

## 3.2.2

## What's Changed
* Fix PDB Symbol Resolution for Unmerged Windows Traces by @​brianrob in
microsoft/perfview#2407


**Full Changelog**:
microsoft/perfview@v3.2.1...v3.2.2

## 3.2.1

## Native and R2R Symbol Download and Parsing Now Available
As of this release, if you capture a trace using [`dotnet-trace
collect-linux`](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-trace#dotnet-trace-collect-linux)
or
[`record-trace`](https://github.com/microsoft/one-collect/tree/main/record-trace),
**native and R2R symbols can now be downloaded and resolved at analysis
time**. All .NET symbols (both native and R2R) are available on the
Microsoft Symbol Server. Additionally, many Azure Linux symbol files are
available on the Microsoft Symbol Server. For those targeting other
distros, PerfView and TraceEvent are capable of pulling those symbol
files from local directories by adding a local symbol path pointing to
the files.

Most of the work for this was completed in PerfView and TraceEvent 3.2.1
with the final required fixes present in this release.

## What's Changed
* Optimize nettrace-to-TraceLog Conversion by @​brianrob in
microsoft/perfview#2403
* Embed missing System.Text.Json transitive dependencies in PerfView by
@​brianrob in microsoft/perfview#2404


**Full Changelog**:
microsoft/perfview@v3.2.0...v3.2.1

## 3.2.0

## What's Changed
* Fix Debug.Assert failures in SpeedScope tests and
DynamicTraceEventParser by @​brianrob in
microsoft/perfview#2368
* Add TraceParserGen.Tests project and fix code generation bugs by
@​Copilot in microsoft/perfview#2308
* Update UsersGuide.htm by @​AftabAnsari10662 in
microsoft/perfview#2370
* Strip .il and .ni suffixes from TraceModuleFile.Name by @​leculver in
microsoft/perfview#2364
* Handle provider names that start with a numeric digit. by @​brianrob
in microsoft/perfview#2369
* Dispose WebView2 controls before Environment.Exit to prevent finalizer
crash by @​brianrob in microsoft/perfview#2371
* Refactor GetManifestForRegisteredProvider to use XmlWriter by
@​Copilot in microsoft/perfview#2353
* docs: Add investigation guidance for JIT-inlined missing stack frames
by @​Copilot in microsoft/perfview#2377
* Fix spurious BROKEN frame at top of Linux thread stacks in CPU Stacks
viewer by @​Copilot in microsoft/perfview#2375
* Fix NRE in AddUniversalDynamicSymbol for invalid symbol address ranges
by @​brianrob in microsoft/perfview#2376
* Add missing authority parameter to log by @​hoyosjs in
microsoft/perfview#2379
* Replace individual code owners with microsoft/perfview-reviewers group
by @​brianrob in microsoft/perfview#2381
* Fix Dynamic Symbol Resolution for Mappings Shared Across Multiple
Processes in Universal Traces by @​brianrob in
microsoft/perfview#2380
* Implement Symbol Demanglers for Linux Binaries by @​brianrob in
microsoft/perfview#2383
* Fix NullReferenceException race condition in
TraceLog.AllocLookup/FreeLookup by @​Copilot in
microsoft/perfview#2387
* Add typed schema for AllocationSampled (EventID 303, .NET 10+) in
ClrTraceEventParser by @​Copilot in
microsoft/perfview#2388
* Add ElfSymbolModule for Parsing ELF Symbol Tables by @​brianrob in
microsoft/perfview#2384
* Update BDN to latest version. by @​cincuranet in
microsoft/perfview#2389
* Fixed overflow when working with large dumps by @​remilema in
microsoft/perfview#2399
* Fix XamlMessageBox STA Threading Crash from Background Threads by
@​brianrob in microsoft/perfview#2400
* Add ELF Symbol Resolution for Linux .nettrace Traces by @​brianrob in
microsoft/perfview#2397
* Add Missing WCF Event Templates by @​brianrob in
microsoft/perfview#2390

## New Contributors
* @​AftabAnsari10662 made their first contribution in
microsoft/perfview#2370
* @​remilema made their first contribution in
microsoft/perfview#2399

**Full Changelog**:
microsoft/perfview@v3.1.30...v3.2.0

## 3.1.30

## What's Changed
* doc: fix typos by @​chinwobble in
microsoft/perfview#2359
* Fix SourceLink parsing to support both wildcard and exact path
mappings by @​ivberg in microsoft/perfview#2355
* add horizontal scrolling to eventviewer by @​logangeorge01 in
microsoft/perfview#2361
* Add SHA-384 and SHA-512 hash algorithm support for PDB checksums by
@​Copilot in microsoft/perfview#2366

## New Contributors
* @​chinwobble made their first contribution in
microsoft/perfview#2359
* @​logangeorge01 made their first contribution in
microsoft/perfview#2361

**Full Changelog**:
microsoft/perfview@v3.1.29...v3.1.30

## 3.1.29

## What's Changed
* Warn users when circular buffer overflow causes missing type info in
allocation views for selected processes by @​Copilot in
microsoft/perfview#2326
* Special-Case BitMask Parsing by @​brianrob in
microsoft/perfview#2327
* Refactor PEFile and PEHeader to use ReadOnlySpan exclusively with
zero-copy buffer sharing by @​Copilot in
microsoft/perfview#2317
* Fix cdbstack parser dropping last sample and missing metrics by
@​Copilot in microsoft/perfview#2329
* Fix unhandled ArgumentOutOfRangeException when exporting FlameGraph
with unrendered canvas by @​Copilot in
microsoft/perfview#2339
* Add guidance for capturing ETW traces in Kubernetes pods by @​Copilot
in microsoft/perfview#2344
* Fix merge command line order in kubernetes documentation by @​Copilot
in microsoft/perfview#2346
* Fix GetRegisteredOrEnabledProviders() documentation claiming list is
small by @​Copilot in microsoft/perfview#2348
* Fix duplicate stringTable elements in instrumentation manifest by
@​Copilot in microsoft/perfview#2347
* Fix Histogram.AddMetric losing values after single-bucket to array
transition by @​Copilot in
microsoft/perfview#2337
* Fix clipboard copy formatting based on selection dimensions in Stack
Viewer by @​Copilot in microsoft/perfview#2332
* Fix XML escaping in GetManifestForRegisteredProvider by @​Copilot in
microsoft/perfview#2351
* Fix race condition in ProviderNameToGuid causing
ERROR_INSUFFICIENT_BUFFER crashes by @​Copilot in
microsoft/perfview#2357


**Full Changelog**:
microsoft/perfview@v3.1.28...v3.1.29

## 3.1.28

## What's Changed
* Add support for Boolean8 to NetTrace V6. by @​noahfalk in
microsoft/perfview#2318
* Implement A Thread Time View for Universal Traces by @​brianrob in
microsoft/perfview#2320
* Remove Incorrect Argument Description by @​brianrob in
microsoft/perfview#2323

**Full Changelog**:
microsoft/perfview@v3.1.26...v3.1.28

## 3.1.26

Roll-up through 2025/10/10.

* Only dispose non-null handles in `ETWTraceEventSource`
[#​2291](microsoft/perfview#2291)
* Small cleanup in `NettraceUniversalConverter`
[#​2292](microsoft/perfview#2292)
* Fix hyperlink focus visibility in dark mode and improve keyboard
navigation [#​2295](microsoft/perfview#2295)
* Gracefully handle invalid characters in `PATH`
[#​2296](microsoft/perfview#2296)
* Fix copying First/Last columns with pipe symbols to work in time range
input [#​2304](microsoft/perfview#2304)


## 3.1.24

Roll-up through 2025/08/26.

* Implement NuGet Central Package Version Management [#​2262]
* Fix broken stacks warning for universal traces [#​2268]
* Fix jitted code symbols in universal traces to show assembly names
instead of memfd:doublemapper [#​2269]
* Use themed background brush for menu and filter [#​2272]
* Improve rendering and dark mode [#​2274]
* Implement configurable symbol server authentication with /SymbolsAuth
command line argument for PerfView and HeapDump [#​2278]
* Add a themed dialog [#​2276]
* Fix regression: "Goto Item in Callers/Callees" now accumulates across
all threads [#​2284]
* Fix parsing issues and add support for additional events to the Linux
perf text file parser [#​2286]
* Fix TraceLog live session RelatedActivityID/ContainerID corruption by
preserving ExtendedData [#​2285]
* NetTrace LabelList metadata overrides and metadata flushing [#​2281]
* Fix NullReferenceException in ProviderBrowser.LevelSelected when
deselecting level [#​2289]

## 3.1.23

Roll-up through 2025/07/11.

- Fixed TraceEvent CaptureState API to support previously unsupported
keyword configurations. [#​2222]
- Added Exception Stacks view for .nettrace files to enhance exception
diagnostics. [#​2223]
- Corrected outdated documentation references to "GC Heap Alloc Stacks".
[#​2224]
- Fixed off-by-one error in P/Invoke buffer handling for Windows volume
events. [#​2227]
- Fixed broken links in the PerfView user guide. [#​2225]
- Improved error handling by throwing when TdhEnumerateProviders fails,
enabling better diagnostics. [#​2177]
- Added AutomationProperties.Name to the Process Selection DataGrid for
improved accessibility. [#​2239]
- Fixed focus indicator visibility for hyperlinks in dark mode and high
contrast themes. [#​2235]
- Addressed NullReferenceException in Anti-Malware view. [#​2233]
- Fixed WebView2 crash on close by implementing proper disposal pattern.
[#​2230]
- Added support for native AOT gcdumps, expanding compatibility with
modern .NET workloads. [#​2242]
- Fixed NVDA screen reader issue where Theme menu items did not announce
selection state. [#​2237]
- Extended PredefinedDynamicTraceEventParser to support dynamic events
from additional sources. [#​2232]
- Implemented MSFZ symbol format support in SymbolReader. [#​2244]
- Removed usage of DefaultAzureCredential, simplifying authentication
dependencies. [#​2255]
- Added option to hide TimeStamp columns in the EventWindow View menu.
[#​2247]
- Fixed NVDA screen reader reporting incorrect list count for File menu
separators. [#​2257]
- Fixed unhandled exception when double-clicking in scroll bar area with
no content. [#​2254]
- Fixed universal symbol conversion for overlapping mappings. [#​2252]
- Fixed TraceEvent.props to respect ProcessorArchitecture when
RuntimeIdentifier is set. [#​2249]

## 3.1.22

Roll-up through 2025/06/04.

- Added GC Heap Analyzer support for .nettrace files to enhance memory
analysis workflows. [#​2216]
- Introduced PredefinedDynamicTraceEventParser for known
TraceLogging events, improving trace event parsing. [#​2220]
- Enabled selection of process trees in the process selection dialog for
multi-process analysis, allowing deeper inspection across related
processes. [#​2195]
- Implemented sorting for the Duration column in the process selection
dialog using TotalDurationSeconds, improving usability. [#​2194]
- Improved NetTrace parameter parsing for better command-line
flexibility. [#​2200]
- Fixed GetActiveSessionNames to handle ERROR_MORE_DATA, resolving
session enumeration issues. [#​2196]
- Fixed ObjectDisposedException when opening Net OS Heap Alloc Stacks,
improving stability. [#​2212]
- Fixed null reference exception in GenFragmentationPercent method,
enhancing reliability. [#​2211]
 - Fixed TreeView auto-expansion when opening trace files. [#​2218]
- Fixed StackViewer issue where "Set Time Range" reset "Goto Items by
callees". [#​2208]
- Fixed markdown table formatting when copying from the stack viewer.
[#​2203]
- Fixed TraceEvent NuGet package to exclude Windows-specific native
DLLs. [#​2215]
- Removed PDB generation for .NET Core assemblies using CrossGen,
reducing build overhead. [#​2202]
- Made symbol server timeout configurable and removed dead code in
SymbolReader. [#​2209]
- Changed help ribbons to use textblocks, enabling tab navigation.
[#​2201]

## 3.1.21

Roll-up through 2025/05/02.

- Change NetTrace format version support
- Add /OSHeapMaxMB to set a max size for OS heap sessions
- Implement Nettrace Support for Traces with Universal Providers
- Implement R2R Symbol Lookup for Linux Traces
- Fix NetTrace parsing for Start/Stop event names
- Fix IndexOutOfRangeException in ProcessGlobalHistory

## 3.1.20

Roll-up through 2025/04/01.

 - Flamegraph and drill-in menu improvements
 - Performance improvements around unhandled event dispatch
 - Add configurable real-time delay in TraceLogEventSource
- Don't queue another flush during a real-time ETW session if one is
already in-process
- Allow configuration of rundown providers for real-time EventPipe
sessions
 - Fix stack handling for NetTrace V4
 - Add multi-line view for events viewer
 - Misc accessibility fixes

## 3.1.19

Roll-up through 2025/01/30.

 - Added missing time information in the Raw XML View for GCStats.
 - Updated activity computation logic to support OpenTelemetry events.
 - Changed timestamp values to use QPC time based on UTC for Relogger.
 - Fixed issues with report command handling.
 - Addressed various POH-related issues.
- Implemented file-size limitation for rundown using an ETW-based
approach.

## 3.1.18

Roll-up through 2024/12/11.

 - Fixed `perfcollect` install script on Azure Linux 3.
- Updated `System.Text.Json` to address
dotnet/announcements#329.

## 3.1.17

Roll-up through 2024/11/08.

- Numerous accessibility fixes to PerfView. This includes switching out
the previous web browser plugin to use WebView2.
- Breaking changes to FastSerialization to ensure that only expected
types are deserialized. This addresses potential vulnerabilities during
deserialization of untrusted input. Details at
microsoft/perfview#2121.

Commits viewable in [compare
view](microsoft/perfview@v3.1.16...v3.2.4).
</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Bad PE Header" exception thrown on valid executable image

3 participants