Skip to content

Commit 249b4af

Browse files
committed
[MERGE #5213 @sigatrev] OS#17384939: avoid race condition when writing callback info IDL
Merge pull request #5213 from sigatrev:callbackrace original setup would add elements to the front of the list when profiling instructions, and would iterator over the whole list while writing the IDL. If an element was added between creating the IDL array and beginning the iteration, too many elements would be written and we'd AV. This changes the setup to add new elements to the end of the list, and limit the number of iterations based on the size of the IDL array created. This should allow elements to be safely added to the list after creating the array. Elements are never removed from the list.
2 parents d04e9e7 + b5e646d commit 249b4af

File tree

2 files changed

+41
-25
lines changed

2 files changed

+41
-25
lines changed

lib/Backend/JITTimeProfileInfo.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,22 @@ JITTimeProfileInfo::InitializeJITProfileData(
9393
else
9494
{
9595
data->profiledCallbackCount = static_cast<Js::ProfileId>(callbackInfoList->Count());
96-
data->callbackData = AnewArrayZ(alloc, CallbackInfoIDL, data->profiledCallbackCount);
97-
98-
size_t callbackInfoIndex = 0;
99-
FOREACH_SLIST_ENTRY(Field(Js::CallbackInfo *), callbackInfo, callbackInfoList)
96+
if (data->profiledCallbackCount > 0)
10097
{
101-
memcpy_s(
102-
&data->callbackData[callbackInfoIndex],
103-
sizeof(CallbackInfoIDL),
104-
callbackInfo,
105-
sizeof(Js::CallbackInfo)
106-
);
107-
++callbackInfoIndex;
98+
data->callbackData = AnewArrayZ(alloc, CallbackInfoIDL, data->profiledCallbackCount);
99+
Js::CallbackInfoList::Iterator iter = callbackInfoList->GetIterator();
100+
for (Js::ProfileId callbackInfoIndex = 0; callbackInfoIndex < data->profiledCallbackCount; ++callbackInfoIndex)
101+
{
102+
iter.Next();
103+
Js::CallbackInfo * info = iter.Data();
104+
memcpy_s(
105+
&data->callbackData[callbackInfoIndex],
106+
sizeof(CallbackInfoIDL),
107+
info,
108+
sizeof(Js::CallbackInfo)
109+
);
110+
}
108111
}
109-
NEXT_SLIST_ENTRY
110112
}
111113

112114
CompileAssert(sizeof(BVUnitIDL) == sizeof(BVUnit));

lib/Runtime/Language/DynamicProfileInfo.cpp

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,20 @@ namespace Js
476476
}
477477
}
478478

479+
CallbackInfoList::EditingIterator TryFindCallbackInfoIterator(CallbackInfoList * list, ProfileId callSiteId)
480+
{
481+
CallbackInfoList::EditingIterator iter = list->GetEditingIterator();
482+
while (iter.Next())
483+
{
484+
if (iter.Data()->callSiteId == callSiteId)
485+
{
486+
return iter;
487+
}
488+
}
489+
490+
return iter;
491+
}
492+
479493
CallbackInfo * DynamicProfileInfo::FindCallbackInfo(FunctionBody * funcBody, ProfileId callSiteId)
480494
{
481495
CallbackInfoList * list = funcBody->GetCallbackInfoList();
@@ -484,14 +498,11 @@ namespace Js
484498
return nullptr;
485499
}
486500

487-
FOREACH_SLIST_ENTRY(Field(CallbackInfo *), callbackInfo, list)
501+
CallbackInfoList::EditingIterator iter = TryFindCallbackInfoIterator(list, callSiteId);
502+
if (iter.IsValid())
488503
{
489-
if (callbackInfo->callSiteId == callSiteId)
490-
{
491-
return callbackInfo;
492-
}
504+
return iter.Data();
493505
}
494-
NEXT_SLIST_ENTRY;
495506

496507
return nullptr;
497508
}
@@ -506,16 +517,19 @@ namespace Js
506517
funcBody->SetCallbackInfoList(list);
507518
}
508519

509-
CallbackInfo * info = FindCallbackInfo(funcBody, callSiteId);
510-
if (info == nullptr)
520+
CallbackInfoList::EditingIterator iter = TryFindCallbackInfoIterator(list, callSiteId);
521+
if (iter.IsValid())
511522
{
512-
info = RecyclerNewStructZ(funcBody->GetScriptContext()->GetRecycler(), CallbackInfo);
513-
info->callSiteId = callSiteId;
514-
info->sourceId = NoSourceId;
515-
info->canInlineCallback = true;
516-
list->Prepend(info);
523+
return iter.Data();
517524
}
518525

526+
// Callsite is not already in the list, so add it to the end.
527+
CallbackInfo * info = info = RecyclerNewStructZ(funcBody->GetScriptContext()->GetRecycler(), CallbackInfo);
528+
info->callSiteId = callSiteId;
529+
info->sourceId = NoSourceId;
530+
info->canInlineCallback = true;
531+
532+
iter.InsertBefore(info);
519533
return info;
520534
}
521535

0 commit comments

Comments
 (0)