Skip to content

Fix handling VAR data type #3169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 9, 2025
Merged
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
20 changes: 18 additions & 2 deletions src/CLR/Core/Execution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1971,10 +1971,26 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals(

case DATATYPE_VAR:
{
// type-level generic parameter in a locals signature (e.g. 'T' inside a generic type)
CLR_INT8 genericParamPosition = *sig++;

methodDefInstance.assembly
->FindGenericParamAtTypeSpec(methodDefInstance, genericParamPosition, cls, dt);
// parse the locals-signature to extract that T
CLR_RT_SignatureParser parser;
parser.Initialize_MethodLocals(assembly, methodDef);
CLR_RT_SignatureParser::Element element;

// advance into the VAR entry
parser.Advance(element);

// walk forward to the Nth generic-parameter
for (int i = 0; i < genericParamPosition; i++)
{
parser.Advance(element);
}

// element.Class and element.DataType represent the T
cls = element.Class;
dt = element.DataType;

goto done;
}
Expand Down
59 changes: 25 additions & 34 deletions src/CLR/Core/TypeSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,6 @@ HRESULT CLR_RT_SignatureParser::Advance(Element &res)

NANOCLR_HEADER();

_ASSERTE(ParamCount > 0);

ParamCount--;

res.IsByRef = false;
Expand Down Expand Up @@ -988,13 +986,36 @@ bool CLR_RT_TypeDef_Instance::ResolveToken(
case DATATYPE_VAR:
{
CLR_RT_TypeDef_Index typeDef;
NanoCLRDataType dataType;
CLR_RT_SignatureParser::Element genericElement;

CLR_RT_SignatureParser varParser;
varParser.Initialize_TypeSpec(assm, ts);

caller->assembly->FindGenericParamAtTypeSpec(*caller, genericParamPosition, typeDef, dataType);
// advance once to consume the GENERICINST or VAR entry
varParser.Advance(genericElement);

// now walk forward genericParameterPosition steps to land on the actual
// argument in the signature stream.
for (CLR_INT8 i = 0; i <= genericParamPosition; i++)
{
if (FAILED(varParser.Advance(genericElement)))
{
return false;
}
}

// genericElement.Class now holds the TypeDef_Index of the T or U, etc.
typeDef = genericElement.Class;

// populate this instance from the resolved TypeDef
data = typeDef.data;
assembly = g_CLR_RT_TypeSystem.m_assemblies[typeDef.Assembly() - 1];
target = assembly->GetTypeDef(typeDef.Type());

#if defined(NANOCLR_INSTANCE_NAMES)
name = assembly->GetString(target->name);
#endif
return true;
}
break;

Expand Down Expand Up @@ -4455,36 +4476,6 @@ bool CLR_RT_Assembly::FindGenericParam(CLR_INDEX typeSpecIndex, CLR_RT_GenericPa
return false;
}

bool CLR_RT_Assembly::FindGenericParamAtTypeSpec(
CLR_RT_MethodDef_Instance md,
CLR_UINT32 genericParameterPosition,
CLR_RT_TypeDef_Index &index,
NanoCLRDataType &dataType)
{
NATIVE_PROFILE_CLR_CORE();

CLR_RT_SignatureParser parser;
parser.Initialize_TypeSpec(md.assembly, md.assembly->GetTypeSpec(md.genericType->TypeSpec()));

CLR_RT_SignatureParser::Element element;

// get type
parser.Advance(element);

for (uint32_t i = 0; i <= genericParameterPosition; i++)
{
if (FAILED(parser.Advance(element)))
{
return false;
}
}

index = element.Class;
dataType = element.DataType;

return true;
}

bool CLR_RT_Assembly::FindGenericParamAtMethodDef(
CLR_RT_MethodDef_Instance md,
CLR_UINT32 genericParameterPosition,
Expand Down
49 changes: 45 additions & 4 deletions src/CLR/Debugger/Debugger.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//
//
// Copyright (c) .NET Foundation and Contributors
// Portions Copyright (c) Microsoft Corporation. All rights reserved.
// See LICENSE file in the project root for full license information.
Expand Down Expand Up @@ -2821,10 +2821,51 @@ bool CLR_DBG_Debugger::Debugging_Value_GetStack(WP_Message *msg)
// handle generic parameters
if (res.DataType == DATATYPE_VAR)
{
// Generic parameter in a generic TypeDef
md.assembly->FindGenericParamAtTypeSpec(md, res.GenericParamPosition, targetClass, targetDataType);
// type‐level generic parameter in a generic TypeDef: re‐parse the signature
CLR_RT_SignatureParser typeParser;

// isGenericInstance = true;
// for arguments, initialize over the method signature and skip the return slot
if (cmd->m_kind == CLR_DBG_Commands::Debugging_Value_GetStack::c_Argument)
{
typeParser.Initialize_MethodSignature(&md);

// skip the return value entry
iElement++;

// if there's an implicit 'this', adjust index
if (typeParser.Flags & PIMAGE_CEE_CS_CALLCONV_HASTHIS)
{
if (iElement == 0)
{
// requested the 'this' argument – invalid for a primitive
return false;
}
iElement--;
}
}
else
{
// for locals or eval‐stack, initialize over the locals signature
typeParser.Initialize_MethodLocals(md.assembly, md.target);
}

// advance to the requested argument/local
CLR_RT_SignatureParser::Element elem;
do
{
typeParser.Advance(elem);
} while (iElement-- > 0);

// now we've landed on a DATATYPE_VAR; walk to the Nth generic‐type parameter
typeParser.Advance(elem);
for (int i = 0; i < res.GenericParamPosition; i++)
{
parser.Advance(elem);
}

// this element.Class is the TypeDef_Index for 'T'
targetClass = elem.Class;
targetDataType = elem.DataType;
}
Comment on lines +2866 to 2869
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

targetClass / targetDataType may remain uninitialised

When any of the above Advance operations fail the two out-parameters are left untouched yet later used to patch tmp.
Ensure they are initialised (e.g. to CLR_RT_TypeDef_Index::Invalid() / DATATYPE_VOID) right before the parsing starts, and only used when the parsing was successful.

else if (res.DataType == DATATYPE_MVAR)
{
Expand Down
5 changes: 0 additions & 5 deletions src/CLR/Include/nanoCLR_Runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -1423,11 +1423,6 @@ struct CLR_RT_Assembly : public CLR_RT_HeapBlock_Node // EVENT HEAP - NO RELOCAT

bool FindTypeSpec(const CLR_PMETADATA sig, CLR_RT_TypeSpec_Index &index);

bool FindGenericParamAtTypeSpec(
CLR_RT_MethodDef_Instance md,
CLR_UINT32 genericParameterPosition,
CLR_RT_TypeDef_Index &index,
NanoCLRDataType &dataType);
bool FindGenericParamAtMethodDef(
CLR_RT_MethodDef_Instance md,
CLR_UINT32 genericParameterPosition,
Expand Down