Skip to content

Commit e12a388

Browse files
committed
[RF] Correctly treat variables with integer names in RooFormula
In case of named arguments, the RooFormula will replace the argument names with` x[0]` to `x[n]`. There are two things that can go wrong if RooFormula is not implemented right. First, if there is a variable named "x" it should only be substituted if the matching substring is not followed by "[", to not replace existing x[i]. Second, variables with integer names like "0" should only be substituted if the match is not followed by a "]", again to avoid replacing x[i]. This test checks that these cases are handled correctly. The second case was so far not dealt with correctly, but with this commit it is. A corresponding unit test was also implemented. The preprocessor commands in `RooFormula` were also reorganized slightly, such that one can test the `TPRegexp` backend simply by commenting out the `define ROOFORMULA_HAVE_STD_REGEX`.
1 parent d9b262a commit e12a388

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

roofit/roofitcore/src/RooFormula.cxx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ RooFormula::RooFormula(const RooFormula& other, const char* name) :
148148
#ifndef _MSC_VER
149149
#if !defined(__GNUC__) || defined(__clang__) || (__GNUC__ > 4) || ( __GNUC__ == 4 && __GNUC_MINOR__ > 8)
150150
#define ROOFORMULA_HAVE_STD_REGEX
151+
#endif //GCC < 4.9 Check
152+
#endif //_MSC_VER
153+
154+
#ifdef ROOFORMULA_HAVE_STD_REGEX
151155
////////////////////////////////////////////////////////////////////////////////
152156
/// Process given formula by replacing all ordinal and name references by
153157
/// `x[i]`, where `i` matches the position of the argument in `_origList`.
@@ -208,6 +212,7 @@ std::string RooFormula::processFormula(std::string formula) const {
208212
auto regex = std::string{"\\b"} + var.GetName();
209213
regex = std::regex_replace(regex, std::regex("([\\[\\]\\{\\}])"), "\\$1"); // The name might contain [, ], {, or }.
210214
regex += "\\b(?!\\[)"; // Veto '[' as next character. If the variable is called `x`, this might otherwise replace `x[0]`.
215+
regex += "\\b(?!\\])"; // Veto ']' as next character. If the variable is called `0`, this might otherwise replace `x[0]`.
211216
std::regex findParameterRegex(regex);
212217

213218
std::stringstream replacement;
@@ -270,8 +275,7 @@ std::string RooFormula::reconstructFormula(std::string internalRepr) const {
270275

271276
return internalRepr;
272277
}
273-
#endif //GCC < 4.9 Check
274-
#endif //_MSC_VER
278+
#endif //ROOFORMULA_HAVE_STD_REGEX
275279

276280

277281

@@ -613,6 +617,7 @@ std::string RooFormula::processFormula(std::string formula) const {
613617
TString regex = "\\b";
614618
regex += var.GetName();
615619
regex += "\\b([^[]|$)"; //Negative lookahead. If the variable is called `x`, this might otherwise replace `x[0]`.
620+
regex += "\\b([^]]|$)"; //Negative lookahead. If the variable is called `0`, this might otherwise replace `x[0]`.
616621
TPRegexp findParameterRegex(regex);
617622

618623
std::stringstream replacement;
@@ -687,4 +692,4 @@ std::string RooFormula::reconstructFormula(std::string internalRepr) const {
687692

688693
return internalReprT.Data();
689694
}
690-
#endif //GCC < 4.9 Check
695+
#endif //ROOFORMULA_HAVE_STD_REGEX

roofit/roofitcore/test/testRooFormula.cxx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,20 @@ TEST(RooFormula, TestInvalidFormulae) {
4040
EXPECT_FLOAT_EQ(form6->eval(nullptr), 1.337 - 1.);
4141
delete form6;
4242
}
43+
44+
// In case of named arguments, the RooFormula will replace the argument names
45+
// with x[0] to x[n]. There are two things that can go wrong if RooFormula is
46+
// not implemented right. First, if there is a variable named "x" it should
47+
// only be substituted if the matching substring is not followed by "[", to not
48+
// replace existing x[i]. Second, variables with integer names like "0" should
49+
// only be substituted if the match is not followed by a "]", again to avoid
50+
// replacing x[i]. This test checks that these cases are handled correctly.
51+
TEST(RooFormula, TestDangerousVariableNames) {
52+
RooRealVar dt("dt", "dt", -10, 10);
53+
RooRealVar x("x", "x", 1.547);
54+
RooRealVar zero("0", "0", 0);
55+
56+
// Create the formula, triggers an error if the formula doesn't compile
57+
// correctly because the dangerous variable names haven't been treated right.
58+
RooFormula formula("formula", "exp(-abs(@0)/@1)*cos(@0*@2)", {dt, x, zero});
59+
}

0 commit comments

Comments
 (0)