1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-10 22:31:40 +02:00

Fix possible leak due to usage of raw pointers in filesystem

This commit is contained in:
Ivan Savenko
2025-04-27 19:55:16 +03:00
parent 3547635c05
commit 4bafab9ad4
10 changed files with 65 additions and 64 deletions

View File

@@ -157,11 +157,12 @@ std::vector<const ISimpleResourceLoader *> CFilesystemList::getResourcesWithName
return ret; return ret;
} }
void CFilesystemList::addLoader(ISimpleResourceLoader * loader, bool writeable) void CFilesystemList::addLoader(std::unique_ptr<ISimpleResourceLoader> loader, bool writeable)
{ {
loaders.push_back(std::unique_ptr<ISimpleResourceLoader>(loader));
if (writeable) if (writeable)
writeableLoaders.insert(loader); writeableLoaders.insert(loader.get());
loaders.push_back(std::move(loader));
} }
bool CFilesystemList::removeLoader(ISimpleResourceLoader * loader) bool CFilesystemList::removeLoader(ISimpleResourceLoader * loader)

View File

@@ -85,8 +85,8 @@ public:
* @param loader The simple resource loader object to add * @param loader The simple resource loader object to add
* @param writeable - resource shall be treated as writeable * @param writeable - resource shall be treated as writeable
*/ */
void addLoader(ISimpleResourceLoader * loader, bool writeable); void addLoader(std::unique_ptr<ISimpleResourceLoader> loader, bool writeable);
/** /**
* Removes loader from the loader list * Removes loader from the loader list
* Take care about memory deallocation * Take care about memory deallocation

View File

@@ -97,7 +97,7 @@ CCompressedStream::CCompressedStream(std::unique_ptr<CInputStream> stream, bool
assert(gzipStream); assert(gzipStream);
// Allocate inflate state // Allocate inflate state
inflateState = new z_stream(); inflateState = std::make_unique<z_stream>();
inflateState->zalloc = Z_NULL; inflateState->zalloc = Z_NULL;
inflateState->zfree = Z_NULL; inflateState->zfree = Z_NULL;
inflateState->opaque = Z_NULL; inflateState->opaque = Z_NULL;
@@ -108,15 +108,14 @@ CCompressedStream::CCompressedStream(std::unique_ptr<CInputStream> stream, bool
if (gzip) if (gzip)
wbits += 16; wbits += 16;
int ret = inflateInit2(inflateState, wbits); int ret = inflateInit2(inflateState.get(), wbits);
if (ret != Z_OK) if (ret != Z_OK)
throw std::runtime_error("Failed to initialize inflate!\n"); throw std::runtime_error("Failed to initialize inflate!\n");
} }
CCompressedStream::~CCompressedStream() CCompressedStream::~CCompressedStream()
{ {
inflateEnd(inflateState); inflateEnd(inflateState.get());
vstd::clear_pointer(inflateState);
} }
si64 CCompressedStream::readMore(ui8 *data, si64 size) si64 CCompressedStream::readMore(ui8 *data, si64 size)
@@ -149,7 +148,7 @@ si64 CCompressedStream::readMore(ui8 *data, si64 size)
inflateState->next_in = compressedBuffer.data(); inflateState->next_in = compressedBuffer.data();
} }
int ret = inflate(inflateState, Z_NO_FLUSH); int ret = inflate(inflateState.get(), Z_NO_FLUSH);
if (inflateState->avail_in == 0 && gzipStream == nullptr) if (inflateState->avail_in == 0 && gzipStream == nullptr)
fileEnded = true; fileEnded = true;
@@ -179,8 +178,8 @@ si64 CCompressedStream::readMore(ui8 *data, si64 size)
// Clean up and return // Clean up and return
if (fileEnded) if (fileEnded)
{ {
inflateEnd(inflateState); inflateEnd(inflateState.get());
vstd::clear_pointer(inflateState); inflateState.reset();
} }
return decompressed; return decompressed;
} }
@@ -190,7 +189,7 @@ bool CCompressedStream::getNextBlock()
if (!inflateState) if (!inflateState)
return false; return false;
if (inflateReset(inflateState) < 0) if (inflateReset(inflateState.get()) < 0)
return false; return false;
reset(); reset();

View File

@@ -132,7 +132,7 @@ private:
std::vector<ui8> compressedBuffer; std::vector<ui8> compressedBuffer;
/** struct with current zlib inflate state */ /** struct with current zlib inflate state */
z_stream_s * inflateState; std::unique_ptr<z_stream_s> inflateState;
enum EState enum EState
{ {

View File

@@ -28,7 +28,7 @@ std::map<std::string, ISimpleResourceLoader*> CResourceHandler::knownLoaders = s
CResourceHandler CResourceHandler::globalResourceHandler; CResourceHandler CResourceHandler::globalResourceHandler;
CFilesystemGenerator::CFilesystemGenerator(std::string prefix, bool extractArchives): CFilesystemGenerator::CFilesystemGenerator(std::string prefix, bool extractArchives):
filesystem(new CFilesystemList()), filesystem(std::make_unique<CFilesystemList>()),
prefix(std::move(prefix)), prefix(std::move(prefix)),
extractArchives(extractArchives) extractArchives(extractArchives)
{ {
@@ -72,9 +72,9 @@ void CFilesystemGenerator::loadConfig(const JsonNode & config)
} }
} }
CFilesystemList * CFilesystemGenerator::getFilesystem() std::unique_ptr<CFilesystemList> CFilesystemGenerator::acquireFilesystem()
{ {
return filesystem; return std::move(filesystem);
} }
void CFilesystemGenerator::loadDirectory(const std::string &mountPoint, const JsonNode & config) void CFilesystemGenerator::loadDirectory(const std::string &mountPoint, const JsonNode & config)
@@ -89,7 +89,7 @@ void CFilesystemGenerator::loadDirectory(const std::string &mountPoint, const Js
for(auto & loader : CResourceHandler::get("initial")->getResourcesWithName(resID)) for(auto & loader : CResourceHandler::get("initial")->getResourcesWithName(resID))
{ {
auto filename = loader->getResourceName(resID); auto filename = loader->getResourceName(resID);
filesystem->addLoader(new CFilesystemLoader(mountPoint, *filename, depth), false); filesystem->addLoader(std::make_unique<CFilesystemLoader>(mountPoint, *filename, depth), false);
} }
} }
@@ -98,7 +98,7 @@ void CFilesystemGenerator::loadZipArchive(const std::string &mountPoint, const J
std::string URI = prefix + config["path"].String(); std::string URI = prefix + config["path"].String();
auto filename = CResourceHandler::get("initial")->getResourceName(ResourcePath(URI, EResType::ARCHIVE_ZIP)); auto filename = CResourceHandler::get("initial")->getResourceName(ResourcePath(URI, EResType::ARCHIVE_ZIP));
if (filename) if (filename)
filesystem->addLoader(new CZipLoader(mountPoint, *filename), false); filesystem->addLoader(std::make_unique<CZipLoader>(mountPoint, *filename), false);
} }
template<EResType archiveType> template<EResType archiveType>
@@ -107,7 +107,7 @@ void CFilesystemGenerator::loadArchive(const std::string &mountPoint, const Json
std::string URI = prefix + config["path"].String(); std::string URI = prefix + config["path"].String();
auto filename = CResourceHandler::get("initial")->getResourceName(ResourcePath(URI, archiveType)); auto filename = CResourceHandler::get("initial")->getResourceName(ResourcePath(URI, archiveType));
if (filename) if (filename)
filesystem->addLoader(new CArchiveLoader(mountPoint, *filename, extractArchives), false); filesystem->addLoader(std::make_unique<CArchiveLoader>(mountPoint, *filename, extractArchives), false);
} }
void CFilesystemGenerator::loadJsonMap(const std::string &mountPoint, const JsonNode & config) void CFilesystemGenerator::loadJsonMap(const std::string &mountPoint, const JsonNode & config)
@@ -118,15 +118,15 @@ void CFilesystemGenerator::loadJsonMap(const std::string &mountPoint, const Json
{ {
auto configData = CResourceHandler::get("initial")->load(JsonPath::builtin(URI))->readAll(); auto configData = CResourceHandler::get("initial")->load(JsonPath::builtin(URI))->readAll();
const JsonNode configInitial(reinterpret_cast<std::byte *>(configData.first.get()), configData.second, URI); const JsonNode configInitial(reinterpret_cast<std::byte *>(configData.first.get()), configData.second, URI);
filesystem->addLoader(new CMappedFileLoader(mountPoint, configInitial), false); filesystem->addLoader(std::make_unique<CMappedFileLoader>(mountPoint, configInitial), false);
} }
} }
ISimpleResourceLoader * CResourceHandler::createInitial() std::unique_ptr<ISimpleResourceLoader> CResourceHandler::createInitial()
{ {
//temporary filesystem that will be used to initialize main one. //temporary filesystem that will be used to initialize main one.
//used to solve several case-sensivity issues like Mp3 vs MP3 //used to solve several case-sensivity issues like Mp3 vs MP3
auto * initialLoader = new CFilesystemList(); auto initialLoader = std::make_unique<CFilesystemList>();
//recurse only into specific directories //recurse only into specific directories
auto recurseInDir = [&](const std::string & URI, int depth) auto recurseInDir = [&](const std::string & URI, int depth)
@@ -138,8 +138,8 @@ ISimpleResourceLoader * CResourceHandler::createInitial()
auto filename = loader->getResourceName(ID); auto filename = loader->getResourceName(ID);
if (filename) if (filename)
{ {
auto * dir = new CFilesystemLoader(URI + '/', *filename, depth, true); auto dir = std::make_unique<CFilesystemLoader>(URI + '/', *filename, depth, true);
initialLoader->addLoader(dir, false); initialLoader->addLoader(std::move(dir), false);
} }
} }
}; };
@@ -147,9 +147,9 @@ ISimpleResourceLoader * CResourceHandler::createInitial()
for (auto & path : VCMIDirs::get().dataPaths()) for (auto & path : VCMIDirs::get().dataPaths())
{ {
if (boost::filesystem::is_directory(path)) // some of system-provided paths may not exist if (boost::filesystem::is_directory(path)) // some of system-provided paths may not exist
initialLoader->addLoader(new CFilesystemLoader("", path, 1, true), false); initialLoader->addLoader(std::make_unique<CFilesystemLoader>("", path, 1, true), false);
} }
initialLoader->addLoader(new CFilesystemLoader("", VCMIDirs::get().userDataPath(), 0, true), false); initialLoader->addLoader(std::make_unique<CFilesystemLoader>("", VCMIDirs::get().userDataPath(), 0, true), false);
recurseInDir("CONFIG", 0);// look for configs recurseInDir("CONFIG", 0);// look for configs
recurseInDir("DATA", 0); // look for archives recurseInDir("DATA", 0); // look for archives
@@ -178,18 +178,21 @@ void CResourceHandler::initialize()
if (globalResourceHandler.rootLoader) if (globalResourceHandler.rootLoader)
return; return;
auto savesLoader = std::make_unique<CFilesystemLoader>("SAVES/", VCMIDirs::get().userSavePath());
auto configLoader = std::make_unique<CFilesystemLoader>("CONFIG/", VCMIDirs::get().userConfigPath());
globalResourceHandler.rootLoader = std::make_unique<CFilesystemList>(); globalResourceHandler.rootLoader = std::make_unique<CFilesystemList>();
knownLoaders["root"] = globalResourceHandler.rootLoader.get(); knownLoaders["root"] = globalResourceHandler.rootLoader.get();
knownLoaders["saves"] = new CFilesystemLoader("SAVES/", VCMIDirs::get().userSavePath()); knownLoaders["saves"] = savesLoader.get();
knownLoaders["config"] = new CFilesystemLoader("CONFIG/", VCMIDirs::get().userConfigPath()); knownLoaders["config"] = configLoader.get();
auto * localFS = new CFilesystemList(); auto localFS = std::make_unique<CFilesystemList>();
localFS->addLoader(knownLoaders["saves"], true); localFS->addLoader(std::move(savesLoader), true);
localFS->addLoader(knownLoaders["config"], true); localFS->addLoader(std::move(configLoader), true);
addFilesystem("root", "initial", createInitial()); addFilesystem("root", "initial", createInitial());
addFilesystem("root", "data", new CFilesystemList()); addFilesystem("root", "data", std::make_unique<CFilesystemList>());
addFilesystem("root", "local", localFS); addFilesystem("root", "local", std::move(localFS));
} }
void CResourceHandler::destroy() void CResourceHandler::destroy()
@@ -218,26 +221,24 @@ void CResourceHandler::load(const std::string &fsConfigURI, bool extractArchives
addFilesystem("data", ModScope::scopeBuiltin(), createFileSystem("", fsConfig["filesystem"], extractArchives)); addFilesystem("data", ModScope::scopeBuiltin(), createFileSystem("", fsConfig["filesystem"], extractArchives));
} }
void CResourceHandler::addFilesystem(const std::string & parent, const std::string & identifier, ISimpleResourceLoader * loader) void CResourceHandler::addFilesystem(const std::string & parent, const std::string & identifier, std::unique_ptr<ISimpleResourceLoader> loader)
{ {
if(knownLoaders.count(identifier) != 0) if(knownLoaders.count(identifier) != 0)
{ {
logMod->error("[CRITICAL] Virtual filesystem %s already loaded!", identifier); logMod->error("[CRITICAL] Virtual filesystem %s already loaded!", identifier);
delete loader;
return; return;
} }
if(knownLoaders.count(parent) == 0) if(knownLoaders.count(parent) == 0)
{ {
logMod->error("[CRITICAL] Parent virtual filesystem %s for %s not found!", parent, identifier); logMod->error("[CRITICAL] Parent virtual filesystem %s for %s not found!", parent, identifier);
delete loader;
return; return;
} }
auto * list = dynamic_cast<CFilesystemList *>(knownLoaders.at(parent)); auto * list = dynamic_cast<CFilesystemList *>(knownLoaders.at(parent));
assert(list); assert(list);
list->addLoader(loader, false); knownLoaders[identifier] = loader.get();
knownLoaders[identifier] = loader; list->addLoader(std::move(loader), false);
} }
bool CResourceHandler::removeFilesystem(const std::string & parent, const std::string & identifier) bool CResourceHandler::removeFilesystem(const std::string & parent, const std::string & identifier)
@@ -255,11 +256,11 @@ bool CResourceHandler::removeFilesystem(const std::string & parent, const std::s
return true; return true;
} }
ISimpleResourceLoader * CResourceHandler::createFileSystem(const std::string & prefix, const JsonNode &fsConfig, bool extractArchives) std::unique_ptr<ISimpleResourceLoader> CResourceHandler::createFileSystem(const std::string & prefix, const JsonNode &fsConfig, bool extractArchives)
{ {
CFilesystemGenerator generator(prefix, extractArchives); CFilesystemGenerator generator(prefix, extractArchives);
generator.loadConfig(fsConfig); generator.loadConfig(fsConfig);
return generator.getFilesystem(); return generator.acquireFilesystem();
} }
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@@ -24,7 +24,7 @@ class DLL_LINKAGE CFilesystemGenerator
using TLoadFunctor = std::function<void(const std::string &, const JsonNode &)>; using TLoadFunctor = std::function<void(const std::string &, const JsonNode &)>;
using TLoadFunctorMap = std::map<std::string, TLoadFunctor>; using TLoadFunctorMap = std::map<std::string, TLoadFunctor>;
CFilesystemList * filesystem; std::unique_ptr<CFilesystemList> filesystem;
std::string prefix; std::string prefix;
template<EResType archiveType> template<EResType archiveType>
@@ -44,7 +44,7 @@ public:
void loadConfig(const JsonNode & config); void loadConfig(const JsonNode & config);
/// returns generated filesystem /// returns generated filesystem
CFilesystemList * getFilesystem(); std::unique_ptr<CFilesystemList> acquireFilesystem();
/** Specifies if Original H3 archives should be extracted to a separate folder **/ /** Specifies if Original H3 archives should be extracted to a separate folder **/
bool extractArchives; bool extractArchives;
@@ -61,7 +61,7 @@ class DLL_LINKAGE CResourceHandler
* @brief createInitial - creates instance of initial loader * @brief createInitial - creates instance of initial loader
* that contains data necessary to load main FS * that contains data necessary to load main FS
*/ */
static ISimpleResourceLoader * createInitial(); static std::unique_ptr<ISimpleResourceLoader> createInitial();
public: public:
/** /**
@@ -98,7 +98,7 @@ public:
* @param identifier name of this loader by which it can be retrieved later * @param identifier name of this loader by which it can be retrieved later
* @param loader resource loader to add * @param loader resource loader to add
*/ */
static void addFilesystem(const std::string & parent, const std::string & identifier, ISimpleResourceLoader * loader); static void addFilesystem(const std::string & parent, const std::string & identifier, std::unique_ptr<ISimpleResourceLoader> loader);
/** /**
* @brief removeFilesystem removes previously added filesystem from global resource holder * @brief removeFilesystem removes previously added filesystem from global resource holder
@@ -114,7 +114,7 @@ public:
* @param fsConfig - configuration to load * @param fsConfig - configuration to load
* @return generated filesystem that contains all config entries * @return generated filesystem that contains all config entries
*/ */
static ISimpleResourceLoader * createFileSystem(const std::string &prefix, const JsonNode & fsConfig, bool extractArchives = false); static std::unique_ptr<ISimpleResourceLoader> createFileSystem(const std::string &prefix, const JsonNode & fsConfig, bool extractArchives = false);
~CResourceHandler() = default; ~CResourceHandler() = default;
private: private:

View File

@@ -71,7 +71,7 @@ static std::string getModDirectory(const TModID & modName)
return "MODS/" + result; return "MODS/" + result;
} }
static ISimpleResourceLoader * genModFilesystem(const std::string & modName, const JsonNode & conf) static std::unique_ptr<ISimpleResourceLoader> genModFilesystem(const std::string & modName, const JsonNode & conf)
{ {
static const JsonNode defaultFS = genDefaultFS(); static const JsonNode defaultFS = genDefaultFS();
@@ -87,20 +87,20 @@ void CModHandler::loadModFilesystems()
const auto & activeMods = modManager->getActiveMods(); const auto & activeMods = modManager->getActiveMods();
std::map<TModID, ISimpleResourceLoader *> modFilesystems; std::map<TModID, std::unique_ptr<ISimpleResourceLoader>> modFilesystems;
for(const TModID & modName : activeMods) for(const TModID & modName : activeMods)
modFilesystems[modName] = genModFilesystem(modName, getModInfo(modName).getFilesystemConfig()); modFilesystems[modName] = genModFilesystem(modName, getModInfo(modName).getFilesystemConfig());
for(const TModID & modName : activeMods)
if (modName != "core") // virtual mod 'core' has no filesystem on its own - shared with base install
CResourceHandler::addFilesystem("data", modName, modFilesystems[modName]);
if (settings["mods"]["validation"].String() == "full") if (settings["mods"]["validation"].String() == "full")
checkModFilesystemsConflicts(modFilesystems); checkModFilesystemsConflicts(modFilesystems);
for(const TModID & modName : activeMods)
if (modName != "core") // virtual mod 'core' has no filesystem on its own - shared with base install
CResourceHandler::addFilesystem("data", modName, std::move(modFilesystems[modName]));
} }
void CModHandler::checkModFilesystemsConflicts(const std::map<TModID, ISimpleResourceLoader *> & modFilesystems) void CModHandler::checkModFilesystemsConflicts(const std::map<TModID, std::unique_ptr<ISimpleResourceLoader>> & modFilesystems)
{ {
for(const auto & [leftName, leftFilesystem] : modFilesystems) for(const auto & [leftName, leftFilesystem] : modFilesystems)
{ {

View File

@@ -27,7 +27,7 @@ class DLL_LINKAGE CModHandler final : boost::noncopyable
std::set<std::string> validationPassed; std::set<std::string> validationPassed;
void loadTranslation(const TModID & modName); void loadTranslation(const TModID & modName);
void checkModFilesystemsConflicts(const std::map<TModID, ISimpleResourceLoader *> & modFilesystems); void checkModFilesystemsConflicts(const std::map<TModID, std::unique_ptr<ISimpleResourceLoader>> & modFilesystems);
bool isModValidationNeeded(const ModDescription & mod) const; bool isModValidationNeeded(const ModDescription & mod) const;

View File

@@ -32,9 +32,9 @@ std::unique_ptr<CMap> Helper::openMapInternal(const QString & filenameSelect)
ResourcePath resId("MAPEDITOR/" + fname, EResType::MAP); ResourcePath resId("MAPEDITOR/" + fname, EResType::MAP);
//addFilesystem takes care about memory deallocation if case of failure, no memory leak here //addFilesystem takes care about memory deallocation if case of failure, no memory leak here
auto * mapEditorFilesystem = new CFilesystemLoader("MAPEDITOR/", fdir, 0); auto mapEditorFilesystem = std::make_unique<CFilesystemLoader>("MAPEDITOR/", fdir, 0);
CResourceHandler::removeFilesystem("local", "mapEditor"); CResourceHandler::removeFilesystem("local", "mapEditor");
CResourceHandler::addFilesystem("local", "mapEditor", mapEditorFilesystem); CResourceHandler::addFilesystem("local", "mapEditor", std::move(mapEditorFilesystem));
if(!CResourceHandler::get("mapEditor")->existsResource(resId)) if(!CResourceHandler::get("mapEditor")->existsResource(resId))
throw std::runtime_error("Cannot open map from this folder"); throw std::runtime_error("Cannot open map from this folder");
@@ -65,9 +65,9 @@ std::shared_ptr<CampaignState> Helper::openCampaignInternal(const QString & file
ResourcePath resId("MAPEDITOR/" + fname, EResType::CAMPAIGN); ResourcePath resId("MAPEDITOR/" + fname, EResType::CAMPAIGN);
//addFilesystem takes care about memory deallocation if case of failure, no memory leak here //addFilesystem takes care about memory deallocation if case of failure, no memory leak here
auto * mapEditorFilesystem = new CFilesystemLoader("MAPEDITOR/", fdir, 0); auto mapEditorFilesystem = std::make_unique<CFilesystemLoader>("MAPEDITOR/", fdir, 0);
CResourceHandler::removeFilesystem("local", "mapEditor"); CResourceHandler::removeFilesystem("local", "mapEditor");
CResourceHandler::addFilesystem("local", "mapEditor", mapEditorFilesystem); CResourceHandler::addFilesystem("local", "mapEditor", std::move(mapEditorFilesystem));
if(!CResourceHandler::get("mapEditor")->existsResource(resId)) if(!CResourceHandler::get("mapEditor")->existsResource(resId))
throw std::runtime_error("Cannot open campaign from this folder"); throw std::runtime_error("Cannot open campaign from this folder");

View File

@@ -32,14 +32,14 @@ void CVcmiTestConfig::SetUp()
auto path = boost::filesystem::current_path(); auto path = boost::filesystem::current_path();
path+= "/" + TEST_DATA_DIR; path+= "/" + TEST_DATA_DIR;
if(boost::filesystem::exists(path)){ if(boost::filesystem::exists(path)){
auto loader = new CFilesystemLoader("test/", TEST_DATA_DIR); auto loader = std::make_unique<CFilesystemLoader>("test/", TEST_DATA_DIR);
dynamic_cast<CFilesystemList*>(CResourceHandler::get("core"))->addLoader(loader, false); dynamic_cast<CFilesystemList*>(CResourceHandler::get("core"))->addLoader(std::move(loader), false);
loader = new CFilesystemLoader("scripts/test/erm/", TEST_DATA_DIR+"erm/"); loader = std::make_unique<CFilesystemLoader>("scripts/test/erm/", TEST_DATA_DIR+"erm/");
dynamic_cast<CFilesystemList*>(CResourceHandler::get("core"))->addLoader(loader, false); dynamic_cast<CFilesystemList*>(CResourceHandler::get("core"))->addLoader(std::move(loader), false);
loader = new CFilesystemLoader("scripts/test/lua/", TEST_DATA_DIR+"lua/"); loader = std::make_unique<CFilesystemLoader>("scripts/test/lua/", TEST_DATA_DIR+"lua/");
dynamic_cast<CFilesystemList*>(CResourceHandler::get("core"))->addLoader(loader, false); dynamic_cast<CFilesystemList*>(CResourceHandler::get("core"))->addLoader(std::move(loader), false);
} }
} }