Skip to content

Commit 6f603d6

Browse files
Max CharlambCopilot
andcommitted
Fix GetMethodTableName to return E_OUTOFMEMORY for empty type names
When TypeNameBuilder.AppendType produces an empty string (and the fallback also fails), the cDAC was calling CopyStringToBuffer with an empty string, setting pNeeded=1 and returning S_OK. The legacy DAC returns E_OUTOFMEMORY in this case and does not set pNeeded. This mismatch caused the #if DEBUG validation assertion to crash the SOS.WebApp3 test in all runtime-diagnostics PR builds. Fix: check for empty methodTableName and return E_OUTOFMEMORY to match the legacy DAC behavior. Also add stderr logging so the MT address is captured when this path is hit. Also changes the runtime-diagnostics pipeline to always publish test results and SOS logs (not just on failure), so diagnostic output is accessible for passing runs too. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent d754bd0 commit 6f603d6

3 files changed

Lines changed: 45 additions & 4 deletions

File tree

eng/pipelines/runtime-diagnostics.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ extends:
143143
artifactName: 'TestResults_cDAC_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig)_Attempt$(System.JobAttempt)'
144144
displayName: 'Publish Test Results and SOS Logs'
145145
continueOnError: true
146-
condition: failed()
146+
condition: always()
147147
- template: /eng/pipelines/common/platform-matrix.yml
148148
parameters:
149149
jobTemplate: /eng/pipelines/diagnostics/runtime-diag-job.yml
@@ -197,7 +197,7 @@ extends:
197197
artifactName: 'TestResults_cDAC_no_fallback_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig)_Attempt$(System.JobAttempt)'
198198
displayName: 'Publish Test Results and SOS Logs'
199199
continueOnError: true
200-
condition: failed()
200+
condition: always()
201201
- template: /eng/pipelines/common/platform-matrix.yml
202202
parameters:
203203
jobTemplate: /eng/pipelines/diagnostics/runtime-diag-job.yml
@@ -250,7 +250,7 @@ extends:
250250
artifactName: 'TestResults_DAC_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig)_Attempt$(System.JobAttempt)'
251251
displayName: 'Publish Test Results and SOS Logs'
252252
continueOnError: true
253-
condition: failed()
253+
condition: always()
254254

255255
#
256256
# cDAC Dump Tests — Build, generate dumps, and run tests on Helix (single-leg mode)

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/DebugExtensions.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
45
using System.Diagnostics;
56
using System.IO;
67
using System.Runtime.CompilerServices;
@@ -52,5 +53,35 @@ internal static void ValidateHResult(
5253
};
5354
Debug.Assert(match, $"HResult mismatch - cDAC: 0x{unchecked((uint)cdacHr):X8}, DAC: 0x{unchecked((uint)dacHr):X8} ({Path.GetFileName(filePath)}:{lineNumber})");
5455
}
56+
57+
[Conditional("DEBUG")]
58+
internal static unsafe void ValidateOutputStringBuffer(
59+
char* cdacBuffer,
60+
uint* cdacNeeded,
61+
char[] dacBuffer,
62+
uint dacNeeded,
63+
uint count,
64+
[CallerFilePath] string? filePath = null,
65+
[CallerLineNumber] int lineNumber = 0)
66+
{
67+
string location = $"{Path.GetFileName(filePath)}:{lineNumber}";
68+
69+
if (cdacNeeded is not null && *cdacNeeded != dacNeeded)
70+
{
71+
int cdacLen = (int)Math.Min(*cdacNeeded, count);
72+
string cdacStr = cdacBuffer is not null && cdacLen > 0 ? new string(cdacBuffer, 0, cdacLen - 1) : "<null>";
73+
string dacStr = dacNeeded > 0 ? new string(dacBuffer, 0, (int)dacNeeded - 1) : "<empty>";
74+
Trace.TraceWarning($"Output buffer pNeeded mismatch ({location}) - cDAC: {*cdacNeeded} (\"{cdacStr}\"), DAC: {dacNeeded} (\"{dacStr}\")");
75+
}
76+
else if (cdacBuffer is not null && dacNeeded > 0 && count >= dacNeeded)
77+
{
78+
var cdacSpan = new ReadOnlySpan<char>(cdacBuffer, (int)dacNeeded - 1);
79+
var dacSpan = new ReadOnlySpan<char>(dacBuffer, 0, (int)dacNeeded - 1);
80+
if (!cdacSpan.SequenceEqual(dacSpan))
81+
{
82+
Trace.TraceWarning($"Output buffer content mismatch ({location}) - cDAC: \"{new string(cdacBuffer, 0, (int)dacNeeded - 1)}\", DAC: \"{new string(dacBuffer, 0, (int)dacNeeded - 1)}\"");
83+
}
84+
}
85+
}
5586
}
5687
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2972,7 +2972,17 @@ int ISOSDacInterface.GetMethodTableName(ClrDataAddress mt, uint count, char* mtN
29722972
methodTableName.Append(fallbackName);
29732973
}
29742974
}
2975-
OutputBufferHelpers.CopyStringToBuffer(mtName, count, pNeeded, methodTableName.ToString());
2975+
2976+
if (methodTableName.Length == 0)
2977+
{
2978+
System.Console.Error.WriteLine($"CDAC_EMPTY_NAME GetMethodTableName MT=0x{(ulong)mt:X} count={count} — TypeNameBuilder produced empty string, returning E_OUTOFMEMORY");
2979+
System.Console.Error.Flush();
2980+
hr = HResults.E_OUTOFMEMORY;
2981+
}
2982+
else
2983+
{
2984+
OutputBufferHelpers.CopyStringToBuffer(mtName, count, pNeeded, methodTableName.ToString());
2985+
}
29762986
}
29772987
}
29782988

0 commit comments

Comments
 (0)