Skip to content

Commit 3249cec

Browse files
committed
[df] Ensure there is code to JIT before calling the interpreter
In an explicit multithreading scenario inside the `RLoopManager::Jit` method, a thread might move the global string with the code to JIT into its own function stack while another thread might still believe that string is not empty. This would make the other thread call `InterpreterCalc` with an empty string which would eventually lead to an exception. Check for the string emptiness twice, once at the beginning of the function, then again after taking the write lock so that if another thread already moved the string then the current thread will not continue with JITting.
1 parent 86c17c0 commit 3249cec

File tree

1 file changed

+10
-4
lines changed

1 file changed

+10
-4
lines changed

Diff for: tree/dataframe/src/RLoopManager.cxx

+10-4
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,7 @@ void RLoopManager::CleanUpTask(TTreeReader *r, unsigned int slot)
805805
/// This method also clears the contents of GetCodeToJit().
806806
void RLoopManager::Jit()
807807
{
808+
808809
{
809810
R__READ_LOCKGUARD(ROOT::gCoreMutex);
810811
if (GetCodeToJit().empty()) {
@@ -813,10 +814,15 @@ void RLoopManager::Jit()
813814
}
814815
}
815816

816-
const std::string code = []() {
817-
R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
818-
return std::move(GetCodeToJit());
819-
}();
817+
R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
818+
// Check again if another thread has already cleared the global string
819+
// with the code to JIT. Without this check, we could end up calling
820+
// InterpreterCalc with an empty string, which would raise an exception.
821+
if (GetCodeToJit().empty()) {
822+
R__LOG_INFO(RDFLogChannel()) << "Nothing to jit and execute.";
823+
return;
824+
}
825+
const std::string code = std::move(GetCodeToJit());
820826

821827
TStopwatch s;
822828
s.Start();

0 commit comments

Comments
 (0)