Skip to content

Commit c5c5551

Browse files
authored
[cdac] Fix getting free object size in GetObjectData (#106505)
Missed that free objects also have their component count set - explicitly at the array base offset for num components. This updates the cDAC implementation of `ISOSDacInterface::GetObjectData` to correctly handle free objects with a non-zero component count.
1 parent 8ea4779 commit c5c5551

File tree

4 files changed

+17
-2
lines changed

4 files changed

+17
-2
lines changed

src/coreclr/debug/daccess/request.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -2632,6 +2632,7 @@ DWORD DACGetNumComponents(TADDR addr, ICorDebugDataTarget* target)
26322632
// This expects that the first member after the MethodTable pointer (from Object)
26332633
// is a 32-bit integer representing the number of components.
26342634
// This holds for ArrayBase and StringObject - see coreclr/vm/object.h
2635+
// Free objects also have a component count set at this offset- see SetFree in coreclr/gc/gc.cpp
26352636
addr += sizeof(size_t); // Method table pointer
26362637
ULONG32 returned = 0;
26372638
DWORD Value = 0;

src/native/managed/cdacreader/src/Contracts/Object_1.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ string IObject.GetStringValue(TargetPointer address)
5252
throw new ArgumentException("Address does not represent a string object", nameof(address));
5353

5454
Data.String str = _target.ProcessedData.GetOrAdd<Data.String>(address);
55+
if (str.StringLength == 0)
56+
return string.Empty;
57+
5558
Span<byte> span = stackalloc byte[(int)str.StringLength * sizeof(char)];
5659
_target.ReadBuffer(str.FirstChar, span);
5760
return new string(MemoryMarshal.Cast<byte, char>(span));
@@ -85,7 +88,7 @@ public TargetPointer GetArrayData(TargetPointer address, out uint count, out Tar
8588
else
8689
{
8790
// Single-dimensional, zero-based - doesn't have bounds
88-
boundsStart = address + (ulong)arrayTypeInfo.Fields["m_NumComponents"].Offset;
91+
boundsStart = address + (ulong)arrayTypeInfo.Fields[Data.Array.FieldNames.NumComponents].Offset;
8992
lowerBounds = _target.ReadGlobalPointer(Constants.Globals.ArrayBoundsZero);
9093
}
9194

src/native/managed/cdacreader/src/Data/Array.cs

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@ public Array(Target target, TargetPointer address)
1212
{
1313
Target.TypeInfo type = target.GetTypeInfo(DataType.Array);
1414

15-
NumComponents = target.Read<uint>(address + (ulong)type.Fields["m_NumComponents"].Offset);
15+
NumComponents = target.Read<uint>(address + (ulong)type.Fields[FieldNames.NumComponents].Offset);
1616
}
1717

1818
public uint NumComponents { get; init; }
19+
20+
internal static class FieldNames
21+
{
22+
internal const string NumComponents = $"m_{nameof(NumComponents)}";
23+
}
1924
}

src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs

+6
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,12 @@ public unsafe int GetObjectData(ulong objAddr, DacpObjectData* data)
408408
if (runtimeTypeSystemContract.IsFreeObjectMethodTable(handle))
409409
{
410410
data->ObjectType = DacpObjectType.OBJ_FREE;
411+
412+
// Free objects have their component count explicitly set at the same offset as that for arrays
413+
// Update the size to include those components
414+
Target.TypeInfo arrayTypeInfo = _target.GetTypeInfo(DataType.Array);
415+
ulong numComponentsOffset = (ulong)_target.GetTypeInfo(DataType.Array).Fields[Data.Array.FieldNames.NumComponents].Offset;
416+
data->Size += _target.Read<uint>(objAddr + numComponentsOffset) * data->dwComponentSize;
411417
}
412418
else if (mt == _stringMethodTable)
413419
{

0 commit comments

Comments
 (0)