BugFix: interrupting recursive session loading

Prevent crash on  recursive (infinite) loading of session file (containing itself).
This commit is contained in:
Bruno
2021-02-14 18:56:48 +01:00
parent 25c2bb59f5
commit e37b21760e
11 changed files with 71 additions and 41 deletions

View File

@@ -948,7 +948,7 @@ void Mixer::load(const std::string& filename)
if (sessionLoaders_.empty()) { if (sessionLoaders_.empty()) {
// Start async thread for loading the session // Start async thread for loading the session
// Will be obtained in the future in update() // Will be obtained in the future in update()
sessionLoaders_.emplace_back( std::async(std::launch::async, Session::load, filename) ); sessionLoaders_.emplace_back( std::async(std::launch::async, Session::load, filename, 0) );
} }
#else #else
set( Session::load(filename) ); set( Session::load(filename) );
@@ -986,7 +986,7 @@ void Mixer::import(const std::string& filename)
if (sessionImporters_.empty()) { if (sessionImporters_.empty()) {
// Start async thread for loading the session // Start async thread for loading the session
// Will be obtained in the future in update() // Will be obtained in the future in update()
sessionImporters_.emplace_back( std::async(std::launch::async, Session::load, filename) ); sessionImporters_.emplace_back( std::async(std::launch::async, Session::load, filename, 0) );
} }
#else #else
merge( Session::load(filename) ); merge( Session::load(filename) );

View File

@@ -1,6 +1,11 @@
#include <algorithm>
#include "SearchVisitor.h" #include "SearchVisitor.h"
#include "Scene.h" #include "Scene.h"
#include "MediaSource.h"
#include "Session.h"
#include "SessionSource.h"
SearchVisitor::SearchVisitor(Node *node) : Visitor(), node_(node), found_(false) SearchVisitor::SearchVisitor(Node *node) : Visitor(), node_(node), found_(false)
{ {
@@ -42,12 +47,11 @@ void SearchVisitor::visit(Scene &n)
SearchFileVisitor::SearchFileVisitor(std::string filename) : Visitor(), filename_(filename), found_(false) SearchFileVisitor::SearchFileVisitor() : Visitor()
{ {
} }
void SearchFileVisitor::visit(Node &n) void SearchFileVisitor::visit(Node &n)
{ {
@@ -55,13 +59,8 @@ void SearchFileVisitor::visit(Node &n)
void SearchFileVisitor::visit(Group &n) void SearchFileVisitor::visit(Group &n)
{ {
if (found_)
return;
for (NodeSet::iterator node = n.begin(); node != n.end(); node++) { for (NodeSet::iterator node = n.begin(); node != n.end(); node++) {
(*node)->accept(*this); (*node)->accept(*this);
if (found_)
break;
} }
} }
@@ -81,10 +80,29 @@ void SearchFileVisitor::visit(Scene &n)
void SearchFileVisitor::visit (MediaSource& s) void SearchFileVisitor::visit (MediaSource& s)
{ {
filenames_.push_back( s.path() );
} }
void SearchFileVisitor::visit (SessionFileSource& s) void SearchFileVisitor::visit (SessionFileSource& s)
{ {
filenames_.push_back( s.path() );
} }
std::list<std::string> SearchFileVisitor::parse (Session *se)
{
SearchFileVisitor sv;
for (auto iter = se->begin(); iter != se->end(); iter++){
(*iter)->accept(sv);
}
return sv.filenames();
}
bool SearchFileVisitor::find (Session *se, std::string path)
{
std::list<std::string> filenames = parse (se);
return std::find(filenames.begin(), filenames.end(), path) != filenames.end();
}

View File

@@ -1,9 +1,12 @@
#ifndef SEARCHVISITOR_H #ifndef SEARCHVISITOR_H
#define SEARCHVISITOR_H #define SEARCHVISITOR_H
#include <list>
#include <string> #include <string>
#include "Visitor.h" #include "Visitor.h"
class Session;
class SearchVisitor: public Visitor class SearchVisitor: public Visitor
{ {
Node *node_; Node *node_;
@@ -15,33 +18,35 @@ public:
inline Node *node() const { return found_ ? node_ : nullptr; } inline Node *node() const { return found_ ? node_ : nullptr; }
// Elements of Scene // Elements of Scene
void visit(Scene& n) override; void visit (Scene& n) override;
void visit(Node& n) override; void visit (Node& n) override;
void visit(Primitive&) override {} void visit (Primitive&) override {}
void visit(Group& n) override; void visit (Group& n) override;
void visit(Switch& n) override; void visit (Switch& n) override;
}; };
class SearchFileVisitor: public Visitor class SearchFileVisitor: public Visitor
{ {
std::string filename_; std::list<std::string> filenames_;
bool found_;
public: public:
SearchFileVisitor(std::string filename); SearchFileVisitor();
inline bool found() const { return found_; } inline std::list<std::string> filenames() const { return filenames_; }
// Elements of Scene // Elements of Scene
void visit(Scene& n) override; void visit (Scene& n) override;
void visit(Node& n) override; void visit (Node& n) override;
void visit(Primitive&) override {} void visit (Primitive&) override {}
void visit(Group& n) override; void visit (Group& n) override;
void visit(Switch& n) override; void visit (Switch& n) override;
// Sources // Sources
void visit (MediaSource& s) override; void visit (MediaSource& s) override;
void visit (SessionFileSource& s) override; void visit (SessionFileSource& s) override;
static std::list<std::string> parse (Session *se);
static bool find (Session *se, std::string path);
}; };
#endif // SEARCHVISITOR_H #endif // SEARCHVISITOR_H

View File

@@ -4,7 +4,6 @@
#include "Settings.h" #include "Settings.h"
#include "FrameBuffer.h" #include "FrameBuffer.h"
#include "Session.h" #include "Session.h"
#include "GarbageVisitor.h"
#include "FrameGrabber.h" #include "FrameGrabber.h"
#include "SessionCreator.h" #include "SessionCreator.h"
#include "SessionSource.h" #include "SessionSource.h"
@@ -323,9 +322,9 @@ void Session::unlock()
} }
Session *Session::load(const std::string& filename) Session *Session::load(const std::string& filename, uint recursion)
{ {
SessionCreator creator; SessionCreator creator(recursion);
creator.load(filename); creator.load(filename);
return creator.session(); return creator.session();

View File

@@ -14,7 +14,7 @@ public:
Session(); Session();
~Session(); ~Session();
static Session *load(const std::string& filename); static Session *load(const std::string& filename, uint recursion = 0);
// add given source into the session // add given source into the session
SourceList::iterator addSource (Source *s); SourceList::iterator addSource (Source *s);

View File

@@ -52,7 +52,7 @@ std::string SessionCreator::info(const std::string& filename)
return ret; return ret;
} }
SessionCreator::SessionCreator(): SessionLoader(nullptr) SessionCreator::SessionCreator(uint recursion): SessionLoader(nullptr, recursion)
{ {
} }
@@ -108,7 +108,7 @@ void SessionCreator::loadConfig(XMLElement *viewsNode)
} }
} }
SessionLoader::SessionLoader(Session *session): Visitor(), session_(session) SessionLoader::SessionLoader(Session *session, uint recursion): Visitor(), session_(session), recursion_(recursion)
{ {
} }
@@ -117,6 +117,11 @@ void SessionLoader::load(XMLElement *sessionNode)
{ {
sources_id_.clear(); sources_id_.clear();
if (recursion_ > MAX_SESSION_LEVEL) {
Log::Warning("Recursive or imbricated sessions detected! Interrupting loading after %d iterations.\n", MAX_SESSION_LEVEL);
return;
}
if (sessionNode != nullptr && session_ != nullptr) { if (sessionNode != nullptr && session_ != nullptr) {
XMLElement* sourceNode = sessionNode->FirstChildElement("Source"); XMLElement* sourceNode = sessionNode->FirstChildElement("Source");
@@ -534,11 +539,11 @@ void SessionLoader::visit (SessionFileSource& s)
XMLElement* pathNode = xmlCurrent_->FirstChildElement("path"); XMLElement* pathNode = xmlCurrent_->FirstChildElement("path");
if (pathNode) { if (pathNode) {
std::string path = std::string ( pathNode->GetText() ); std::string path = std::string ( pathNode->GetText() );
// load only new files // load only new files
if ( path != s.path() ) if ( path != s.path() )
s.load(path); s.load(path, recursion_ + 1);
} }
} }
void SessionLoader::visit (SessionGroupSource& s) void SessionLoader::visit (SessionGroupSource& s)
@@ -550,10 +555,9 @@ void SessionLoader::visit (SessionGroupSource& s)
XMLElement* sessionGroupNode = xmlCurrent_->FirstChildElement("Session"); XMLElement* sessionGroupNode = xmlCurrent_->FirstChildElement("Session");
if (sessionGroupNode) { if (sessionGroupNode) {
// load session inside group // load session inside group
SessionLoader grouploader( s.session() ); SessionLoader grouploader( s.session(), recursion_ + 1 );
grouploader.load( sessionGroupNode ); grouploader.load( sessionGroupNode );
} }
} }
void SessionLoader::visit (RenderSource& s) void SessionLoader::visit (RenderSource& s)

View File

@@ -13,7 +13,7 @@ class SessionLoader : public Visitor {
public: public:
SessionLoader(Session *session); SessionLoader(Session *session, uint recursion = 0);
inline Session *session() const { return session_; } inline Session *session() const { return session_; }
void load(tinyxml2::XMLElement *sessionNode); void load(tinyxml2::XMLElement *sessionNode);
@@ -58,6 +58,7 @@ protected:
tinyxml2::XMLElement *xmlCurrent_; tinyxml2::XMLElement *xmlCurrent_;
Session *session_; Session *session_;
std::list<uint64_t> sources_id_; std::list<uint64_t> sources_id_;
uint recursion_;
static void XMLToNode(tinyxml2::XMLElement *xml, Node &n); static void XMLToNode(tinyxml2::XMLElement *xml, Node &n);
}; };
@@ -69,7 +70,7 @@ class SessionCreator : public SessionLoader {
void loadConfig(tinyxml2::XMLElement *viewsNode); void loadConfig(tinyxml2::XMLElement *viewsNode);
public: public:
SessionCreator(); SessionCreator(uint recursion = 0);
void load(const std::string& filename); void load(const std::string& filename);

View File

@@ -128,7 +128,7 @@ SessionFileSource::SessionFileSource() : SessionSource(), path_("")
wait_for_sources_ = false; wait_for_sources_ = false;
} }
void SessionFileSource::load(const std::string &p) void SessionFileSource::load(const std::string &p, uint recursion)
{ {
path_ = p; path_ = p;
@@ -142,10 +142,11 @@ void SessionFileSource::load(const std::string &p)
if ( path_.empty() ) { if ( path_.empty() ) {
// empty session // empty session
session_ = new Session; session_ = new Session;
Log::Warning("Empty Session filename provided.");
} }
else { else {
// launch a thread to load the session file // launch a thread to load the session file
sessionLoader_ = std::async(std::launch::async, Session::load, path_); sessionLoader_ = std::async(std::launch::async, Session::load, path_, recursion);
Log::Notify("Opening %s", p.c_str()); Log::Notify("Opening %s", p.c_str());
} }
} }

View File

@@ -35,7 +35,7 @@ public:
void accept (Visitor& v) override; void accept (Visitor& v) override;
// SessionFile Source specific interface // SessionFile Source specific interface
void load(const std::string &p = ""); void load(const std::string &p = "", uint recursion = 0);
inline std::string path() const { return path_; } inline std::string path() const { return path_; }
glm::ivec2 icon() const override { return glm::ivec2(2, 16); } glm::ivec2 icon() const override { return glm::ivec2(2, 16); }

View File

@@ -433,9 +433,10 @@ void SessionVisitor::visit (SessionGroupSource& s)
XMLElement *rootgroup = xmlDoc_->NewElement("Session"); XMLElement *rootgroup = xmlDoc_->NewElement("Session");
xmlCurrent_->InsertEndChild(rootgroup); xmlCurrent_->InsertEndChild(rootgroup);
setRoot(rootgroup); for (auto iter = se->begin(); iter != se->end(); iter++){
for (auto iter = se->begin(); iter != se->end(); iter++, setRoot(rootgroup) ) setRoot(rootgroup);
(*iter)->accept(*this); (*iter)->accept(*this);
}
} }

View File

@@ -9,6 +9,7 @@
#define XML_VERSION_MAJOR 0 #define XML_VERSION_MAJOR 0
#define XML_VERSION_MINOR 2 #define XML_VERSION_MINOR 2
#define MAX_RECENT_HISTORY 20 #define MAX_RECENT_HISTORY 20
#define MAX_SESSION_LEVEL 3
#define MINI(a, b) (((a) < (b)) ? (a) : (b)) #define MINI(a, b) (((a) < (b)) ? (a) : (b))
#define MAXI(a, b) (((a) > (b)) ? (a) : (b)) #define MAXI(a, b) (((a) > (b)) ? (a) : (b))