Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions eng/pipelines/runtime-diagnostics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ extends:
artifactName: 'TestResults_cDAC_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig)_Attempt$(System.JobAttempt)'
displayName: 'Publish Test Results and SOS Logs'
continueOnError: true
condition: failed()
condition: always()
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

Using condition: always() will also run this artifact publish step on canceled jobs, which often produces noisy "path not found" failures (even with continueOnError) and extra pipeline work. If the goal is to publish on both pass and fail runs, condition: succeededOrFailed() is typically a better fit (or an always() condition additionally excluding Agent.JobStatus == 'Canceled').

Suggested change
condition: always()
condition: succeededOrFailed()

Copilot uses AI. Check for mistakes.
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
jobTemplate: /eng/pipelines/diagnostics/runtime-diag-job.yml
Expand Down Expand Up @@ -197,7 +197,7 @@ extends:
artifactName: 'TestResults_cDAC_no_fallback_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig)_Attempt$(System.JobAttempt)'
displayName: 'Publish Test Results and SOS Logs'
continueOnError: true
condition: failed()
condition: always()
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

Same as earlier: consider using succeededOrFailed() (or exclude canceled) instead of always() so this publish step doesn’t run on canceled jobs and create noisy failures.

Suggested change
condition: always()
condition: succeededOrFailed()

Copilot uses AI. Check for mistakes.
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
jobTemplate: /eng/pipelines/diagnostics/runtime-diag-job.yml
Expand Down Expand Up @@ -250,7 +250,7 @@ extends:
artifactName: 'TestResults_DAC_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig)_Attempt$(System.JobAttempt)'
displayName: 'Publish Test Results and SOS Logs'
continueOnError: true
condition: failed()
condition: always()
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

Same as earlier: consider using succeededOrFailed() (or exclude canceled) instead of always() so this publish step doesn’t run on canceled jobs and create noisy failures.

Suggested change
condition: always()
condition: succeededOrFailed()

Copilot uses AI. Check for mistakes.

#
# cDAC Dump Tests — Build, generate dumps, and run tests on Helix (single-leg mode)
Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1939,7 +1939,11 @@ ClrDataAccess::GetMethodTableName(CLRDATA_ADDRESS mt, unsigned int count, _Inout

if (s.IsEmpty())
{
hr = E_OUTOFMEMORY;
if (pNeeded)
*pNeeded = 1;

if (mtName && count)
mtName[0] = 0;
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
Expand Down Expand Up @@ -52,5 +53,35 @@ internal static void ValidateHResult(
};
Debug.Assert(match, $"HResult mismatch - cDAC: 0x{unchecked((uint)cdacHr):X8}, DAC: 0x{unchecked((uint)dacHr):X8} ({Path.GetFileName(filePath)}:{lineNumber})");
}

[Conditional("DEBUG")]
internal static unsafe void ValidateOutputStringBuffer(
char* cdacBuffer,
uint* cdacNeeded,
char[] dacBuffer,
uint dacNeeded,
uint count,
[CallerFilePath] string? filePath = null,
[CallerLineNumber] int lineNumber = 0)
{
string location = $"{Path.GetFileName(filePath)}:{lineNumber}";

if (cdacNeeded is not null && *cdacNeeded != dacNeeded)
{
int cdacLen = (int)Math.Min(*cdacNeeded, count);
string cdacStr = cdacBuffer is not null && cdacLen > 0 ? new string(cdacBuffer, 0, cdacLen - 1) : "<null>";
string dacStr = dacNeeded > 0 ? new string(dacBuffer, 0, (int)dacNeeded - 1) : "<empty>";
Trace.TraceWarning($"Output buffer pNeeded mismatch ({location}) - cDAC: {*cdacNeeded} (\"{cdacStr}\"), DAC: {dacNeeded} (\"{dacStr}\")");
}
else if (cdacBuffer is not null && dacNeeded > 0 && count >= dacNeeded)
{
var cdacSpan = new ReadOnlySpan<char>(cdacBuffer, (int)dacNeeded - 1);
var dacSpan = new ReadOnlySpan<char>(dacBuffer, 0, (int)dacNeeded - 1);
if (!cdacSpan.SequenceEqual(dacSpan))
{
Trace.TraceWarning($"Output buffer content mismatch ({location}) - cDAC: \"{new string(cdacBuffer, 0, (int)dacNeeded - 1)}\", DAC: \"{new string(dacBuffer, 0, (int)dacNeeded - 1)}\"");
Comment on lines +72 to +82
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

ValidateOutputStringBuffer can throw when formatting dacStr/content: dacNeeded may be larger than dacBuffer.Length (e.g., when the legacy DAC reports required size > count). In the pNeeded-mismatch branch and the content-mismatch warning, clamp the length to the available buffer (e.g., min(dacNeeded, (uint)dacBuffer.Length, count)) before calling new string(...) or constructing spans.

Suggested change
string cdacStr = cdacBuffer is not null && cdacLen > 0 ? new string(cdacBuffer, 0, cdacLen - 1) : "<null>";
string dacStr = dacNeeded > 0 ? new string(dacBuffer, 0, (int)dacNeeded - 1) : "<empty>";
Trace.TraceWarning($"Output buffer pNeeded mismatch ({location}) - cDAC: {*cdacNeeded} (\"{cdacStr}\"), DAC: {dacNeeded} (\"{dacStr}\")");
}
else if (cdacBuffer is not null && dacNeeded > 0 && count >= dacNeeded)
{
var cdacSpan = new ReadOnlySpan<char>(cdacBuffer, (int)dacNeeded - 1);
var dacSpan = new ReadOnlySpan<char>(dacBuffer, 0, (int)dacNeeded - 1);
if (!cdacSpan.SequenceEqual(dacSpan))
{
Trace.TraceWarning($"Output buffer content mismatch ({location}) - cDAC: \"{new string(cdacBuffer, 0, (int)dacNeeded - 1)}\", DAC: \"{new string(dacBuffer, 0, (int)dacNeeded - 1)}\"");
int dacLen = (int)Math.Min(dacNeeded, Math.Min((uint)dacBuffer.Length, count));
string cdacStr = cdacBuffer is not null && cdacLen > 0 ? new string(cdacBuffer, 0, cdacLen - 1) : "<null>";
string dacStr = dacLen > 0 ? new string(dacBuffer, 0, dacLen - 1) : "<empty>";
Trace.TraceWarning($"Output buffer pNeeded mismatch ({location}) - cDAC: {*cdacNeeded} (\"{cdacStr}\"), DAC: {dacNeeded} (\"{dacStr}\")");
}
else if (cdacBuffer is not null && dacNeeded > 0 && count >= dacNeeded)
{
int compareLen = (int)Math.Min(dacNeeded, Math.Min((uint)dacBuffer.Length, count));
if (compareLen > 0)
{
var cdacSpan = new ReadOnlySpan<char>(cdacBuffer, compareLen - 1);
var dacSpan = new ReadOnlySpan<char>(dacBuffer, 0, compareLen - 1);
if (!cdacSpan.SequenceEqual(dacSpan))
{
Trace.TraceWarning($"Output buffer content mismatch ({location}) - cDAC: \"{new string(cdacBuffer, 0, compareLen - 1)}\", DAC: \"{new string(dacBuffer, 0, compareLen - 1)}\"");
}

Copilot uses AI. Check for mistakes.
}
}
}
}
}
Loading