8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 19:23:03 +01:00

Postfix for #7418: Reliability of plugin manager; better error handling during plugin registration, removed limit on length of registration name

This commit is contained in:
AlexPeshkoff 2022-12-12 19:45:51 +03:00
parent 801bac7da0
commit 7ccbceead6

View File

@ -30,6 +30,7 @@
#include "../yvalve/why_proto.h"
#include "../common/os/path_utils.h"
#include "../common/os/fbsyslog.h"
#include "../common/StatusArg.h"
#include "../common/isc_proto.h"
#include "../common/classes/fb_string.h"
@ -42,6 +43,8 @@
#include "../common/classes/GenericMap.h"
#include "../common/db_alias.h"
#include "../common/dllinst.h"
#include "../common/file_params.h"
#include "../common/status.h"
#include "../yvalve/config/os/config_root.h"
@ -246,8 +249,7 @@ namespace
IConfig* findPluginConfig(ConfigFile* pluginLoaderConfig, const PathName& confName)
{
LocalStatus ls;
CheckStatusWrapper s(&ls);
FbLocalStatus ls;
if (pluginLoaderConfig)
{
@ -266,40 +268,39 @@ namespace
}
}
IConfig* rc = PluginManagerInterfacePtr()->getConfig(&s, confName.nullStr());
check(&s);
IConfig* rc = PluginManagerInterfacePtr()->getConfig(&ls, confName.nullStr());
check(&ls);
return rc;
}
// Plugins registered when loading plugin module.
// This is POD object - no dtor, only simple data types inside.
struct RegisteredPlugin
{
RegisteredPlugin(IPluginFactory* f, const char* nm, unsigned int t)
: factory(f), type(t)
: factory(f), name(nm), type(t)
{ }
RegisteredPlugin(MemoryPool& p, IPluginFactory* f, const char* nm, unsigned int t)
: factory(f), name(p), type(t)
{
if (nm)
{
if (strlen(nm) >= sizeof(name))
{
fatal_exception::raiseFmt("Size of plugin registration name should not exceed %d bytes",
sizeof(name) - 1);
}
strcpy(name, nm);
}
else
name[0] = 0;
name = nm;
}
RegisteredPlugin()
: factory(NULL), type(0)
{
name[0] = 0;
}
: factory(NULL), name(), type(0)
{ }
RegisteredPlugin(MemoryPool& p)
: factory(NULL), name(p), type(0)
{ }
RegisteredPlugin(MemoryPool& p, const RegisteredPlugin& from)
: factory(from.factory), name(p, from.name), type(from.type)
{ }
IPluginFactory* factory;
char name[32];
PathName name;
unsigned int type;
};
@ -410,7 +411,7 @@ namespace
PathName name;
Firebird::AutoPtr<ModuleLoader::Module> module;
Firebird::IPluginModule* cleanup;
HalfStaticArray<RegisteredPlugin, 2> regPlugins;
ObjectsArray<RegisteredPlugin> regPlugins;
PluginModule* next;
PluginModule** prev;
};
@ -589,9 +590,8 @@ namespace
fprintf(stderr, "~FactoryParameter places configuredPlugin %s in unload query for %d seconds\n",
configuredPlugin->getPlugName(), configuredPlugin->getReleaseDelay() / 1000000);
#endif
LocalStatus ls;
CheckStatusWrapper s(&ls);
TimerInterfacePtr()->start(&s, configuredPlugin, configuredPlugin->getReleaseDelay());
FbLocalStatus ls;
TimerInterfacePtr()->start(&ls, configuredPlugin, configuredPlugin->getReleaseDelay());
// errors are ignored here - configuredPlugin will be released at once
}
@ -604,18 +604,17 @@ namespace
FactoryParameter* par = FB_NEW FactoryParameter(this, firebirdConf);
par->addRef();
LocalStatus ls;
CheckStatusWrapper s(&ls);
IPluginBase* plugin = module->getPlugin(regPlugin).factory->createPlugin(&s, par);
FbLocalStatus ls;
IPluginBase* plugin = module->getPlugin(regPlugin).factory->createPlugin(&ls, par);
if (!(s.getState() & Firebird::IStatus::STATE_ERRORS))
if (!(ls->getState() & Firebird::IStatus::STATE_ERRORS))
{
plugin->setOwner(par);
return plugin;
}
par->release();
check(&s);
check(&ls);
return NULL;
}
@ -826,8 +825,7 @@ namespace
{
namesList.assign(pnamesList);
namesList.alltrim(" \t");
Firebird::LocalStatus s;
Firebird::CheckStatusWrapper statusWrapper(&s);
FbLocalStatus statusWrapper;
next(&statusWrapper);
check(&statusWrapper);
}
@ -1024,26 +1022,55 @@ PluginManager::PluginManager()
void PluginManager::registerPluginFactory(unsigned int interfaceType, const char* defaultName, IPluginFactory* factory)
{
MutexLockGuard g(plugins->mutex, FB_FUNCTION);
if (!current)
try
{
// not good time to call this function - ignore request
gds__log("Unexpected call to register plugin %s, type %d - ignored\n", defaultName, interfaceType);
return;
MutexLockGuard g(plugins->mutex, FB_FUNCTION);
if (!current)
{
// not good time to call this function - ignore request
gds__log("Unexpected call to register plugin %s, type %d - ignored\n", defaultName, interfaceType);
return;
}
unsigned int r = current->addPlugin(RegisteredPlugin(factory, defaultName, interfaceType));
if (current == builtin)
{
PathName plugConfigFile = fb_utils::getPrefix(IConfigManager::DIR_PLUGINS, defaultName);
changeExtension(plugConfigFile, "conf");
ConfiguredPlugin* p = FB_NEW ConfiguredPlugin(RefPtr<PluginModule>(builtin), r,
findInPluginsConf("Plugin", defaultName), plugConfigFile, defaultName);
p->addRef(); // Will never be unloaded
plugins->put(MapKey(interfaceType, defaultName), p);
}
}
unsigned int r = current->addPlugin(RegisteredPlugin(factory, defaultName, interfaceType));
if (current == builtin)
catch(const Exception& ex)
{
PathName plugConfigFile = fb_utils::getPrefix(IConfigManager::DIR_PLUGINS, defaultName);
changeExtension(plugConfigFile, "conf");
// looks like something gone seriously wrong - therefore add more error handling here
try
{
FbLocalStatus ls;
ex.stuffException(&ls);
char text[256];
UtilInterfacePtr()->formatStatus(text, sizeof(text), &ls);
Syslog::Record(Syslog::Error, text);
ConfiguredPlugin* p = FB_NEW ConfiguredPlugin(RefPtr<PluginModule>(builtin), r,
findInPluginsConf("Plugin", defaultName), plugConfigFile, defaultName);
p->addRef(); // Will never be unloaded
plugins->put(MapKey(interfaceType, defaultName), p);
iscLogException("Plugin registration error", ex);
}
catch(const BadAlloc&)
{
Syslog::Record(Syslog::Error, "Plugin registration error - out of memory");
}
catch(...)
{
Syslog::Record(Syslog::Error, "Double fault during plugin registration");
}
#ifdef DEV_BUILD
abort();
#endif
}
}