Skip to content

Commit

Permalink
[cdac] Fix getting free object size in GetObjectData (#106505)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
elinor-fung authored Aug 16, 2024
1 parent 8ea4779 commit c5c5551
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2632,6 +2632,7 @@ DWORD DACGetNumComponents(TADDR addr, ICorDebugDataTarget* target)
// This expects that the first member after the MethodTable pointer (from Object)
// is a 32-bit integer representing the number of components.
// This holds for ArrayBase and StringObject - see coreclr/vm/object.h
// Free objects also have a component count set at this offset- see SetFree in coreclr/gc/gc.cpp
addr += sizeof(size_t); // Method table pointer
ULONG32 returned = 0;
DWORD Value = 0;
Expand Down
5 changes: 4 additions & 1 deletion src/native/managed/cdacreader/src/Contracts/Object_1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ string IObject.GetStringValue(TargetPointer address)
throw new ArgumentException("Address does not represent a string object", nameof(address));

Data.String str = _target.ProcessedData.GetOrAdd<Data.String>(address);
if (str.StringLength == 0)
return string.Empty;

Span<byte> span = stackalloc byte[(int)str.StringLength * sizeof(char)];
_target.ReadBuffer(str.FirstChar, span);
return new string(MemoryMarshal.Cast<byte, char>(span));
Expand Down Expand Up @@ -85,7 +88,7 @@ public TargetPointer GetArrayData(TargetPointer address, out uint count, out Tar
else
{
// Single-dimensional, zero-based - doesn't have bounds
boundsStart = address + (ulong)arrayTypeInfo.Fields["m_NumComponents"].Offset;
boundsStart = address + (ulong)arrayTypeInfo.Fields[Data.Array.FieldNames.NumComponents].Offset;
lowerBounds = _target.ReadGlobalPointer(Constants.Globals.ArrayBoundsZero);
}

Expand Down
7 changes: 6 additions & 1 deletion src/native/managed/cdacreader/src/Data/Array.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ public Array(Target target, TargetPointer address)
{
Target.TypeInfo type = target.GetTypeInfo(DataType.Array);

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

public uint NumComponents { get; init; }

internal static class FieldNames
{
internal const string NumComponents = $"m_{nameof(NumComponents)}";
}
}
6 changes: 6 additions & 0 deletions src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,12 @@ public unsafe int GetObjectData(ulong objAddr, DacpObjectData* data)
if (runtimeTypeSystemContract.IsFreeObjectMethodTable(handle))
{
data->ObjectType = DacpObjectType.OBJ_FREE;

// Free objects have their component count explicitly set at the same offset as that for arrays
// Update the size to include those components
Target.TypeInfo arrayTypeInfo = _target.GetTypeInfo(DataType.Array);
ulong numComponentsOffset = (ulong)_target.GetTypeInfo(DataType.Array).Fields[Data.Array.FieldNames.NumComponents].Offset;
data->Size += _target.Read<uint>(objAddr + numComponentsOffset) * data->dwComponentSize;
}
else if (mt == _stringMethodTable)
{
Expand Down

0 comments on commit c5c5551

Please # to comment.