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
2 changes: 1 addition & 1 deletion roofit/roofitcore/inc/RooAbsArg.h
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,7 @@ class RooAbsArg : public TNamed, public RooPrintable {

RooAbsProxy *getProxy(Int_t index) const;
Int_t numProxies() const;
void setProxyNormSet(const RooArgSet *nset);

/// De-duplicated pointer to this object's name.
/// This can be used for fast name comparisons.
Expand Down Expand Up @@ -582,7 +583,6 @@ class RooAbsArg : public TNamed, public RooPrintable {
void unRegisterProxy(RooArgProxy &proxy);
void unRegisterProxy(RooSetProxy &proxy);
void unRegisterProxy(RooListProxy &proxy);
void setProxyNormSet(const RooArgSet *nset);

// Attribute list
std::set<std::string> _boolAttrib; // Boolean attributes
Expand Down
5 changes: 4 additions & 1 deletion roofit/roofitcore/src/RooAbsArg.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1284,7 +1284,10 @@ Int_t RooAbsArg::numProxies() const
}

/// Forward a change in the cached normalization argset
/// to all the registered proxies.
/// to all the registered proxies. Passing `nullptr` makes this object forget
/// any normalization set previously passed to `getVal()`, which is required if
/// that set may not outlive this object (e.g. it lived on the caller's stack),
/// as the proxies only keep a bare pointer to it.

void RooAbsArg::setProxyNormSet(const RooArgSet *nset)
{
Expand Down
19 changes: 19 additions & 0 deletions roofit/xroofit/src/xRooNode.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -9355,6 +9355,25 @@ TH1 *xRooNode::BuildHistogram(RooAbsLValue *v, bool empty, bool errors, int binS
}
}

// We evaluated the above with `normSet`, which lives on this function's stack.
// RooFit proxies only cache a bare pointer to the last normSet and re-use it
// later (e.g. RooProduct::evaluate reads back _compRSet.nset()), so before it
// goes out of scope we must clear it everywhere it could have been cached,
// otherwise a later evaluation dereferences freed stack ("use of uninitialised
// value" in valgrind). sterilize() only walks clients, but getVal() propagates
// the normSet to the servers of the evaluated function, so reset those here.
{
RooArgSet evaluatedNodes;
for (RooAbsArg *treeRoot : {static_cast<RooAbsArg *>(rar), static_cast<RooAbsArg *>(p),
static_cast<RooAbsArg *>(oldrar), _coefs.get<RooAbsArg>()}) {
if (treeRoot)
treeRoot->treeNodeServerList(&evaluatedNodes);
}
for (RooAbsArg *node : evaluatedNodes) {
node->setProxyNormSet(nullptr);
}
}

if (oldrar) {
std::vector<RooAbsArg *> extra;
if (auto s = dynamic_cast<RooSimultaneous *>(rar)) {
Expand Down
Loading