-
Notifications
You must be signed in to change notification settings - Fork 151
[IAST] Fix racing conditions in Dataflow #7838
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
base: master
Are you sure you want to change the base?
Changes from 4 commits
41f968b
d196232
e742073
4828694
64ff1b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -182,7 +182,9 @@ Dataflow::Dataflow(ICorProfilerInfo* profiler, std::shared_ptr<RejitHandler> rej | |
|
|
||
| Dataflow::~Dataflow() | ||
| { | ||
| _initialized = false; | ||
| CSGUARD(_cs); | ||
| SetInitialized(false); | ||
|
|
||
| REL(_profiler); | ||
| DEL_MAP_VALUES(_modules); | ||
| DEL_MAP_VALUES(_appDomains); | ||
|
|
@@ -191,9 +193,9 @@ Dataflow::~Dataflow() | |
|
|
||
| void Dataflow::LoadAspects(WCHAR** aspects, int aspectsLength, UINT32 enabledCategories, UINT32 platform) | ||
| { | ||
| if (!_initialized) | ||
| if (!IsInitialized()) | ||
| { | ||
| _initialized = true; | ||
| SetInitialized(true); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Silly question, but could this also be part of the problem? 🤔 We set I feel like we probably need something more like this? CSGUARD(_cs);
if (!IsInitialized())
{
// Do all the other work in the if block
SetInitialized(true);
}
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes I do think you need to guard in this one as well.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The main problem is here, in LoadAspects, and this function is the one that has to be well covered. _isInitialized should be set to true as the last thing done here, not in the begining of the function. |
||
|
|
||
| // Init aspects | ||
| DBG("Dataflow::LoadAspects -> Processing aspects... ", aspectsLength, " Enabled categories: ", enabledCategories, " Platform: ", platform); | ||
|
|
@@ -237,9 +239,15 @@ void Dataflow::LoadAspects(WCHAR** aspects, int aspectsLength, UINT32 enabledCat | |
|
|
||
| LoadSecurityControls(); | ||
|
|
||
| auto moduleAspects = _moduleAspects; | ||
| _moduleAspects.clear(); | ||
| DEL_MAP_VALUES(moduleAspects); | ||
| // Move the map out under the lock | ||
| std::map<ModuleID, ModuleAspects*> oldModuleAspects; | ||
| { | ||
| CSGUARD(_cs); | ||
| oldModuleAspects.swap(_moduleAspects); | ||
| } | ||
|
|
||
| // Destroy outside the lock | ||
| DEL_MAP_VALUES(oldModuleAspects) | ||
|
|
||
| trace::Logger::Info("Dataflow::LoadAspects -> read ", _aspects.size(), " aspects"); | ||
| m_rejitHandler->RegisterRejitter(this); | ||
|
|
@@ -369,12 +377,12 @@ void Dataflow::LoadSecurityControls() | |
|
|
||
| HRESULT Dataflow::AppDomainShutdown(AppDomainID appDomainId) | ||
| { | ||
| if (!_initialized) | ||
| CSGUARD(_cs); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want to use double checking here to avoid contention? I'm not sure it's a big problem for // Initial check outside the lock
if (!IsInitialized())
{
return S_OK;
}
CSGUARD(_cs);
// Double check inside the lock
if (!IsInitialized())
{
return S_OK;
}
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we add the guard for each IsInitialized() call we should consider to just use a normal bool instead of the atomic bool.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are not going to find the situation where a threar reads true while it has been set to false. The problem is the oposite, in initialization. IMO the whole thing could be solved with deferring the set to true in _isInitialized to the end of the LoadAspects function. |
||
| if (!IsInitialized()) | ||
| { | ||
| return S_OK; | ||
| } | ||
|
|
||
| CSGUARD(_cs); | ||
| auto it = _appDomains.find(appDomainId); | ||
| if (it != _appDomains.end()) | ||
| { | ||
|
|
@@ -388,7 +396,7 @@ HRESULT Dataflow::AppDomainShutdown(AppDomainID appDomainId) | |
|
|
||
| HRESULT Dataflow::ModuleLoaded(ModuleID moduleId, ModuleInfo** pModuleInfo) | ||
| { | ||
| if (!_initialized) | ||
| if (!IsInitialized()) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This still has the CSGUARD after the
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. GetModuleInfo() already checks for that, this is just an early check. |
||
| { | ||
| return S_OK; | ||
| } | ||
|
|
@@ -399,12 +407,12 @@ HRESULT Dataflow::ModuleLoaded(ModuleID moduleId, ModuleInfo** pModuleInfo) | |
|
|
||
| HRESULT Dataflow::ModuleUnloaded(ModuleID moduleId) | ||
| { | ||
| if (!_initialized) | ||
| CSGUARD(_cs); | ||
| if (!IsInitialized()) | ||
| { | ||
| return S_OK; | ||
| } | ||
|
|
||
| CSGUARD(_cs); | ||
| { | ||
| auto it = _moduleAspects.find(moduleId); | ||
| if (it != _moduleAspects.end()) | ||
|
|
@@ -510,6 +518,11 @@ ICorProfilerInfo* Dataflow::GetCorProfilerInfo() | |
| AppDomainInfo* Dataflow::GetAppDomain(AppDomainID id) | ||
| { | ||
| CSGUARD(_cs); | ||
| if (!IsInitialized()) | ||
| { | ||
| return nullptr; | ||
| } | ||
|
|
||
| auto found = _appDomains.find(id); | ||
| if (found != _appDomains.end()) | ||
| { | ||
|
|
@@ -538,6 +551,11 @@ AppDomainInfo* Dataflow::GetAppDomain(AppDomainID id) | |
| ModuleInfo* Dataflow::GetModuleInfo(ModuleID id) | ||
| { | ||
| CSGUARD(_cs); | ||
| if (!IsInitialized()) | ||
| { | ||
| return nullptr; | ||
| } | ||
|
|
||
| auto found = _modules.find(id); | ||
| if (found != _modules.end()) | ||
| { | ||
|
|
@@ -595,7 +613,11 @@ ModuleInfo* Dataflow::GetModuleInfo(ModuleID id) | |
|
|
||
| ModuleInfo* Dataflow::GetAspectsModule(AppDomainID id) | ||
| { | ||
| CSGUARD(_cs); | ||
| if (!IsInitialized()) | ||
andrewlock marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| return nullptr; | ||
| } | ||
|
|
||
| ModuleID moduleId = trace::profiler->GetProfilerAssemblyModuleId(id); | ||
|
|
||
| if (moduleId > 0) | ||
|
|
@@ -618,7 +640,7 @@ MethodInfo* Dataflow::GetMethodInfo(ModuleID moduleId, mdMethodDef methodId) | |
|
|
||
| bool Dataflow::IsInlineEnabled(ModuleID calleeModuleId, mdToken calleeMethodId) | ||
| { | ||
| if (!_initialized) | ||
| if (!IsInitialized()) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like there's a bunch of places here without the guards... is that safe?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is safe as long as we dont perform sensitive operations. In this case, IsInitialized() is already safe because we are using an atomic bool and we will recheck that later in a locked envirinment. |
||
| { | ||
| return true; | ||
| } | ||
|
|
@@ -632,7 +654,7 @@ bool Dataflow::IsInlineEnabled(ModuleID calleeModuleId, mdToken calleeMethodId) | |
| } | ||
| bool Dataflow::JITCompilationStarted(ModuleID moduleId, mdToken methodId) | ||
| { | ||
| if (!_initialized) | ||
| if (!IsInitialized()) | ||
| { | ||
| return false; | ||
| } | ||
|
|
@@ -642,7 +664,7 @@ bool Dataflow::JITCompilationStarted(ModuleID moduleId, mdToken methodId) | |
| } | ||
| MethodInfo* Dataflow::JITProcessMethod(ModuleID moduleId, mdToken methodId, trace::FunctionControlWrapper* pFunctionControl) | ||
| { | ||
| if (!_initialized) | ||
| if (!IsInitialized()) | ||
| { | ||
| return nullptr; | ||
| } | ||
|
|
@@ -741,6 +763,12 @@ HRESULT Dataflow::RewriteMethod(MethodInfo* method, trace::FunctionControlWrappe | |
|
|
||
| std::vector<DataflowAspectReference*> Dataflow::GetAspects(ModuleInfo* module) | ||
| { | ||
| CSGUARD(_cs); | ||
| if (!IsInitialized()) | ||
| { | ||
| return std::vector<DataflowAspectReference*>(); | ||
| } | ||
|
|
||
| auto value = _moduleAspects.find(module->_id); | ||
| if (value != _moduleAspects.end()) | ||
| { | ||
|
|
@@ -783,7 +811,7 @@ void Dataflow::AddNGenInlinerModule(ModuleID moduleId) | |
|
|
||
| HRESULT Dataflow::RejitMethod(trace::FunctionControlWrapper& functionControl) | ||
| { | ||
| if (!_initialized) | ||
| if (!IsInitialized()) | ||
| { | ||
| return S_FALSE; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dataflow is destroyed on profiler unload and this is the only place where _initialized is set to false. This CS is unnecessary (although does not hurt).