Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 013eb56

Browse files
authored
Fix manual GC_PROTECTs around StackTraceArray (#15621)
StackTraceArray wraps GC reference that needs to be GC_PROTECTED exactly once accross all GC triggering points. The calls from copy constructor and assignment operator were violating this invariant. I have fixed this by deleting the copy constructor and assignment operator, and replaced their use by explicit CopyFrom method. Fixes #15537
1 parent d7d457f commit 013eb56

File tree

2 files changed

+14
-36
lines changed

2 files changed

+14
-36
lines changed

src/vm/object.cpp

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2997,6 +2997,7 @@ void StackTraceArray::Append(StackTraceElement const * begin, StackTraceElement
29972997
THROWS;
29982998
GC_TRIGGERS;
29992999
MODE_COOPERATIVE;
3000+
PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)this));
30003001
}
30013002
CONTRACTL_END;
30023003

@@ -3021,6 +3022,7 @@ void StackTraceArray::AppendSkipLast(StackTraceElement const * begin, StackTrace
30213022
THROWS;
30223023
GC_TRIGGERS;
30233024
MODE_COOPERATIVE;
3025+
PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)this));
30243026
}
30253027
CONTRACTL_END;
30263028

@@ -3048,8 +3050,9 @@ void StackTraceArray::AppendSkipLast(StackTraceElement const * begin, StackTrace
30483050
else
30493051
{
30503052
// slow path: create a copy and append
3051-
StackTraceArray copy(*this);
3053+
StackTraceArray copy;
30523054
GCPROTECT_BEGIN(copy);
3055+
copy.CopyFrom(*this);
30533056
copy.SetSize(copy.Size() - 1);
30543057
copy.Append(begin, end);
30553058
this->Swap(copy);
@@ -3091,6 +3094,7 @@ void StackTraceArray::Grow(size_t grow_size)
30913094
GC_TRIGGERS;
30923095
MODE_COOPERATIVE;
30933096
INJECT_FAULT(ThrowOutOfMemory(););
3097+
PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)this));
30943098
}
30953099
CONTRACTL_END;
30963100

@@ -3132,38 +3136,18 @@ void StackTraceArray::EnsureThreadAffinity()
31323136
{
31333137
// object is being changed by a thread different from the one which created it
31343138
// make a copy of the array to prevent a race condition when two different threads try to change it
3135-
StackTraceArray copy(*this);
3136-
this->Swap(copy);
3139+
StackTraceArray copy;
3140+
GCPROTECT_BEGIN(copy);
3141+
copy.CopyFrom(*this);
3142+
this->Swap(copy);
3143+
GCPROTECT_END();
31373144
}
31383145
}
31393146

31403147
#ifdef _MSC_VER
31413148
#pragma warning(disable: 4267)
31423149
#endif
31433150

3144-
StackTraceArray::StackTraceArray(StackTraceArray const & rhs)
3145-
{
3146-
CONTRACTL
3147-
{
3148-
THROWS;
3149-
GC_TRIGGERS;
3150-
MODE_COOPERATIVE;
3151-
INJECT_FAULT(ThrowOutOfMemory(););
3152-
}
3153-
CONTRACTL_END;
3154-
3155-
m_array = (I1ARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_I1, static_cast<DWORD>(rhs.Capacity()));
3156-
3157-
GCPROTECT_BEGIN(m_array);
3158-
Volatile<size_t> size = rhs.Size();
3159-
memcpyNoGCRefs(GetRaw(), rhs.GetRaw(), size * sizeof(StackTraceElement) + sizeof(ArrayHeader));
3160-
3161-
SetSize(size); // set size to the exact value which was used when we copied the data
3162-
// another thread might have changed it at the time of copying
3163-
SetObjectThread(); // affinitize the newly created array with the current thread
3164-
GCPROTECT_END();
3165-
}
3166-
31673151
// Deep copies the stack trace array
31683152
void StackTraceArray::CopyFrom(StackTraceArray const & src)
31693153
{
@@ -3173,19 +3157,19 @@ void StackTraceArray::CopyFrom(StackTraceArray const & src)
31733157
GC_TRIGGERS;
31743158
MODE_COOPERATIVE;
31753159
INJECT_FAULT(ThrowOutOfMemory(););
3160+
PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)this));
3161+
PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)&src));
31763162
}
31773163
CONTRACTL_END;
31783164

31793165
m_array = (I1ARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_I1, static_cast<DWORD>(src.Capacity()));
31803166

3181-
GCPROTECT_BEGIN(m_array);
31823167
Volatile<size_t> size = src.Size();
31833168
memcpyNoGCRefs(GetRaw(), src.GetRaw(), size * sizeof(StackTraceElement) + sizeof(ArrayHeader));
31843169

31853170
SetSize(size); // set size to the exact value which was used when we copied the data
31863171
// another thread might have changed it at the time of copying
31873172
SetObjectThread(); // affinitize the newly created array with the current thread
3188-
GCPROTECT_END();
31893173
}
31903174

31913175
#ifdef _MSC_VER

src/vm/object.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3110,15 +3110,9 @@ class StackTraceArray
31103110
void CopyFrom(StackTraceArray const & src);
31113111

31123112
private:
3113-
StackTraceArray(StackTraceArray const & rhs);
3113+
StackTraceArray(StackTraceArray const & rhs) = delete;
31143114

3115-
StackTraceArray & operator=(StackTraceArray const & rhs)
3116-
{
3117-
WRAPPER_NO_CONTRACT;
3118-
StackTraceArray copy(rhs);
3119-
this->Swap(copy);
3120-
return *this;
3121-
}
3115+
StackTraceArray & operator=(StackTraceArray const & rhs) = delete;
31223116

31233117
void Grow(size_t size);
31243118
void EnsureThreadAffinity();

0 commit comments

Comments
 (0)