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()) {
// Start async thread for loading the session
// 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
set( Session::load(filename) );
@@ -986,7 +986,7 @@ void Mixer::import(const std::string& filename)
if (sessionImporters_.empty()) {
// Start async thread for loading the session
// 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
merge( Session::load(filename) );

View File

@@ -1,6 +1,11 @@
#include <algorithm>
#include "SearchVisitor.h"
#include "Scene.h"
#include "MediaSource.h"
#include "Session.h"
#include "SessionSource.h"
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)
{
@@ -55,13 +59,8 @@ void SearchFileVisitor::visit(Node &n)
void SearchFileVisitor::visit(Group &n)
{
if (found_)
return;
for (NodeSet::iterator node = n.begin(); node != n.end(); node++) {
(*node)->accept(*this);
if (found_)
break;
}
}
@@ -81,10 +80,29 @@ void SearchFileVisitor::visit(Scene &n)
void SearchFileVisitor::visit (MediaSource& s)
{
filenames_.push_back( s.path() );
}
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
#define SEARCHVISITOR_H
#include <list>
#include <string>
#include "Visitor.h"
class Session;
class SearchVisitor: public Visitor
{
Node *node_;
@@ -15,33 +18,35 @@ public:
inline Node *node() const { return found_ ? node_ : nullptr; }
// Elements of Scene
void visit(Scene& n) override;
void visit(Node& n) override;
void visit(Primitive&) override {}
void visit(Group& n) override;
void visit(Switch& n) override;
void visit (Scene& n) override;
void visit (Node& n) override;
void visit (Primitive&) override {}
void visit (Group& n) override;
void visit (Switch& n) override;
};
class SearchFileVisitor: public Visitor
{
std::string filename_;
bool found_;
std::list<std::string> filenames_;
public:
SearchFileVisitor(std::string filename);
inline bool found() const { return found_; }
SearchFileVisitor();
inline std::list<std::string> filenames() const { return filenames_; }
// Elements of Scene
void visit(Scene& n) override;
void visit(Node& n) override;
void visit(Primitive&) override {}
void visit(Group& n) override;
void visit(Switch& n) override;
void visit (Scene& n) override;
void visit (Node& n) override;
void visit (Primitive&) override {}
void visit (Group& n) override;
void visit (Switch& n) override;
// Sources
void visit (MediaSource& 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

View File

@@ -4,7 +4,6 @@
#include "Settings.h"
#include "FrameBuffer.h"
#include "Session.h"
#include "GarbageVisitor.h"
#include "FrameGrabber.h"
#include "SessionCreator.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);
return creator.session();

View File

@@ -14,7 +14,7 @@ public:
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
SourceList::iterator addSource (Source *s);

View File

@@ -52,7 +52,7 @@ std::string SessionCreator::info(const std::string& filename)
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();
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) {
XMLElement* sourceNode = sessionNode->FirstChildElement("Source");
@@ -534,11 +539,11 @@ void SessionLoader::visit (SessionFileSource& s)
XMLElement* pathNode = xmlCurrent_->FirstChildElement("path");
if (pathNode) {
std::string path = std::string ( pathNode->GetText() );
// load only new files
if ( path != s.path() )
s.load(path);
s.load(path, recursion_ + 1);
}
}
void SessionLoader::visit (SessionGroupSource& s)
@@ -550,10 +555,9 @@ void SessionLoader::visit (SessionGroupSource& s)
XMLElement* sessionGroupNode = xmlCurrent_->FirstChildElement("Session");
if (sessionGroupNode) {
// load session inside group
SessionLoader grouploader( s.session() );
SessionLoader grouploader( s.session(), recursion_ + 1 );
grouploader.load( sessionGroupNode );
}
}
void SessionLoader::visit (RenderSource& s)

View File

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

View File

@@ -128,7 +128,7 @@ SessionFileSource::SessionFileSource() : SessionSource(), path_("")
wait_for_sources_ = false;
}
void SessionFileSource::load(const std::string &p)
void SessionFileSource::load(const std::string &p, uint recursion)
{
path_ = p;
@@ -142,10 +142,11 @@ void SessionFileSource::load(const std::string &p)
if ( path_.empty() ) {
// empty session
session_ = new Session;
Log::Warning("Empty Session filename provided.");
}
else {
// 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());
}
}

View File

@@ -35,7 +35,7 @@ public:
void accept (Visitor& v) override;
// 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_; }
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");
xmlCurrent_->InsertEndChild(rootgroup);
for (auto iter = se->begin(); iter != se->end(); iter++){
setRoot(rootgroup);
for (auto iter = se->begin(); iter != se->end(); iter++, setRoot(rootgroup) )
(*iter)->accept(*this);
}
}

View File

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