Skip to content

Fix PerfMap crash when Enable IPC command is sent early in startup#124055

Open
Copilot wants to merge 2 commits intomainfrom
copilot/fix-runtime-issue-123438
Open

Fix PerfMap crash when Enable IPC command is sent early in startup#124055
Copilot wants to merge 2 commits intomainfrom
copilot/fix-runtime-issue-123438

Conversation

Copy link
Contributor

Copilot AI commented Feb 5, 2026

Description

Fixes #123438

PerfMap::Enable(sendExisting=true) crashes when a PerfMapEnable IPC command is received very early in startup (e.g., during PauseForDiagnosticsMonitor). At this point in the startup sequence:

 - GetAppDomain() returns NULL (AppDomain created in SystemDomain::Attach)
 - ExecutionManager::GetEEJitManager() returns NULL (EEJitManager created in ExecutionManager::Init)

Both are initialized after DiagnosticServerAdapter::Initialize, so IPC commands can arrive before these are ready.

Changes

 - Add null check for GetAppDomain() before calling IterateAssembliesEx
 - Add null check for GetEEJitManager() before iterating the JIT code heap

Both are safe to skip when null - no assemblies are loaded and no code is JIT'd at that point in startup. Future methods will still be logged as they are JIT'd.

Startup Timeline

     CodeVersionManager::StaticInitialize()   ← Lock initialized (safe to acquire)
     PerfMap::Initialize()
     DiagnosticServerAdapter::Initialize()    ← IPC listener starts
     PauseForDiagnosticsMonitor()             ← Can receive PerfMapEnable here!
     ...
     SystemDomain::Attach()                   ← AppDomain created
     ExecutionManager::Init()                 ← EEJitManager created

Testing

mdh1418 validated on a wsl2 instance, pausing the startup logic with DOTNET_DefaultDiagnosticPortSuspend=1 and kicking off a separate app invoking DiagnosticClient.EnablePerfMap. Before the change, it would sigsegv and crash.
After the changes, its resilient and doesn't crash.

Original prompt

Can you investigate ways to fix #123438


💡 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.

Copilot AI changed the title [WIP] Investigate ways to fix runtime issue 123438 Fix PerfMap crash when Enable IPC command is sent early in startup Feb 5, 2026
Copilot AI requested a review from mdh1418 February 5, 2026 19:06
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 6, 2026
AppDomain is created in SystemDomain::Attach, which runs after
DiagnosticServerAdapter::Initialize. A PerfMapEnable IPC command received
during PauseForDiagnosticsMonitor would crash calling IterateAssembliesEx
on null.

Safe to skip: no assemblies are loaded before SystemDomain::Attach.
EEJitManager is created in ExecutionManager::Init, which runs after
DiagnosticServerAdapter::Initialize. A PerfMapEnable IPC command received
during PauseForDiagnosticsMonitor would crash on null dereference.

Safe to skip: no JIT'd code exists before ExecutionManager::Init.

CodeVersionManager::LockHolder remains inside the null check intentionally -
the lock is only needed while iterating code versions, not for the null check.
The lock is already initialized in CodeVersionManager::StaticInitialize before
DiagnosticServerAdapter::Initialize.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a CoreCLR startup crash when a PerfMapEnable IPC command arrives very early (before AppDomain and/or EEJitManager are initialized), by making PerfMap::Enable(sendExisting: true) resilient to those components being unavailable.

Changes:

  • Guard assembly enumeration behind a null-check for GetAppDomain() to avoid calling IterateAssembliesEx before SystemDomain::Attach().
  • Guard JIT code heap enumeration behind a null-check for ExecutionManager::GetEEJitManager() to avoid iterating heaps before ExecutionManager::Init().
  • Reuse the EEJitManager* local when building the CodeHeapIterator.

@mdh1418 mdh1418 added area-VM-coreclr and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Feb 6, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @agocke
See info in area-owners.md if you want to be subscribed.


// Similarly, the EEJitManager may not exist yet if called before ExecutionManager::Init().
// In this case, there's no JIT'd code to log anyway.
EEJitManager *pJitManager = ExecutionManager::GetEEJitManager();
Copy link
Member

Choose a reason for hiding this comment

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

m_pEEJitManager that this returns is not Volatile so this still has a race conditions due to memory model issues. I do not think we want to make the statics like m_pEEJitManager Volatile.

I assume that we have a good reason to start listening to initialize perfmap very early before basic subsystems like code manager are ready. Is that correct?

If it is the case, I would introduce a new static Volatile<bool> s_perfmapReady set after we have everything in place to JIT managed code, and do an early out check using this bool variable.

Copy link
Member

Choose a reason for hiding this comment

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

we have a good reason to start listening to initialize perfmap very early before basic subsystems like code manager are ready. Is that correct?

I was aiming for simple changes that would make the runtime resilient to early PerfMap Enable commands, rather than adding logic to queue the EnablePerfMap request dependencies are all initiailized. Currently the only known instance of early perfmap enable is record-trace, but the crash behavior would still exist, as repro'd by DiagnosticClient.EnablePerfMap on an app suspended with DOTNET_DefaultDiagnosticPortSuspend=1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PerfMap Reenable Crashing from AssemblyIterator IterateAssembliesEx

3 participants