Skip to content
Merged
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
25 changes: 21 additions & 4 deletions tree/dataframe/src/RLoopManager.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,14 @@ void DeclareAndRetrieveDeferredJitCalls(const std::string &codeToDeclare)
// error: 'MyHelperType' is an incomplete type
// return std::make_unique<Action_t>(Helper_t(std::move(*h)), bl, std::move(prevNode), colRegister);
// ^
gInterpreter->ProcessLine(codeToDeclare.c_str());
TInterpreter::EErrorCode interpErrorCode(TInterpreter::kNoError);
gInterpreter->ProcessLine(codeToDeclare.c_str(), &interpErrorCode);
if (interpErrorCode != TInterpreter::kNoError) {
throw std::runtime_error(
"\nAn error occurred during just-in-time compilation in RLoopManager::Run. The lines above might "
"indicate the cause of the error.\nAll RDF objects that have not run their event loop yet should be "
"considered in an invalid state.\n");
}

// Step 2: Retrieve the declared functions as function pointers, cache them
// for later use in RunDeferredCalls
Expand All @@ -139,9 +146,19 @@ void DeclareAndRetrieveDeferredJitCalls(const std::string &codeToDeclare)
// fast fetch of the address via gInterpreter
// (faster than gInterpreter->Evaluate(function name, ret), ret->GetAsPointer())
// Retrieve the JIT helper function we registered via RegisterJitHelperCall
auto declid =
gInterpreter->GetFunction(clinfo, ("jitNodeRegistrator_" + std::to_string(codeAndId.second)).c_str());
assert(declid);
const std::string funcName = "jitNodeRegistrator_" + std::to_string(codeAndId.second);
auto declid = gInterpreter->GetFunction(clinfo, funcName.c_str());
if (!declid) {
// The interpreter failed to compile the helper. Without this check
// we would later dereference a null function pointer and crash.
gInterpreter->ClassInfo_Delete(clinfo);
throw std::runtime_error(
"\nAn error occurred during just-in-time compilation in RLoopManager::Run: failed to retrieve "
"the JIT helper function '" +
funcName +
"'. The lines above might indicate the cause of the error.\nAll RDF objects that have not run "
"their event loop yet should be considered in an invalid state.\n");
}
auto minfo = gInterpreter->MethodInfo_Factory(declid);
assert(gInterpreter->MethodInfo_IsValid(minfo));
auto mname = gInterpreter->MethodInfo_GetMangledName(minfo);
Expand Down
32 changes: 31 additions & 1 deletion tree/dataframe/test/dataframe_vary.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,36 @@ TEST(RDFVary, RequireVariationsHaveConsistentTypeJitted)
std::runtime_error);
}
}

// Regression test: when a deferred JIT helper fails to compile (e.g. the
// multi-column Vary() overload was picked with a single-column expression,
// yielding an ill-formed template instantiation), RDataFrame must throw
// instead of dereferencing a null function pointer at event-loop time.
//
// Run in a forked subprocess via EXPECT_EXIT, because the failed cling
// declaration leaves the interpreter in a state from which subsequent
// JIT compilations cannot recover (it would crash later tests).
TEST(RDFVaryDeathTest, JitFailureThrowsInsteadOfCrashing)
{
::testing::FLAGS_gtest_death_test_style = "threadsafe";
EXPECT_EXIT(
{
try {
auto df = ROOT::RDataFrame(10).Define("x", "1.f * rdfentry_");
// Multi-column overload with a single-RVec expression: the
// resulting RVariation<..., IsSingleColumn=false> is ill-formed.
auto bad = df.Vary(std::vector<std::string>{"x"}, "ROOT::RVecF{x - 0.5f, x + 0.5f}",
std::vector<std::string>{"down", "up"}, "xVar");
bad.Count().GetValue();
std::exit(2); // no exception thrown: unexpected
} catch (const std::runtime_error &) {
std::exit(0); // expected path
} catch (...) {
std::exit(3); // wrong exception type
}
},
::testing::ExitedWithCode(0), "");
}
#endif
#endif

Expand Down Expand Up @@ -1917,4 +1947,4 @@ TEST_P(RDFVary, JittedVaryEmptyString)
throw;
},
std::runtime_error);
}
}
Loading