diff --git a/io/io/inc/ROOT/RFile.hxx b/io/io/inc/ROOT/RFile.hxx index c3d7fe8637270..9b2000e01abd2 100644 --- a/io/io/inc/ROOT/RFile.hxx +++ b/io/io/inc/ROOT/RFile.hxx @@ -381,6 +381,9 @@ public: /// Puts object `namedObj` in the file under the path `dirPath/namedObj.GetName()`, giving it a title equal to /// `namedObj.GetTitle()`. /// If `dirPath` is empty (default), the object is put at the top level of the file. + /// + /// \throws ROOT::RException if `dirPath/namedObj.GetName()` results in an invalid object path. Notably, this + /// includes the case where `namedObj.GetName()` contains a slash character. void Put(const class TNamed &namedObj, std::string_view dirPath = ""); /// Puts an object into the file, overwriting any previously-existing object at that path. diff --git a/io/io/src/RFile.cxx b/io/io/src/RFile.cxx index 15e6d786732a3..09843058bff76 100644 --- a/io/io/src/RFile.cxx +++ b/io/io/src/RFile.cxx @@ -331,6 +331,10 @@ void *RFile::GetUntyped(std::string_view path, void RFile::Put(const TNamed &namedObj, std::string_view dirPath) { + if (strchr(namedObj.GetName(), '/')) { + throw ROOT::RException(R__FAIL(std::string("TNamed object '") + namedObj.GetName() + + "' given to RFile::Put cannot have '/' in its name!")); + } std::string completePath = (dirPath.empty() ? "" : std::string(dirPath) + '/') + namedObj.GetName(); Put(completePath, namedObj, namedObj.GetTitle()); } diff --git a/io/io/test/rfile.cxx b/io/io/test/rfile.cxx index 410b25b40fa9b..8f6793aacc62a 100644 --- a/io/io/test/rfile.cxx +++ b/io/io/test/rfile.cxx @@ -931,3 +931,39 @@ TEST(RFile, PutTNamed) EXPECT_EQ(key2.GetTitle(), "title 2"); } } + +TEST(RFile, PutTNamedInvalid) +{ + FileRaii fileGuard("test_rfile_put_tnamed_invalid.root"); + + { + TNamed named1("my/funny/name", "title 1"); + TNamed named2("", "title 2"); + TNamed named3("invalid.name", "title 3"); + auto file = RFile::Recreate(fileGuard.GetPath()); + try { + file->Put(named1); + FAIL() << "putting objects with a slash in their name should fail."; + } catch (const ROOT::RException &ex) { + EXPECT_THAT(ex.what(), testing::HasSubstr("cannot have '/'")); + } + try { + file->Put(named2, "my/dir"); + FAIL() << "putting objects with an empty name should fail."; + } catch (const ROOT::RException &ex) { + EXPECT_THAT(ex.what(), testing::HasSubstr("Invalid object path")); + } + try { + file->Put(named2); + FAIL() << "putting objects with an empty name should fail."; + } catch (const ROOT::RException &ex) { + EXPECT_THAT(ex.what(), testing::HasSubstr("Invalid object path")); + } + try { + file->Put(named3); + FAIL() << "putting objects with an invalid name should fail."; + } catch (const ROOT::RException &ex) { + EXPECT_THAT(ex.what(), testing::HasSubstr("Invalid object path")); + } + } +}