Emit platform-native line endings in requesting assembly chain - #127945

Merged
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain
May 15, 2026
Merged

Emit platform-native line endings in requesting assembly chain#127945
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain

Conversation

CopilotAI commented May 8, 2026

Copy link
Copy Markdown
Contributor
  • Update native chain construction in appdomain.cpp to use \r\n on Windows, \n on Unix
  • Remove ReplaceLineEndings() calls from BadImageFormatException.ToString(), FileLoadException.ToString(), and FileNotFoundException.ToString()
  • Rebuild CLR + libs successfully
  • Run existing MissingTransitiveDependency_ShowsRequestingAssemblyChain test - passes (39/39)
  • Run exception-specific tests (BadImageFormatException, FileLoadException, FileNotFoundException) - all pass
  • Run code review and CodeQL validation - passed
Original prompt

In dotnet/runtime, update the implementation from PR #125795 so the requesting assembly chain uses proper platform line endings when it is constructed in native code, instead of normalizing the chain later in managed ToString() overrides.

Context:

  • PR Include requesting assembly chain in assembly load failure exceptions #125795 added _requestingAssemblyChain to BadImageFormatException, FileLoadException, and FileNotFoundException.
  • The native chain builder currently appends transitive entries with a hard-coded LF separator, e.g. in src/coreclr/vm/appdomain.cpp:
    chain.Append(W("\n --> "));
  • The managed exception ToString() overrides compensate by calling _requestingAssemblyChain.ReplaceLineEndings() before formatting SR.IO_FileLoad_RequestedBy in:
    • src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.cs

Requested change:

  1. Change the native chain construction to append the correct platform newline (\n on Unix, \r\n on Windows) before -->, using an existing CoreCLR convention/helper/constant if one exists, or a small local/native helper/conditional if not.
  2. Remove the ReplaceLineEndings() calls from the three managed ToString() overrides and format _requestingAssemblyChain directly.
  3. Keep behavior equivalent: exception strings should still use platform-appropriate line endings and include the same requesting assembly chain text.
  4. Add or update tests if practical to cover/validate the line-ending behavior without making tests culture-sensitive. Avoid asserting localized text unless the test explicitly controls UI culture.

Please create a pull request with the fix.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: why do we need to call ReplaceLineEndings in the ToString overrides?

Assistant: We call ReplaceLineEndings() to normalize the embedded newlines inside _requestingAssemblyChain to the current platform’s newline convention before Exception.ToString() emits them.

The requesting chain is built in native code with hard-coded \n separators:

  • first assembly: LibB, Version=...
  • subsequent assemblies appended like: \n --> LibA, Version=...

But the managed ToString() implementations build the rest of the exception text using Environment.NewLineConst. On Windows that is \r\n, while the native chain would otherwise contain lone \n. So without:

_requestingAssemblyChain.ReplaceLineEndings()

the final exception string would mix line endings:

System.IO.FileNotFoundException: ...
\r\nFile name: ...
\r\nRequested by: LibB...
\n --> LibA...
\n --> Root...
\r\n at ...

With ReplaceLineEndings(), the chain’s internal separators match the rest of ToString() output.

So it’s not needed for the assembly-chain logic itself; it’s for consistent, platform-appropriate exception formatting and avoiding mixed line endings in logs, tests, and string consumers. On Unix it likely makes no observable difference, but on Windows it prevents LF-only continuation lines inside an otherwise CRLF-formatted exception string.

User: can we not use proper line endings in the native code?

Assistant: Yes, that would probably be better: have the native code emit the platform-appropriate newline in the diagnostic string, then the managed ToString() overrides can just format _requestingAssemblyChain directly.

Right now the native code hard-codes "\n --> ":

chain.Append(W("\n --> "));

That’s why the managed side normalizes with:

_requestingAssemblyChain.ReplaceLineEndings()

A cleaner alternative would be to use a native helper/constant for the runtime’s platform newline, e.g. conceptually:

#ifdef TARGET_UNIX
#defineCLR_NEWLINEW("\n")
#else
#defineCLR_NEWLINEW("\r\n")
#endif
chain.Append(CLR_NEWLINEW(" --> "));

or whatever existing CoreCLR convention/helper is preferred for platform newlines.

Then the managed side can become:

s+=Environment.NewLineConst+SR.Format(SR.IO_FileLoad_RequestedBy,_requestingAssemblyChain);

That avoids doing normalization every time ToString() is called and keeps the line-ending decision at the point where the multi-line string is constructed.

The main thing to watch for is not to use Environment.NewLine from native code directly, since this path is intentionally low-level exception construction and should avoid extra managed calls/allocations. But a native compile-time/platform constant would be fine.

User: make a pull request that does this

Assistant: I’m waiting for your response to the confirmation dialog so I can continue creating the pull request.

This pull request was created from Copilot chat.

CopilotAI self-assigned this May 8, 2026
CopilotAI review requested due to automatic review settings May 8, 2026 04:25
CopilotAI removed the request for review from CopilotMay 8, 2026 04:25
Copilot stopped work on behalf of MichalStrehovsky due to an error May 8, 2026 04:34
CopilotAI requested a review from MichalStrehovskyMay 8, 2026 04:34
…uction and remove managed ReplaceLineEndings() normalization
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f53f4e08-76fb-4fb1-bfb2-c79be29bf11e
Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotMay 8, 2026 05:04
@github-actionsgithub-actionsBot added the area-ExceptionHandling-coreclr only use for closed issues label May 8, 2026
@github-actionsgithub-actionsBot mentioned this pull request May 8, 2026
@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review May 8, 2026 07:01
CopilotAI review requested due to automatic review settings May 8, 2026 07:01
@MichalStrehovskyMichalStrehovsky changed the title [WIP] Update implementation for requesting assembly chain line endingsEmit platform-native line endings in requesting assembly chainMay 8, 2026
@MichalStrehovsky

Copy link
Copy Markdown
Member

Size statistics

Pull request #127945

ProjectSize beforeSize afterDifference
TodosApi-linux 24491512 24491512 0
TodosApi-windows 25798656 25797632 -1024
avalonia.app-linux 18904048 18904048 0
avalonia.app-windows 19444736 19443200 -1536
hello-linux 1254480 1250384 -4096
hello-minimal-linux 1106904 1106904 0
hello-minimal-windows 790016 779264 -10752
hello-windows 951296 938496 -12800
kestrel-minimal-linux 5273056 5273056 0
kestrel-minimal-windows 4820992 4819968 -1024
reflection-linux 1841160 1841160 0
reflection-windows 1716736 1703424 -13312
webapiaot-linux 9695728 9695728 0
webapiaot-windows 10231808 10230272 -1536
winrt-component-minimal-windows 738304 727040 -11264

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR makes the requesting-assembly chain string use platform-native newlines at the point it’s constructed in CoreCLR native code, allowing the managed ToString() overrides to emit _requestingAssemblyChain as-is (without later line-ending normalization).

Changes:

  • Updated AppDomain::GetParentAssemblyChain to append \r\n on Windows and \n on Unix before each " --> " continuation.
  • Removed _requestingAssemblyChain.ReplaceLineEndings() from ToString() in BadImageFormatException, FileLoadException, and FileNotFoundException.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

FileDescription
src/coreclr/vm/appdomain.cppEmits platform-native newlines when appending " --> " entries to the requesting-assembly chain.
src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.csStops normalizing requesting-chain line endings during ToString().

Comment threadsrc/coreclr/vm/appdomain.cpp
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g filed #127992 on the failure, can't seem to be able to rerun build analysis to pick it up

@MichalStrehovsky
MichalStrehovsky enabled auto-merge (squash) May 9, 2026 12:38
CopilotAI review requested due to automatic review settings May 13, 2026 04:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

@MichalStrehovsky
MichalStrehovsky merged commit 1858a24 into mainMay 15, 2026
152 of 157 checks passed
@MichalStrehovsky
MichalStrehovsky deleted the copilot/update-requesting-assembly-chain branch May 15, 2026 03:26
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

Python problem is dotnet/dnceng#6487.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 14, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@MichalStrehovsky@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Emit platform-native line endings in requesting assembly chain - #127945

Merged
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain
May 15, 2026
Merged

Emit platform-native line endings in requesting assembly chain#127945
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain

Conversation

CopilotAI commented May 8, 2026

Copy link
Copy Markdown
Contributor
  • Update native chain construction in appdomain.cpp to use \r\n on Windows, \n on Unix
  • Remove ReplaceLineEndings() calls from BadImageFormatException.ToString(), FileLoadException.ToString(), and FileNotFoundException.ToString()
  • Rebuild CLR + libs successfully
  • Run existing MissingTransitiveDependency_ShowsRequestingAssemblyChain test - passes (39/39)
  • Run exception-specific tests (BadImageFormatException, FileLoadException, FileNotFoundException) - all pass
  • Run code review and CodeQL validation - passed
Original prompt

In dotnet/runtime, update the implementation from PR #125795 so the requesting assembly chain uses proper platform line endings when it is constructed in native code, instead of normalizing the chain later in managed ToString() overrides.

Context:

  • PR Include requesting assembly chain in assembly load failure exceptions #125795 added _requestingAssemblyChain to BadImageFormatException, FileLoadException, and FileNotFoundException.
  • The native chain builder currently appends transitive entries with a hard-coded LF separator, e.g. in src/coreclr/vm/appdomain.cpp:
    chain.Append(W("\n --> "));
  • The managed exception ToString() overrides compensate by calling _requestingAssemblyChain.ReplaceLineEndings() before formatting SR.IO_FileLoad_RequestedBy in:
    • src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.cs

Requested change:

  1. Change the native chain construction to append the correct platform newline (\n on Unix, \r\n on Windows) before -->, using an existing CoreCLR convention/helper/constant if one exists, or a small local/native helper/conditional if not.
  2. Remove the ReplaceLineEndings() calls from the three managed ToString() overrides and format _requestingAssemblyChain directly.
  3. Keep behavior equivalent: exception strings should still use platform-appropriate line endings and include the same requesting assembly chain text.
  4. Add or update tests if practical to cover/validate the line-ending behavior without making tests culture-sensitive. Avoid asserting localized text unless the test explicitly controls UI culture.

Please create a pull request with the fix.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: why do we need to call ReplaceLineEndings in the ToString overrides?

Assistant: We call ReplaceLineEndings() to normalize the embedded newlines inside _requestingAssemblyChain to the current platform’s newline convention before Exception.ToString() emits them.

The requesting chain is built in native code with hard-coded \n separators:

  • first assembly: LibB, Version=...
  • subsequent assemblies appended like: \n --> LibA, Version=...

But the managed ToString() implementations build the rest of the exception text using Environment.NewLineConst. On Windows that is \r\n, while the native chain would otherwise contain lone \n. So without:

_requestingAssemblyChain.ReplaceLineEndings()

the final exception string would mix line endings:

System.IO.FileNotFoundException: ...
\r\nFile name: ...
\r\nRequested by: LibB...
\n --> LibA...
\n --> Root...
\r\n at ...

With ReplaceLineEndings(), the chain’s internal separators match the rest of ToString() output.

So it’s not needed for the assembly-chain logic itself; it’s for consistent, platform-appropriate exception formatting and avoiding mixed line endings in logs, tests, and string consumers. On Unix it likely makes no observable difference, but on Windows it prevents LF-only continuation lines inside an otherwise CRLF-formatted exception string.

User: can we not use proper line endings in the native code?

Assistant: Yes, that would probably be better: have the native code emit the platform-appropriate newline in the diagnostic string, then the managed ToString() overrides can just format _requestingAssemblyChain directly.

Right now the native code hard-codes "\n --> ":

chain.Append(W("\n --> "));

That’s why the managed side normalizes with:

_requestingAssemblyChain.ReplaceLineEndings()

A cleaner alternative would be to use a native helper/constant for the runtime’s platform newline, e.g. conceptually:

#ifdef TARGET_UNIX
#defineCLR_NEWLINEW("\n")
#else
#defineCLR_NEWLINEW("\r\n")
#endif
chain.Append(CLR_NEWLINEW(" --> "));

or whatever existing CoreCLR convention/helper is preferred for platform newlines.

Then the managed side can become:

s+=Environment.NewLineConst+SR.Format(SR.IO_FileLoad_RequestedBy,_requestingAssemblyChain);

That avoids doing normalization every time ToString() is called and keeps the line-ending decision at the point where the multi-line string is constructed.

The main thing to watch for is not to use Environment.NewLine from native code directly, since this path is intentionally low-level exception construction and should avoid extra managed calls/allocations. But a native compile-time/platform constant would be fine.

User: make a pull request that does this

Assistant: I’m waiting for your response to the confirmation dialog so I can continue creating the pull request.

This pull request was created from Copilot chat.

CopilotAI self-assigned this May 8, 2026
CopilotAI review requested due to automatic review settings May 8, 2026 04:25
CopilotAI removed the request for review from CopilotMay 8, 2026 04:25
Copilot stopped work on behalf of MichalStrehovsky due to an error May 8, 2026 04:34
CopilotAI requested a review from MichalStrehovskyMay 8, 2026 04:34
…uction and remove managed ReplaceLineEndings() normalization
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f53f4e08-76fb-4fb1-bfb2-c79be29bf11e
Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotMay 8, 2026 05:04
@github-actionsgithub-actionsBot added the area-ExceptionHandling-coreclr only use for closed issues label May 8, 2026
@github-actionsgithub-actionsBot mentioned this pull request May 8, 2026
@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review May 8, 2026 07:01
CopilotAI review requested due to automatic review settings May 8, 2026 07:01
@MichalStrehovskyMichalStrehovsky changed the title [WIP] Update implementation for requesting assembly chain line endingsEmit platform-native line endings in requesting assembly chainMay 8, 2026
@MichalStrehovsky

Copy link
Copy Markdown
Member

Size statistics

Pull request #127945

ProjectSize beforeSize afterDifference
TodosApi-linux 24491512 24491512 0
TodosApi-windows 25798656 25797632 -1024
avalonia.app-linux 18904048 18904048 0
avalonia.app-windows 19444736 19443200 -1536
hello-linux 1254480 1250384 -4096
hello-minimal-linux 1106904 1106904 0
hello-minimal-windows 790016 779264 -10752
hello-windows 951296 938496 -12800
kestrel-minimal-linux 5273056 5273056 0
kestrel-minimal-windows 4820992 4819968 -1024
reflection-linux 1841160 1841160 0
reflection-windows 1716736 1703424 -13312
webapiaot-linux 9695728 9695728 0
webapiaot-windows 10231808 10230272 -1536
winrt-component-minimal-windows 738304 727040 -11264

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR makes the requesting-assembly chain string use platform-native newlines at the point it’s constructed in CoreCLR native code, allowing the managed ToString() overrides to emit _requestingAssemblyChain as-is (without later line-ending normalization).

Changes:

  • Updated AppDomain::GetParentAssemblyChain to append \r\n on Windows and \n on Unix before each " --> " continuation.
  • Removed _requestingAssemblyChain.ReplaceLineEndings() from ToString() in BadImageFormatException, FileLoadException, and FileNotFoundException.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

FileDescription
src/coreclr/vm/appdomain.cppEmits platform-native newlines when appending " --> " entries to the requesting-assembly chain.
src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.csStops normalizing requesting-chain line endings during ToString().

Comment threadsrc/coreclr/vm/appdomain.cpp
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g filed #127992 on the failure, can't seem to be able to rerun build analysis to pick it up

@MichalStrehovsky
MichalStrehovsky enabled auto-merge (squash) May 9, 2026 12:38
CopilotAI review requested due to automatic review settings May 13, 2026 04:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

@MichalStrehovsky
MichalStrehovsky merged commit 1858a24 into mainMay 15, 2026
152 of 157 checks passed
@MichalStrehovsky
MichalStrehovsky deleted the copilot/update-requesting-assembly-chain branch May 15, 2026 03:26
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

Python problem is dotnet/dnceng#6487.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 14, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@MichalStrehovsky@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Emit platform-native line endings in requesting assembly chain - #127945

Merged
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain
May 15, 2026
Merged

Emit platform-native line endings in requesting assembly chain#127945
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain

Conversation

CopilotAI commented May 8, 2026

Copy link
Copy Markdown
Contributor
  • Update native chain construction in appdomain.cpp to use \r\n on Windows, \n on Unix
  • Remove ReplaceLineEndings() calls from BadImageFormatException.ToString(), FileLoadException.ToString(), and FileNotFoundException.ToString()
  • Rebuild CLR + libs successfully
  • Run existing MissingTransitiveDependency_ShowsRequestingAssemblyChain test - passes (39/39)
  • Run exception-specific tests (BadImageFormatException, FileLoadException, FileNotFoundException) - all pass
  • Run code review and CodeQL validation - passed
Original prompt

In dotnet/runtime, update the implementation from PR #125795 so the requesting assembly chain uses proper platform line endings when it is constructed in native code, instead of normalizing the chain later in managed ToString() overrides.

Context:

  • PR Include requesting assembly chain in assembly load failure exceptions #125795 added _requestingAssemblyChain to BadImageFormatException, FileLoadException, and FileNotFoundException.
  • The native chain builder currently appends transitive entries with a hard-coded LF separator, e.g. in src/coreclr/vm/appdomain.cpp:
    chain.Append(W("\n --> "));
  • The managed exception ToString() overrides compensate by calling _requestingAssemblyChain.ReplaceLineEndings() before formatting SR.IO_FileLoad_RequestedBy in:
    • src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.cs

Requested change:

  1. Change the native chain construction to append the correct platform newline (\n on Unix, \r\n on Windows) before -->, using an existing CoreCLR convention/helper/constant if one exists, or a small local/native helper/conditional if not.
  2. Remove the ReplaceLineEndings() calls from the three managed ToString() overrides and format _requestingAssemblyChain directly.
  3. Keep behavior equivalent: exception strings should still use platform-appropriate line endings and include the same requesting assembly chain text.
  4. Add or update tests if practical to cover/validate the line-ending behavior without making tests culture-sensitive. Avoid asserting localized text unless the test explicitly controls UI culture.

Please create a pull request with the fix.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: why do we need to call ReplaceLineEndings in the ToString overrides?

Assistant: We call ReplaceLineEndings() to normalize the embedded newlines inside _requestingAssemblyChain to the current platform’s newline convention before Exception.ToString() emits them.

The requesting chain is built in native code with hard-coded \n separators:

  • first assembly: LibB, Version=...
  • subsequent assemblies appended like: \n --> LibA, Version=...

But the managed ToString() implementations build the rest of the exception text using Environment.NewLineConst. On Windows that is \r\n, while the native chain would otherwise contain lone \n. So without:

_requestingAssemblyChain.ReplaceLineEndings()

the final exception string would mix line endings:

System.IO.FileNotFoundException: ...
\r\nFile name: ...
\r\nRequested by: LibB...
\n --> LibA...
\n --> Root...
\r\n at ...

With ReplaceLineEndings(), the chain’s internal separators match the rest of ToString() output.

So it’s not needed for the assembly-chain logic itself; it’s for consistent, platform-appropriate exception formatting and avoiding mixed line endings in logs, tests, and string consumers. On Unix it likely makes no observable difference, but on Windows it prevents LF-only continuation lines inside an otherwise CRLF-formatted exception string.

User: can we not use proper line endings in the native code?

Assistant: Yes, that would probably be better: have the native code emit the platform-appropriate newline in the diagnostic string, then the managed ToString() overrides can just format _requestingAssemblyChain directly.

Right now the native code hard-codes "\n --> ":

chain.Append(W("\n --> "));

That’s why the managed side normalizes with:

_requestingAssemblyChain.ReplaceLineEndings()

A cleaner alternative would be to use a native helper/constant for the runtime’s platform newline, e.g. conceptually:

#ifdef TARGET_UNIX
#defineCLR_NEWLINEW("\n")
#else
#defineCLR_NEWLINEW("\r\n")
#endif
chain.Append(CLR_NEWLINEW(" --> "));

or whatever existing CoreCLR convention/helper is preferred for platform newlines.

Then the managed side can become:

s+=Environment.NewLineConst+SR.Format(SR.IO_FileLoad_RequestedBy,_requestingAssemblyChain);

That avoids doing normalization every time ToString() is called and keeps the line-ending decision at the point where the multi-line string is constructed.

The main thing to watch for is not to use Environment.NewLine from native code directly, since this path is intentionally low-level exception construction and should avoid extra managed calls/allocations. But a native compile-time/platform constant would be fine.

User: make a pull request that does this

Assistant: I’m waiting for your response to the confirmation dialog so I can continue creating the pull request.

This pull request was created from Copilot chat.

CopilotAI self-assigned this May 8, 2026
CopilotAI review requested due to automatic review settings May 8, 2026 04:25
CopilotAI removed the request for review from CopilotMay 8, 2026 04:25
Copilot stopped work on behalf of MichalStrehovsky due to an error May 8, 2026 04:34
CopilotAI requested a review from MichalStrehovskyMay 8, 2026 04:34
…uction and remove managed ReplaceLineEndings() normalization
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f53f4e08-76fb-4fb1-bfb2-c79be29bf11e
Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotMay 8, 2026 05:04
@github-actionsgithub-actionsBot added the area-ExceptionHandling-coreclr only use for closed issues label May 8, 2026
@github-actionsgithub-actionsBot mentioned this pull request May 8, 2026
@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review May 8, 2026 07:01
CopilotAI review requested due to automatic review settings May 8, 2026 07:01
@MichalStrehovskyMichalStrehovsky changed the title [WIP] Update implementation for requesting assembly chain line endingsEmit platform-native line endings in requesting assembly chainMay 8, 2026
@MichalStrehovsky

Copy link
Copy Markdown
Member

Size statistics

Pull request #127945

ProjectSize beforeSize afterDifference
TodosApi-linux 24491512 24491512 0
TodosApi-windows 25798656 25797632 -1024
avalonia.app-linux 18904048 18904048 0
avalonia.app-windows 19444736 19443200 -1536
hello-linux 1254480 1250384 -4096
hello-minimal-linux 1106904 1106904 0
hello-minimal-windows 790016 779264 -10752
hello-windows 951296 938496 -12800
kestrel-minimal-linux 5273056 5273056 0
kestrel-minimal-windows 4820992 4819968 -1024
reflection-linux 1841160 1841160 0
reflection-windows 1716736 1703424 -13312
webapiaot-linux 9695728 9695728 0
webapiaot-windows 10231808 10230272 -1536
winrt-component-minimal-windows 738304 727040 -11264

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR makes the requesting-assembly chain string use platform-native newlines at the point it’s constructed in CoreCLR native code, allowing the managed ToString() overrides to emit _requestingAssemblyChain as-is (without later line-ending normalization).

Changes:

  • Updated AppDomain::GetParentAssemblyChain to append \r\n on Windows and \n on Unix before each " --> " continuation.
  • Removed _requestingAssemblyChain.ReplaceLineEndings() from ToString() in BadImageFormatException, FileLoadException, and FileNotFoundException.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

FileDescription
src/coreclr/vm/appdomain.cppEmits platform-native newlines when appending " --> " entries to the requesting-assembly chain.
src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.csStops normalizing requesting-chain line endings during ToString().

Comment threadsrc/coreclr/vm/appdomain.cpp
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g filed #127992 on the failure, can't seem to be able to rerun build analysis to pick it up

@MichalStrehovsky
MichalStrehovsky enabled auto-merge (squash) May 9, 2026 12:38
CopilotAI review requested due to automatic review settings May 13, 2026 04:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

@MichalStrehovsky
MichalStrehovsky merged commit 1858a24 into mainMay 15, 2026
152 of 157 checks passed
@MichalStrehovsky
MichalStrehovsky deleted the copilot/update-requesting-assembly-chain branch May 15, 2026 03:26
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

Python problem is dotnet/dnceng#6487.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 14, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@MichalStrehovsky@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Emit platform-native line endings in requesting assembly chain - #127945

Merged
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain
May 15, 2026
Merged

Emit platform-native line endings in requesting assembly chain#127945
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain

Conversation

CopilotAI commented May 8, 2026

Copy link
Copy Markdown
Contributor
  • Update native chain construction in appdomain.cpp to use \r\n on Windows, \n on Unix
  • Remove ReplaceLineEndings() calls from BadImageFormatException.ToString(), FileLoadException.ToString(), and FileNotFoundException.ToString()
  • Rebuild CLR + libs successfully
  • Run existing MissingTransitiveDependency_ShowsRequestingAssemblyChain test - passes (39/39)
  • Run exception-specific tests (BadImageFormatException, FileLoadException, FileNotFoundException) - all pass
  • Run code review and CodeQL validation - passed
Original prompt

In dotnet/runtime, update the implementation from PR #125795 so the requesting assembly chain uses proper platform line endings when it is constructed in native code, instead of normalizing the chain later in managed ToString() overrides.

Context:

  • PR Include requesting assembly chain in assembly load failure exceptions #125795 added _requestingAssemblyChain to BadImageFormatException, FileLoadException, and FileNotFoundException.
  • The native chain builder currently appends transitive entries with a hard-coded LF separator, e.g. in src/coreclr/vm/appdomain.cpp:
    chain.Append(W("\n --> "));
  • The managed exception ToString() overrides compensate by calling _requestingAssemblyChain.ReplaceLineEndings() before formatting SR.IO_FileLoad_RequestedBy in:
    • src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.cs

Requested change:

  1. Change the native chain construction to append the correct platform newline (\n on Unix, \r\n on Windows) before -->, using an existing CoreCLR convention/helper/constant if one exists, or a small local/native helper/conditional if not.
  2. Remove the ReplaceLineEndings() calls from the three managed ToString() overrides and format _requestingAssemblyChain directly.
  3. Keep behavior equivalent: exception strings should still use platform-appropriate line endings and include the same requesting assembly chain text.
  4. Add or update tests if practical to cover/validate the line-ending behavior without making tests culture-sensitive. Avoid asserting localized text unless the test explicitly controls UI culture.

Please create a pull request with the fix.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: why do we need to call ReplaceLineEndings in the ToString overrides?

Assistant: We call ReplaceLineEndings() to normalize the embedded newlines inside _requestingAssemblyChain to the current platform’s newline convention before Exception.ToString() emits them.

The requesting chain is built in native code with hard-coded \n separators:

  • first assembly: LibB, Version=...
  • subsequent assemblies appended like: \n --> LibA, Version=...

But the managed ToString() implementations build the rest of the exception text using Environment.NewLineConst. On Windows that is \r\n, while the native chain would otherwise contain lone \n. So without:

_requestingAssemblyChain.ReplaceLineEndings()

the final exception string would mix line endings:

System.IO.FileNotFoundException: ...
\r\nFile name: ...
\r\nRequested by: LibB...
\n --> LibA...
\n --> Root...
\r\n at ...

With ReplaceLineEndings(), the chain’s internal separators match the rest of ToString() output.

So it’s not needed for the assembly-chain logic itself; it’s for consistent, platform-appropriate exception formatting and avoiding mixed line endings in logs, tests, and string consumers. On Unix it likely makes no observable difference, but on Windows it prevents LF-only continuation lines inside an otherwise CRLF-formatted exception string.

User: can we not use proper line endings in the native code?

Assistant: Yes, that would probably be better: have the native code emit the platform-appropriate newline in the diagnostic string, then the managed ToString() overrides can just format _requestingAssemblyChain directly.

Right now the native code hard-codes "\n --> ":

chain.Append(W("\n --> "));

That’s why the managed side normalizes with:

_requestingAssemblyChain.ReplaceLineEndings()

A cleaner alternative would be to use a native helper/constant for the runtime’s platform newline, e.g. conceptually:

#ifdef TARGET_UNIX
#defineCLR_NEWLINEW("\n")
#else
#defineCLR_NEWLINEW("\r\n")
#endif
chain.Append(CLR_NEWLINEW(" --> "));

or whatever existing CoreCLR convention/helper is preferred for platform newlines.

Then the managed side can become:

s+=Environment.NewLineConst+SR.Format(SR.IO_FileLoad_RequestedBy,_requestingAssemblyChain);

That avoids doing normalization every time ToString() is called and keeps the line-ending decision at the point where the multi-line string is constructed.

The main thing to watch for is not to use Environment.NewLine from native code directly, since this path is intentionally low-level exception construction and should avoid extra managed calls/allocations. But a native compile-time/platform constant would be fine.

User: make a pull request that does this

Assistant: I’m waiting for your response to the confirmation dialog so I can continue creating the pull request.

This pull request was created from Copilot chat.

CopilotAI self-assigned this May 8, 2026
CopilotAI review requested due to automatic review settings May 8, 2026 04:25
CopilotAI removed the request for review from CopilotMay 8, 2026 04:25
Copilot stopped work on behalf of MichalStrehovsky due to an error May 8, 2026 04:34
CopilotAI requested a review from MichalStrehovskyMay 8, 2026 04:34
…uction and remove managed ReplaceLineEndings() normalization
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f53f4e08-76fb-4fb1-bfb2-c79be29bf11e
Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotMay 8, 2026 05:04
@github-actionsgithub-actionsBot added the area-ExceptionHandling-coreclr only use for closed issues label May 8, 2026
@github-actionsgithub-actionsBot mentioned this pull request May 8, 2026
@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review May 8, 2026 07:01
CopilotAI review requested due to automatic review settings May 8, 2026 07:01
@MichalStrehovskyMichalStrehovsky changed the title [WIP] Update implementation for requesting assembly chain line endingsEmit platform-native line endings in requesting assembly chainMay 8, 2026
@MichalStrehovsky

Copy link
Copy Markdown
Member

Size statistics

Pull request #127945

ProjectSize beforeSize afterDifference
TodosApi-linux 24491512 24491512 0
TodosApi-windows 25798656 25797632 -1024
avalonia.app-linux 18904048 18904048 0
avalonia.app-windows 19444736 19443200 -1536
hello-linux 1254480 1250384 -4096
hello-minimal-linux 1106904 1106904 0
hello-minimal-windows 790016 779264 -10752
hello-windows 951296 938496 -12800
kestrel-minimal-linux 5273056 5273056 0
kestrel-minimal-windows 4820992 4819968 -1024
reflection-linux 1841160 1841160 0
reflection-windows 1716736 1703424 -13312
webapiaot-linux 9695728 9695728 0
webapiaot-windows 10231808 10230272 -1536
winrt-component-minimal-windows 738304 727040 -11264

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR makes the requesting-assembly chain string use platform-native newlines at the point it’s constructed in CoreCLR native code, allowing the managed ToString() overrides to emit _requestingAssemblyChain as-is (without later line-ending normalization).

Changes:

  • Updated AppDomain::GetParentAssemblyChain to append \r\n on Windows and \n on Unix before each " --> " continuation.
  • Removed _requestingAssemblyChain.ReplaceLineEndings() from ToString() in BadImageFormatException, FileLoadException, and FileNotFoundException.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

FileDescription
src/coreclr/vm/appdomain.cppEmits platform-native newlines when appending " --> " entries to the requesting-assembly chain.
src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.csStops normalizing requesting-chain line endings during ToString().

Comment threadsrc/coreclr/vm/appdomain.cpp
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g filed #127992 on the failure, can't seem to be able to rerun build analysis to pick it up

@MichalStrehovsky
MichalStrehovsky enabled auto-merge (squash) May 9, 2026 12:38
CopilotAI review requested due to automatic review settings May 13, 2026 04:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

@MichalStrehovsky
MichalStrehovsky merged commit 1858a24 into mainMay 15, 2026
152 of 157 checks passed
@MichalStrehovsky
MichalStrehovsky deleted the copilot/update-requesting-assembly-chain branch May 15, 2026 03:26
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

Python problem is dotnet/dnceng#6487.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 14, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@MichalStrehovsky@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Emit platform-native line endings in requesting assembly chain - #127945

Merged
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain
May 15, 2026
Merged

Emit platform-native line endings in requesting assembly chain#127945
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain

Conversation

CopilotAI commented May 8, 2026

Copy link
Copy Markdown
Contributor
  • Update native chain construction in appdomain.cpp to use \r\n on Windows, \n on Unix
  • Remove ReplaceLineEndings() calls from BadImageFormatException.ToString(), FileLoadException.ToString(), and FileNotFoundException.ToString()
  • Rebuild CLR + libs successfully
  • Run existing MissingTransitiveDependency_ShowsRequestingAssemblyChain test - passes (39/39)
  • Run exception-specific tests (BadImageFormatException, FileLoadException, FileNotFoundException) - all pass
  • Run code review and CodeQL validation - passed
Original prompt

In dotnet/runtime, update the implementation from PR #125795 so the requesting assembly chain uses proper platform line endings when it is constructed in native code, instead of normalizing the chain later in managed ToString() overrides.

Context:

  • PR Include requesting assembly chain in assembly load failure exceptions #125795 added _requestingAssemblyChain to BadImageFormatException, FileLoadException, and FileNotFoundException.
  • The native chain builder currently appends transitive entries with a hard-coded LF separator, e.g. in src/coreclr/vm/appdomain.cpp:
    chain.Append(W("\n --> "));
  • The managed exception ToString() overrides compensate by calling _requestingAssemblyChain.ReplaceLineEndings() before formatting SR.IO_FileLoad_RequestedBy in:
    • src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.cs

Requested change:

  1. Change the native chain construction to append the correct platform newline (\n on Unix, \r\n on Windows) before -->, using an existing CoreCLR convention/helper/constant if one exists, or a small local/native helper/conditional if not.
  2. Remove the ReplaceLineEndings() calls from the three managed ToString() overrides and format _requestingAssemblyChain directly.
  3. Keep behavior equivalent: exception strings should still use platform-appropriate line endings and include the same requesting assembly chain text.
  4. Add or update tests if practical to cover/validate the line-ending behavior without making tests culture-sensitive. Avoid asserting localized text unless the test explicitly controls UI culture.

Please create a pull request with the fix.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: why do we need to call ReplaceLineEndings in the ToString overrides?

Assistant: We call ReplaceLineEndings() to normalize the embedded newlines inside _requestingAssemblyChain to the current platform’s newline convention before Exception.ToString() emits them.

The requesting chain is built in native code with hard-coded \n separators:

  • first assembly: LibB, Version=...
  • subsequent assemblies appended like: \n --> LibA, Version=...

But the managed ToString() implementations build the rest of the exception text using Environment.NewLineConst. On Windows that is \r\n, while the native chain would otherwise contain lone \n. So without:

_requestingAssemblyChain.ReplaceLineEndings()

the final exception string would mix line endings:

System.IO.FileNotFoundException: ...
\r\nFile name: ...
\r\nRequested by: LibB...
\n --> LibA...
\n --> Root...
\r\n at ...

With ReplaceLineEndings(), the chain’s internal separators match the rest of ToString() output.

So it’s not needed for the assembly-chain logic itself; it’s for consistent, platform-appropriate exception formatting and avoiding mixed line endings in logs, tests, and string consumers. On Unix it likely makes no observable difference, but on Windows it prevents LF-only continuation lines inside an otherwise CRLF-formatted exception string.

User: can we not use proper line endings in the native code?

Assistant: Yes, that would probably be better: have the native code emit the platform-appropriate newline in the diagnostic string, then the managed ToString() overrides can just format _requestingAssemblyChain directly.

Right now the native code hard-codes "\n --> ":

chain.Append(W("\n --> "));

That’s why the managed side normalizes with:

_requestingAssemblyChain.ReplaceLineEndings()

A cleaner alternative would be to use a native helper/constant for the runtime’s platform newline, e.g. conceptually:

#ifdef TARGET_UNIX
#defineCLR_NEWLINEW("\n")
#else
#defineCLR_NEWLINEW("\r\n")
#endif
chain.Append(CLR_NEWLINEW(" --> "));

or whatever existing CoreCLR convention/helper is preferred for platform newlines.

Then the managed side can become:

s+=Environment.NewLineConst+SR.Format(SR.IO_FileLoad_RequestedBy,_requestingAssemblyChain);

That avoids doing normalization every time ToString() is called and keeps the line-ending decision at the point where the multi-line string is constructed.

The main thing to watch for is not to use Environment.NewLine from native code directly, since this path is intentionally low-level exception construction and should avoid extra managed calls/allocations. But a native compile-time/platform constant would be fine.

User: make a pull request that does this

Assistant: I’m waiting for your response to the confirmation dialog so I can continue creating the pull request.

This pull request was created from Copilot chat.

CopilotAI self-assigned this May 8, 2026
CopilotAI review requested due to automatic review settings May 8, 2026 04:25
CopilotAI removed the request for review from CopilotMay 8, 2026 04:25
Copilot stopped work on behalf of MichalStrehovsky due to an error May 8, 2026 04:34
CopilotAI requested a review from MichalStrehovskyMay 8, 2026 04:34
…uction and remove managed ReplaceLineEndings() normalization
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f53f4e08-76fb-4fb1-bfb2-c79be29bf11e
Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotMay 8, 2026 05:04
@github-actionsgithub-actionsBot added the area-ExceptionHandling-coreclr only use for closed issues label May 8, 2026
@github-actionsgithub-actionsBot mentioned this pull request May 8, 2026
@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review May 8, 2026 07:01
CopilotAI review requested due to automatic review settings May 8, 2026 07:01
@MichalStrehovskyMichalStrehovsky changed the title [WIP] Update implementation for requesting assembly chain line endingsEmit platform-native line endings in requesting assembly chainMay 8, 2026
@MichalStrehovsky

Copy link
Copy Markdown
Member

Size statistics

Pull request #127945

ProjectSize beforeSize afterDifference
TodosApi-linux 24491512 24491512 0
TodosApi-windows 25798656 25797632 -1024
avalonia.app-linux 18904048 18904048 0
avalonia.app-windows 19444736 19443200 -1536
hello-linux 1254480 1250384 -4096
hello-minimal-linux 1106904 1106904 0
hello-minimal-windows 790016 779264 -10752
hello-windows 951296 938496 -12800
kestrel-minimal-linux 5273056 5273056 0
kestrel-minimal-windows 4820992 4819968 -1024
reflection-linux 1841160 1841160 0
reflection-windows 1716736 1703424 -13312
webapiaot-linux 9695728 9695728 0
webapiaot-windows 10231808 10230272 -1536
winrt-component-minimal-windows 738304 727040 -11264

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR makes the requesting-assembly chain string use platform-native newlines at the point it’s constructed in CoreCLR native code, allowing the managed ToString() overrides to emit _requestingAssemblyChain as-is (without later line-ending normalization).

Changes:

  • Updated AppDomain::GetParentAssemblyChain to append \r\n on Windows and \n on Unix before each " --> " continuation.
  • Removed _requestingAssemblyChain.ReplaceLineEndings() from ToString() in BadImageFormatException, FileLoadException, and FileNotFoundException.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

FileDescription
src/coreclr/vm/appdomain.cppEmits platform-native newlines when appending " --> " entries to the requesting-assembly chain.
src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.csStops normalizing requesting-chain line endings during ToString().

Comment threadsrc/coreclr/vm/appdomain.cpp
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g filed #127992 on the failure, can't seem to be able to rerun build analysis to pick it up

@MichalStrehovsky
MichalStrehovsky enabled auto-merge (squash) May 9, 2026 12:38
CopilotAI review requested due to automatic review settings May 13, 2026 04:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

@MichalStrehovsky
MichalStrehovsky merged commit 1858a24 into mainMay 15, 2026
152 of 157 checks passed
@MichalStrehovsky
MichalStrehovsky deleted the copilot/update-requesting-assembly-chain branch May 15, 2026 03:26
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

Python problem is dotnet/dnceng#6487.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 14, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@MichalStrehovsky@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Emit platform-native line endings in requesting assembly chain - #127945

Merged
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain
May 15, 2026
Merged

Emit platform-native line endings in requesting assembly chain#127945
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain

Conversation

CopilotAI commented May 8, 2026

Copy link
Copy Markdown
Contributor
  • Update native chain construction in appdomain.cpp to use \r\n on Windows, \n on Unix
  • Remove ReplaceLineEndings() calls from BadImageFormatException.ToString(), FileLoadException.ToString(), and FileNotFoundException.ToString()
  • Rebuild CLR + libs successfully
  • Run existing MissingTransitiveDependency_ShowsRequestingAssemblyChain test - passes (39/39)
  • Run exception-specific tests (BadImageFormatException, FileLoadException, FileNotFoundException) - all pass
  • Run code review and CodeQL validation - passed
Original prompt

In dotnet/runtime, update the implementation from PR #125795 so the requesting assembly chain uses proper platform line endings when it is constructed in native code, instead of normalizing the chain later in managed ToString() overrides.

Context:

  • PR Include requesting assembly chain in assembly load failure exceptions #125795 added _requestingAssemblyChain to BadImageFormatException, FileLoadException, and FileNotFoundException.
  • The native chain builder currently appends transitive entries with a hard-coded LF separator, e.g. in src/coreclr/vm/appdomain.cpp:
    chain.Append(W("\n --> "));
  • The managed exception ToString() overrides compensate by calling _requestingAssemblyChain.ReplaceLineEndings() before formatting SR.IO_FileLoad_RequestedBy in:
    • src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.cs

Requested change:

  1. Change the native chain construction to append the correct platform newline (\n on Unix, \r\n on Windows) before -->, using an existing CoreCLR convention/helper/constant if one exists, or a small local/native helper/conditional if not.
  2. Remove the ReplaceLineEndings() calls from the three managed ToString() overrides and format _requestingAssemblyChain directly.
  3. Keep behavior equivalent: exception strings should still use platform-appropriate line endings and include the same requesting assembly chain text.
  4. Add or update tests if practical to cover/validate the line-ending behavior without making tests culture-sensitive. Avoid asserting localized text unless the test explicitly controls UI culture.

Please create a pull request with the fix.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: why do we need to call ReplaceLineEndings in the ToString overrides?

Assistant: We call ReplaceLineEndings() to normalize the embedded newlines inside _requestingAssemblyChain to the current platform’s newline convention before Exception.ToString() emits them.

The requesting chain is built in native code with hard-coded \n separators:

  • first assembly: LibB, Version=...
  • subsequent assemblies appended like: \n --> LibA, Version=...

But the managed ToString() implementations build the rest of the exception text using Environment.NewLineConst. On Windows that is \r\n, while the native chain would otherwise contain lone \n. So without:

_requestingAssemblyChain.ReplaceLineEndings()

the final exception string would mix line endings:

System.IO.FileNotFoundException: ...
\r\nFile name: ...
\r\nRequested by: LibB...
\n --> LibA...
\n --> Root...
\r\n at ...

With ReplaceLineEndings(), the chain’s internal separators match the rest of ToString() output.

So it’s not needed for the assembly-chain logic itself; it’s for consistent, platform-appropriate exception formatting and avoiding mixed line endings in logs, tests, and string consumers. On Unix it likely makes no observable difference, but on Windows it prevents LF-only continuation lines inside an otherwise CRLF-formatted exception string.

User: can we not use proper line endings in the native code?

Assistant: Yes, that would probably be better: have the native code emit the platform-appropriate newline in the diagnostic string, then the managed ToString() overrides can just format _requestingAssemblyChain directly.

Right now the native code hard-codes "\n --> ":

chain.Append(W("\n --> "));

That’s why the managed side normalizes with:

_requestingAssemblyChain.ReplaceLineEndings()

A cleaner alternative would be to use a native helper/constant for the runtime’s platform newline, e.g. conceptually:

#ifdef TARGET_UNIX
#defineCLR_NEWLINEW("\n")
#else
#defineCLR_NEWLINEW("\r\n")
#endif
chain.Append(CLR_NEWLINEW(" --> "));

or whatever existing CoreCLR convention/helper is preferred for platform newlines.

Then the managed side can become:

s+=Environment.NewLineConst+SR.Format(SR.IO_FileLoad_RequestedBy,_requestingAssemblyChain);

That avoids doing normalization every time ToString() is called and keeps the line-ending decision at the point where the multi-line string is constructed.

The main thing to watch for is not to use Environment.NewLine from native code directly, since this path is intentionally low-level exception construction and should avoid extra managed calls/allocations. But a native compile-time/platform constant would be fine.

User: make a pull request that does this

Assistant: I’m waiting for your response to the confirmation dialog so I can continue creating the pull request.

This pull request was created from Copilot chat.

CopilotAI self-assigned this May 8, 2026
CopilotAI review requested due to automatic review settings May 8, 2026 04:25
CopilotAI removed the request for review from CopilotMay 8, 2026 04:25
Copilot stopped work on behalf of MichalStrehovsky due to an error May 8, 2026 04:34
CopilotAI requested a review from MichalStrehovskyMay 8, 2026 04:34
…uction and remove managed ReplaceLineEndings() normalization
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f53f4e08-76fb-4fb1-bfb2-c79be29bf11e
Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotMay 8, 2026 05:04
@github-actionsgithub-actionsBot added the area-ExceptionHandling-coreclr only use for closed issues label May 8, 2026
@github-actionsgithub-actionsBot mentioned this pull request May 8, 2026
@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review May 8, 2026 07:01
CopilotAI review requested due to automatic review settings May 8, 2026 07:01
@MichalStrehovskyMichalStrehovsky changed the title [WIP] Update implementation for requesting assembly chain line endingsEmit platform-native line endings in requesting assembly chainMay 8, 2026
@MichalStrehovsky

Copy link
Copy Markdown
Member

Size statistics

Pull request #127945

ProjectSize beforeSize afterDifference
TodosApi-linux 24491512 24491512 0
TodosApi-windows 25798656 25797632 -1024
avalonia.app-linux 18904048 18904048 0
avalonia.app-windows 19444736 19443200 -1536
hello-linux 1254480 1250384 -4096
hello-minimal-linux 1106904 1106904 0
hello-minimal-windows 790016 779264 -10752
hello-windows 951296 938496 -12800
kestrel-minimal-linux 5273056 5273056 0
kestrel-minimal-windows 4820992 4819968 -1024
reflection-linux 1841160 1841160 0
reflection-windows 1716736 1703424 -13312
webapiaot-linux 9695728 9695728 0
webapiaot-windows 10231808 10230272 -1536
winrt-component-minimal-windows 738304 727040 -11264

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR makes the requesting-assembly chain string use platform-native newlines at the point it’s constructed in CoreCLR native code, allowing the managed ToString() overrides to emit _requestingAssemblyChain as-is (without later line-ending normalization).

Changes:

  • Updated AppDomain::GetParentAssemblyChain to append \r\n on Windows and \n on Unix before each " --> " continuation.
  • Removed _requestingAssemblyChain.ReplaceLineEndings() from ToString() in BadImageFormatException, FileLoadException, and FileNotFoundException.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

FileDescription
src/coreclr/vm/appdomain.cppEmits platform-native newlines when appending " --> " entries to the requesting-assembly chain.
src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.csStops normalizing requesting-chain line endings during ToString().

Comment threadsrc/coreclr/vm/appdomain.cpp
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g filed #127992 on the failure, can't seem to be able to rerun build analysis to pick it up

@MichalStrehovsky
MichalStrehovsky enabled auto-merge (squash) May 9, 2026 12:38
CopilotAI review requested due to automatic review settings May 13, 2026 04:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

@MichalStrehovsky
MichalStrehovsky merged commit 1858a24 into mainMay 15, 2026
152 of 157 checks passed
@MichalStrehovsky
MichalStrehovsky deleted the copilot/update-requesting-assembly-chain branch May 15, 2026 03:26
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

Python problem is dotnet/dnceng#6487.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 14, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@MichalStrehovsky@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Emit platform-native line endings in requesting assembly chain - #127945

Merged
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain
May 15, 2026
Merged

Emit platform-native line endings in requesting assembly chain#127945
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain

Conversation

CopilotAI commented May 8, 2026

Copy link
Copy Markdown
Contributor
  • Update native chain construction in appdomain.cpp to use \r\n on Windows, \n on Unix
  • Remove ReplaceLineEndings() calls from BadImageFormatException.ToString(), FileLoadException.ToString(), and FileNotFoundException.ToString()
  • Rebuild CLR + libs successfully
  • Run existing MissingTransitiveDependency_ShowsRequestingAssemblyChain test - passes (39/39)
  • Run exception-specific tests (BadImageFormatException, FileLoadException, FileNotFoundException) - all pass
  • Run code review and CodeQL validation - passed
Original prompt

In dotnet/runtime, update the implementation from PR #125795 so the requesting assembly chain uses proper platform line endings when it is constructed in native code, instead of normalizing the chain later in managed ToString() overrides.

Context:

  • PR Include requesting assembly chain in assembly load failure exceptions #125795 added _requestingAssemblyChain to BadImageFormatException, FileLoadException, and FileNotFoundException.
  • The native chain builder currently appends transitive entries with a hard-coded LF separator, e.g. in src/coreclr/vm/appdomain.cpp:
    chain.Append(W("\n --> "));
  • The managed exception ToString() overrides compensate by calling _requestingAssemblyChain.ReplaceLineEndings() before formatting SR.IO_FileLoad_RequestedBy in:
    • src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.cs

Requested change:

  1. Change the native chain construction to append the correct platform newline (\n on Unix, \r\n on Windows) before -->, using an existing CoreCLR convention/helper/constant if one exists, or a small local/native helper/conditional if not.
  2. Remove the ReplaceLineEndings() calls from the three managed ToString() overrides and format _requestingAssemblyChain directly.
  3. Keep behavior equivalent: exception strings should still use platform-appropriate line endings and include the same requesting assembly chain text.
  4. Add or update tests if practical to cover/validate the line-ending behavior without making tests culture-sensitive. Avoid asserting localized text unless the test explicitly controls UI culture.

Please create a pull request with the fix.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: why do we need to call ReplaceLineEndings in the ToString overrides?

Assistant: We call ReplaceLineEndings() to normalize the embedded newlines inside _requestingAssemblyChain to the current platform’s newline convention before Exception.ToString() emits them.

The requesting chain is built in native code with hard-coded \n separators:

  • first assembly: LibB, Version=...
  • subsequent assemblies appended like: \n --> LibA, Version=...

But the managed ToString() implementations build the rest of the exception text using Environment.NewLineConst. On Windows that is \r\n, while the native chain would otherwise contain lone \n. So without:

_requestingAssemblyChain.ReplaceLineEndings()

the final exception string would mix line endings:

System.IO.FileNotFoundException: ...
\r\nFile name: ...
\r\nRequested by: LibB...
\n --> LibA...
\n --> Root...
\r\n at ...

With ReplaceLineEndings(), the chain’s internal separators match the rest of ToString() output.

So it’s not needed for the assembly-chain logic itself; it’s for consistent, platform-appropriate exception formatting and avoiding mixed line endings in logs, tests, and string consumers. On Unix it likely makes no observable difference, but on Windows it prevents LF-only continuation lines inside an otherwise CRLF-formatted exception string.

User: can we not use proper line endings in the native code?

Assistant: Yes, that would probably be better: have the native code emit the platform-appropriate newline in the diagnostic string, then the managed ToString() overrides can just format _requestingAssemblyChain directly.

Right now the native code hard-codes "\n --> ":

chain.Append(W("\n --> "));

That’s why the managed side normalizes with:

_requestingAssemblyChain.ReplaceLineEndings()

A cleaner alternative would be to use a native helper/constant for the runtime’s platform newline, e.g. conceptually:

#ifdef TARGET_UNIX
#defineCLR_NEWLINEW("\n")
#else
#defineCLR_NEWLINEW("\r\n")
#endif
chain.Append(CLR_NEWLINEW(" --> "));

or whatever existing CoreCLR convention/helper is preferred for platform newlines.

Then the managed side can become:

s+=Environment.NewLineConst+SR.Format(SR.IO_FileLoad_RequestedBy,_requestingAssemblyChain);

That avoids doing normalization every time ToString() is called and keeps the line-ending decision at the point where the multi-line string is constructed.

The main thing to watch for is not to use Environment.NewLine from native code directly, since this path is intentionally low-level exception construction and should avoid extra managed calls/allocations. But a native compile-time/platform constant would be fine.

User: make a pull request that does this

Assistant: I’m waiting for your response to the confirmation dialog so I can continue creating the pull request.

This pull request was created from Copilot chat.

CopilotAI self-assigned this May 8, 2026
CopilotAI review requested due to automatic review settings May 8, 2026 04:25
CopilotAI removed the request for review from CopilotMay 8, 2026 04:25
Copilot stopped work on behalf of MichalStrehovsky due to an error May 8, 2026 04:34
CopilotAI requested a review from MichalStrehovskyMay 8, 2026 04:34
…uction and remove managed ReplaceLineEndings() normalization
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f53f4e08-76fb-4fb1-bfb2-c79be29bf11e
Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotMay 8, 2026 05:04
@github-actionsgithub-actionsBot added the area-ExceptionHandling-coreclr only use for closed issues label May 8, 2026
@github-actionsgithub-actionsBot mentioned this pull request May 8, 2026
@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review May 8, 2026 07:01
CopilotAI review requested due to automatic review settings May 8, 2026 07:01
@MichalStrehovskyMichalStrehovsky changed the title [WIP] Update implementation for requesting assembly chain line endingsEmit platform-native line endings in requesting assembly chainMay 8, 2026
@MichalStrehovsky

Copy link
Copy Markdown
Member

Size statistics

Pull request #127945

ProjectSize beforeSize afterDifference
TodosApi-linux 24491512 24491512 0
TodosApi-windows 25798656 25797632 -1024
avalonia.app-linux 18904048 18904048 0
avalonia.app-windows 19444736 19443200 -1536
hello-linux 1254480 1250384 -4096
hello-minimal-linux 1106904 1106904 0
hello-minimal-windows 790016 779264 -10752
hello-windows 951296 938496 -12800
kestrel-minimal-linux 5273056 5273056 0
kestrel-minimal-windows 4820992 4819968 -1024
reflection-linux 1841160 1841160 0
reflection-windows 1716736 1703424 -13312
webapiaot-linux 9695728 9695728 0
webapiaot-windows 10231808 10230272 -1536
winrt-component-minimal-windows 738304 727040 -11264

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR makes the requesting-assembly chain string use platform-native newlines at the point it’s constructed in CoreCLR native code, allowing the managed ToString() overrides to emit _requestingAssemblyChain as-is (without later line-ending normalization).

Changes:

  • Updated AppDomain::GetParentAssemblyChain to append \r\n on Windows and \n on Unix before each " --> " continuation.
  • Removed _requestingAssemblyChain.ReplaceLineEndings() from ToString() in BadImageFormatException, FileLoadException, and FileNotFoundException.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

FileDescription
src/coreclr/vm/appdomain.cppEmits platform-native newlines when appending " --> " entries to the requesting-assembly chain.
src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.csStops normalizing requesting-chain line endings during ToString().

Comment threadsrc/coreclr/vm/appdomain.cpp
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g filed #127992 on the failure, can't seem to be able to rerun build analysis to pick it up

@MichalStrehovsky
MichalStrehovsky enabled auto-merge (squash) May 9, 2026 12:38
CopilotAI review requested due to automatic review settings May 13, 2026 04:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

@MichalStrehovsky
MichalStrehovsky merged commit 1858a24 into mainMay 15, 2026
152 of 157 checks passed
@MichalStrehovsky
MichalStrehovsky deleted the copilot/update-requesting-assembly-chain branch May 15, 2026 03:26
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

Python problem is dotnet/dnceng#6487.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 14, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@MichalStrehovsky@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Emit platform-native line endings in requesting assembly chain - #127945

Merged
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain
May 15, 2026
Merged

Emit platform-native line endings in requesting assembly chain#127945
MichalStrehovsky merged 5 commits into
mainfrom
copilot/update-requesting-assembly-chain

Conversation

CopilotAI commented May 8, 2026

Copy link
Copy Markdown
Contributor
  • Update native chain construction in appdomain.cpp to use \r\n on Windows, \n on Unix
  • Remove ReplaceLineEndings() calls from BadImageFormatException.ToString(), FileLoadException.ToString(), and FileNotFoundException.ToString()
  • Rebuild CLR + libs successfully
  • Run existing MissingTransitiveDependency_ShowsRequestingAssemblyChain test - passes (39/39)
  • Run exception-specific tests (BadImageFormatException, FileLoadException, FileNotFoundException) - all pass
  • Run code review and CodeQL validation - passed
Original prompt

In dotnet/runtime, update the implementation from PR #125795 so the requesting assembly chain uses proper platform line endings when it is constructed in native code, instead of normalizing the chain later in managed ToString() overrides.

Context:

  • PR Include requesting assembly chain in assembly load failure exceptions #125795 added _requestingAssemblyChain to BadImageFormatException, FileLoadException, and FileNotFoundException.
  • The native chain builder currently appends transitive entries with a hard-coded LF separator, e.g. in src/coreclr/vm/appdomain.cpp:
    chain.Append(W("\n --> "));
  • The managed exception ToString() overrides compensate by calling _requestingAssemblyChain.ReplaceLineEndings() before formatting SR.IO_FileLoad_RequestedBy in:
    • src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.cs
    • src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.cs

Requested change:

  1. Change the native chain construction to append the correct platform newline (\n on Unix, \r\n on Windows) before -->, using an existing CoreCLR convention/helper/constant if one exists, or a small local/native helper/conditional if not.
  2. Remove the ReplaceLineEndings() calls from the three managed ToString() overrides and format _requestingAssemblyChain directly.
  3. Keep behavior equivalent: exception strings should still use platform-appropriate line endings and include the same requesting assembly chain text.
  4. Add or update tests if practical to cover/validate the line-ending behavior without making tests culture-sensitive. Avoid asserting localized text unless the test explicitly controls UI culture.

Please create a pull request with the fix.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: why do we need to call ReplaceLineEndings in the ToString overrides?

Assistant: We call ReplaceLineEndings() to normalize the embedded newlines inside _requestingAssemblyChain to the current platform’s newline convention before Exception.ToString() emits them.

The requesting chain is built in native code with hard-coded \n separators:

  • first assembly: LibB, Version=...
  • subsequent assemblies appended like: \n --> LibA, Version=...

But the managed ToString() implementations build the rest of the exception text using Environment.NewLineConst. On Windows that is \r\n, while the native chain would otherwise contain lone \n. So without:

_requestingAssemblyChain.ReplaceLineEndings()

the final exception string would mix line endings:

System.IO.FileNotFoundException: ...
\r\nFile name: ...
\r\nRequested by: LibB...
\n --> LibA...
\n --> Root...
\r\n at ...

With ReplaceLineEndings(), the chain’s internal separators match the rest of ToString() output.

So it’s not needed for the assembly-chain logic itself; it’s for consistent, platform-appropriate exception formatting and avoiding mixed line endings in logs, tests, and string consumers. On Unix it likely makes no observable difference, but on Windows it prevents LF-only continuation lines inside an otherwise CRLF-formatted exception string.

User: can we not use proper line endings in the native code?

Assistant: Yes, that would probably be better: have the native code emit the platform-appropriate newline in the diagnostic string, then the managed ToString() overrides can just format _requestingAssemblyChain directly.

Right now the native code hard-codes "\n --> ":

chain.Append(W("\n --> "));

That’s why the managed side normalizes with:

_requestingAssemblyChain.ReplaceLineEndings()

A cleaner alternative would be to use a native helper/constant for the runtime’s platform newline, e.g. conceptually:

#ifdef TARGET_UNIX
#defineCLR_NEWLINEW("\n")
#else
#defineCLR_NEWLINEW("\r\n")
#endif
chain.Append(CLR_NEWLINEW(" --> "));

or whatever existing CoreCLR convention/helper is preferred for platform newlines.

Then the managed side can become:

s+=Environment.NewLineConst+SR.Format(SR.IO_FileLoad_RequestedBy,_requestingAssemblyChain);

That avoids doing normalization every time ToString() is called and keeps the line-ending decision at the point where the multi-line string is constructed.

The main thing to watch for is not to use Environment.NewLine from native code directly, since this path is intentionally low-level exception construction and should avoid extra managed calls/allocations. But a native compile-time/platform constant would be fine.

User: make a pull request that does this

Assistant: I’m waiting for your response to the confirmation dialog so I can continue creating the pull request.

This pull request was created from Copilot chat.

CopilotAI self-assigned this May 8, 2026
CopilotAI review requested due to automatic review settings May 8, 2026 04:25
CopilotAI removed the request for review from CopilotMay 8, 2026 04:25
Copilot stopped work on behalf of MichalStrehovsky due to an error May 8, 2026 04:34
CopilotAI requested a review from MichalStrehovskyMay 8, 2026 04:34
…uction and remove managed ReplaceLineEndings() normalization
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f53f4e08-76fb-4fb1-bfb2-c79be29bf11e
Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotMay 8, 2026 05:04
@github-actionsgithub-actionsBot added the area-ExceptionHandling-coreclr only use for closed issues label May 8, 2026
@github-actionsgithub-actionsBot mentioned this pull request May 8, 2026
@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review May 8, 2026 07:01
CopilotAI review requested due to automatic review settings May 8, 2026 07:01
@MichalStrehovskyMichalStrehovsky changed the title [WIP] Update implementation for requesting assembly chain line endingsEmit platform-native line endings in requesting assembly chainMay 8, 2026
@MichalStrehovsky

Copy link
Copy Markdown
Member

Size statistics

Pull request #127945

ProjectSize beforeSize afterDifference
TodosApi-linux 24491512 24491512 0
TodosApi-windows 25798656 25797632 -1024
avalonia.app-linux 18904048 18904048 0
avalonia.app-windows 19444736 19443200 -1536
hello-linux 1254480 1250384 -4096
hello-minimal-linux 1106904 1106904 0
hello-minimal-windows 790016 779264 -10752
hello-windows 951296 938496 -12800
kestrel-minimal-linux 5273056 5273056 0
kestrel-minimal-windows 4820992 4819968 -1024
reflection-linux 1841160 1841160 0
reflection-windows 1716736 1703424 -13312
webapiaot-linux 9695728 9695728 0
webapiaot-windows 10231808 10230272 -1536
winrt-component-minimal-windows 738304 727040 -11264

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR makes the requesting-assembly chain string use platform-native newlines at the point it’s constructed in CoreCLR native code, allowing the managed ToString() overrides to emit _requestingAssemblyChain as-is (without later line-ending normalization).

Changes:

  • Updated AppDomain::GetParentAssemblyChain to append \r\n on Windows and \n on Unix before each " --> " continuation.
  • Removed _requestingAssemblyChain.ReplaceLineEndings() from ToString() in BadImageFormatException, FileLoadException, and FileNotFoundException.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

FileDescription
src/coreclr/vm/appdomain.cppEmits platform-native newlines when appending " --> " entries to the requesting-assembly chain.
src/libraries/System.Private.CoreLib/src/System/BadImageFormatException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileLoadException.csStops normalizing requesting-chain line endings during ToString().
src/libraries/System.Private.CoreLib/src/System/IO/FileNotFoundException.csStops normalizing requesting-chain line endings during ToString().

Comment threadsrc/coreclr/vm/appdomain.cpp
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g filed #127992 on the failure, can't seem to be able to rerun build analysis to pick it up

@MichalStrehovsky
MichalStrehovsky enabled auto-merge (squash) May 9, 2026 12:38
CopilotAI review requested due to automatic review settings May 13, 2026 04:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

@MichalStrehovsky
MichalStrehovsky merged commit 1858a24 into mainMay 15, 2026
152 of 157 checks passed
@MichalStrehovsky
MichalStrehovsky deleted the copilot/update-requesting-assembly-chain branch May 15, 2026 03:26
@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g python problem on osx. the test succeeded.

Python problem is dotnet/dnceng#6487.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 14, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@MichalStrehovsky@elinor-fung