Skip to content
Open
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
1 change: 1 addition & 0 deletions src/coreclr/nativeaot/Runtime/AsmOffsets.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ ASM_CONST( 6, 6, ARM64_ATOMICS_FEATURE_FLAG_BIT)
ASM_OFFSET( 0, 0, MethodTable, m_usComponentSize)
ASM_OFFSET( 0, 0, MethodTable, m_uFlags)
ASM_OFFSET( 4, 4, MethodTable, m_uBaseSize)
ASM_OFFSET( C, 10, MethodTable, m_usNumVtableSlots)
ASM_OFFSET( 14, 18, MethodTable, m_VTable)

ASM_OFFSET( 0, 0, Thread, m_eeAllocContext)
Expand Down
57 changes: 55 additions & 2 deletions src/coreclr/nativeaot/Runtime/MethodTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ bool MethodTable::Validate(bool assertOnFail /* default: true */)
{
case CanonicalEEType:
{
MethodTable* pBaseType = GetNonArrayBaseType();

// If the parent type is NULL this had better look like Object.
if (!IsInterface() && (m_RelatedType.m_pBaseType == NULL))
if (pBaseType == NULL)
{
if (IsValueType() ||
HasFinalizer() ||
Expand All @@ -51,6 +53,24 @@ bool MethodTable::Validate(bool assertOnFail /* default: true */)
REPORT_FAILURE();
}
}
else if (GetNumVtableSlots() == 0
&& !IsGCStaticMethodTable())
{
// We only really expect zero vtable slots for GCStatic MethodTables, however
// to cover the unlikely case that we managed to trim out Equals/GetHashCode/ToString,
// check an invariant that says if a derived type has zero vtable slots, all bases need
// to have zero slots.
MethodTable* pCurrentType = pBaseType;
do
{
if (pCurrentType->GetNumVtableSlots() > GetNumVtableSlots())
{
REPORT_FAILURE();
}
pCurrentType = pCurrentType->GetNonArrayBaseType();
}
while (pCurrentType != NULL);
}
break;
}

Expand All @@ -59,7 +79,8 @@ bool MethodTable::Validate(bool assertOnFail /* default: true */)
// The only parameter EETypes that can exist on the heap are arrays

// Array types must have a related type.
if (m_RelatedType.m_pRelatedParameterType == NULL)
MethodTable* pParameterType = GetRelatedParameterType();
if (pParameterType == NULL)
REPORT_FAILURE();

// Component size cannot be zero in this case.
Expand All @@ -73,6 +94,38 @@ bool MethodTable::Validate(bool assertOnFail /* default: true */)
REPORT_FAILURE();
}

// Zero vtable slots is suspicious. To cover the unlikely case that we managed to trim
// out Equals/GetHashCode/ToString, compare with number of slots of Object class.
if (GetNumVtableSlots() == 0)
{
// Drill into the type to find System.Object

MethodTable* pCurrentType = pParameterType;

while (pCurrentType->IsParameterizedType())
pCurrentType = pCurrentType->GetRelatedParameterType();

// We don't have facilities to unwrap function pointers, so just skip for now.
// We won't get System.Object from interfaces, skip too.
if (!pCurrentType->IsFunctionPointer() && !pCurrentType->IsInterface())
{
do
{
MethodTable* pBaseType = pCurrentType->GetNonArrayBaseType();
if (pBaseType == NULL)
{
// Found System.Object, now compare number of slots
if (pCurrentType->GetNumVtableSlots() > GetNumVtableSlots())
{
REPORT_FAILURE();
}
}

pCurrentType = pBaseType;
} while (pCurrentType != NULL);
}
}

break;
}

Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/nativeaot/Runtime/eventtrace_bulktype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,9 @@ int BulkTypeEventLogger::LogSingleType(MethodTable * pEEType)
// Determine this MethodTable's module.
RuntimeInstance * pRuntimeInstance = GetRuntimeInstance();

// EEType for GC statics are not fully populated and they do not have a valid TypeManager. We will identify them by checking for `ElementType_Unknown`.
// EEType for GC statics are not fully populated and they do not have a valid TypeManager.
ULONGLONG osModuleHandle = 0;
if (pEEType->GetElementType() != ElementType_Unknown)
if (!pEEType->IsGCStaticMethodTable())
{
osModuleHandle = (ULONGLONG) pEEType->GetTypeManagerPtr()->AsTypeManager()->GetOsModuleHandle();
}
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/nativeaot/Runtime/inc/MethodTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,11 @@ class MethodTable

Kinds GetKind();

bool IsGCStaticMethodTable()
{
return GetElementType() == ElementType_Unknown;
}

bool IsArray()
{
EETypeElementType elementType = GetElementType();
Expand Down
55 changes: 55 additions & 0 deletions src/coreclr/runtime/amd64/AllocFast.S
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ LEAF_ENTRY RhpNewFast, _TEXT
push_nonvol_reg rbx
mov rbx, rdi

#ifdef FEATURE_NATIVEAOT
mov ax, [rdi + OFFSETOF__MethodTable__m_usNumVtableSlots]
test ax, ax
jnz LOCAL_LABEL(RhpNewFast_ValidMethodTable)
mov eax, [rdi]
and eax, 0x7C000000
jz LOCAL_LABEL(RhpNewFast_ValidMethodTable)
int 3
LOCAL_LABEL(RhpNewFast_ValidMethodTable):
#endif


// rax = ee_alloc_context pointer; trashes volatile registers
INLINE_GET_ALLOC_CONTEXT_BASE

Expand Down Expand Up @@ -81,6 +93,17 @@ NESTED_ENTRY RhpNewObject, _TEXT, NoHandler

// RCX: transition frame

#ifdef FEATURE_NATIVEAOT
mov ax, [rdi + OFFSETOF__MethodTable__m_usNumVtableSlots]
test ax, ax
jnz LOCAL_LABEL(RhpNewObject_ValidMethodTable)
mov eax, [rdi]
and eax, 0x7C000000
jz LOCAL_LABEL(RhpNewObject_ValidMethodTable)
int 3
LOCAL_LABEL(RhpNewObject_ValidMethodTable):
#endif

// Preserve the MethodTable in RBX
mov rbx, rdi

Expand Down Expand Up @@ -176,6 +199,14 @@ NESTED_END RhpNewObject, _TEXT
// RSI == character/element count
LEAF_ENTRY RhNewString, _TEXT

#ifdef FEATURE_NATIVEAOT
mov ax, [rdi + OFFSETOF__MethodTable__m_usNumVtableSlots]
test ax, ax
jnz LOCAL_LABEL(RhNewString_ValidMethodTable)
int 3
LOCAL_LABEL(RhNewString_ValidMethodTable):
#endif

// we want to limit the element count to the non-negative 32-bit int range
cmp rsi, MAX_STRING_LENGTH
ja LOCAL_LABEL(StringSizeOverflow)
Expand Down Expand Up @@ -203,6 +234,14 @@ LEAF_END RhNewString, _TEXT
// ESI == element count
LEAF_ENTRY RhpNewArrayFast, _TEXT

#ifdef FEATURE_NATIVEAOT
mov ax, [rdi + OFFSETOF__MethodTable__m_usNumVtableSlots]
test ax, ax
jnz LOCAL_LABEL(RhpNewArrayFast_ValidMethodTable)
int 3
LOCAL_LABEL(RhpNewArrayFast_ValidMethodTable):
#endif

// we want to limit the element count to the non-negative 32-bit int range
cmp rsi, 0x07fffffff
ja LOCAL_LABEL(ArraySizeOverflow)
Expand Down Expand Up @@ -232,6 +271,14 @@ LEAF_END RhpNewArrayFast, _TEXT
// ESI == element count
LEAF_ENTRY RhpNewPtrArrayFast, _TEXT

#ifdef FEATURE_NATIVEAOT
mov ax, [rdi + OFFSETOF__MethodTable__m_usNumVtableSlots]
test ax, ax
jnz LOCAL_LABEL(RhpNewPtrArrayFast_ValidMethodTable)
int 3
LOCAL_LABEL(RhpNewPtrArrayFast_ValidMethodTable):
#endif

// Delegate overflow handling to the generic helper conservatively
// The constant 0x8000000 is (0x40000000 / sizeof(void*))
// Some assemblers don't like an expression here, so the
Expand Down Expand Up @@ -261,6 +308,14 @@ NESTED_ENTRY RhpNewVariableSizeObject, _TEXT, NoHandler

PUSH_COOP_PINVOKE_FRAME rcx

#ifdef FEATURE_NATIVEAOT
mov ax, [rdi + OFFSETOF__MethodTable__m_usNumVtableSlots]
test ax, ax
jnz LOCAL_LABEL(RhpNewVariableSizeObject_ValidMethodTable)
int 3
LOCAL_LABEL(RhpNewVariableSizeObject_ValidMethodTable):
#endif

// rcx: transition frame

// Preserve the MethodTable in RBX
Expand Down
55 changes: 55 additions & 0 deletions src/coreclr/runtime/amd64/AllocFast.asm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ include AsmMacros_Shared.inc
;; RCX == MethodTable
LEAF_ENTRY RhpNewFast, _TEXT

ifdef FEATURE_NATIVEAOT
mov ax, [rcx + OFFSETOF__MethodTable__m_usNumVtableSlots]
test ax, ax
jnz RhpNewFast_ValidMethodTable
mov eax, [rcx]
and eax, 7C000000h
jz RhpNewFast_ValidMethodTable
int 3
RhpNewFast_ValidMethodTable:
endif

;; rdx = ee_alloc_context pointer, TRASHES rax
INLINE_GET_ALLOC_CONTEXT_BASE rdx, rax

Expand Down Expand Up @@ -66,6 +77,17 @@ NESTED_ENTRY RhpNewObject, _TEXT

; R9: transition frame

ifdef FEATURE_NATIVEAOT
mov ax, [rcx + OFFSETOF__MethodTable__m_usNumVtableSlots]
test ax, ax
jnz RhpNewObject_ValidMethodTable
mov eax, [rcx]
and eax, 7C000000h
jz RhpNewObject_ValidMethodTable
int 3
RhpNewObject_ValidMethodTable:
endif

;; Preserve the MethodTable in RSI
mov rsi, rcx

Expand Down Expand Up @@ -131,6 +153,15 @@ ENDM ; NEW_ARRAY_FAST
;; RDX == character/element count
LEAF_ENTRY RhNewString, _TEXT

ifdef FEATURE_NATIVEAOT
mov ax, [rcx + OFFSETOF__MethodTable__m_usNumVtableSlots]
test ax, ax
jnz RhNewString_ValidMethodTable
int 3
RhNewString_ValidMethodTable:
endif


; we want to limit the element count to the non-negative 32-bit int range
cmp rdx, MAX_STRING_LENGTH
ja StringSizeOverflow
Expand Down Expand Up @@ -158,6 +189,14 @@ LEAF_END RhNewString, _TEXT
;; EDX == element count
LEAF_ENTRY RhpNewArrayFast, _TEXT

ifdef FEATURE_NATIVEAOT
mov ax, [rcx + OFFSETOF__MethodTable__m_usNumVtableSlots]
test ax, ax
jnz RhpNewArrayFast_ValidMethodTable
int 3
RhpNewArrayFast_ValidMethodTable:
endif

; we want to limit the element count to the non-negative 32-bit int range
cmp rdx, 07fffffffh
ja ArraySizeOverflow
Expand Down Expand Up @@ -187,6 +226,14 @@ LEAF_END RhpNewArrayFast, _TEXT
;; EDX == element count
LEAF_ENTRY RhpNewPtrArrayFast, _TEXT

ifdef FEATURE_NATIVEAOT
mov ax, [rcx + OFFSETOF__MethodTable__m_usNumVtableSlots]
test ax, ax
jnz RhpNewPtrArrayFast_ValidMethodTable
int 3
RhpNewPtrArrayFast_ValidMethodTable:
endif

; Delegate overflow handling to the generic helper conservatively

cmp rdx, (40000000h / 8) ; sizeof(void*)
Expand All @@ -213,6 +260,14 @@ NESTED_ENTRY RhpNewVariableSizeObject, _TEXT

PUSH_COOP_PINVOKE_FRAME r9

ifdef FEATURE_NATIVEAOT
mov ax, [rcx + OFFSETOF__MethodTable__m_usNumVtableSlots]
test ax, ax
jnz RhpNewVariableSizeObject_ValidMethodTable
int 3
RhpNewVariableSizeObject_ValidMethodTable:
endif

; r9: transition frame

; Preserve the MethodTable in RSI
Expand Down
Loading
Loading