Add a plugin_globals vector to aid in safety checks for plugins that require globals

This allows "using df::global::foo" to be replaced by "REQUIRE_GLOBAL(foo)",
and DFHack will refuse to load the plugin if df::global::foo is NULL
develop
lethosor 2014-12-02 21:29:13 -05:00
parent 760acf017b
commit e206c242c6
3 changed files with 35 additions and 7 deletions

@ -30,6 +30,7 @@ distribution.
#include "RemoteServer.h" #include "RemoteServer.h"
#include "Console.h" #include "Console.h"
#include "Types.h" #include "Types.h"
#include "VersionInfo.h"
#include "DataDefs.h" #include "DataDefs.h"
#include "MiscUtils.h" #include "MiscUtils.h"
@ -167,6 +168,7 @@ Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _f
} }
plugin_lib = 0; plugin_lib = 0;
plugin_init = 0; plugin_init = 0;
plugin_globals = 0;
plugin_shutdown = 0; plugin_shutdown = 0;
plugin_status = 0; plugin_status = 0;
plugin_onupdate = 0; plugin_onupdate = 0;
@ -235,13 +237,32 @@ bool Plugin::load(color_ostream &con)
*plug_self = this; *plug_self = this;
RefAutolock lock(access); RefAutolock lock(access);
plugin_init = (command_result (*)(color_ostream &, std::vector <PluginCommand> &)) LookupPlugin(plug, "plugin_init"); plugin_init = (command_result (*)(color_ostream &, std::vector <PluginCommand> &)) LookupPlugin(plug, "plugin_init");
if(!plugin_init) std::vector<std::string>** plugin_globals_ptr = (std::vector<std::string>**) LookupPlugin(plug, "plugin_globals");
if(!plugin_init || !plugin_globals_ptr)
{ {
con.printerr("Plugin %s has no init function.\n", filename.c_str()); con.printerr("Plugin %s has no init function or globals vector.\n", filename.c_str());
ClosePlugin(plug); ClosePlugin(plug);
state = PS_BROKEN; state = PS_BROKEN;
return false; return false;
} }
plugin_globals = *plugin_globals_ptr;
if (plugin_globals->size())
{
std::vector<std::string> missing_globals;
for (auto it = plugin_globals->begin(); it != plugin_globals->end(); ++it)
{
if (!Core::getInstance().vinfo->getAddress(it->c_str()))
missing_globals.push_back(*it);
}
if (missing_globals.size())
{
con.printerr("Plugin %s is missing required globals: %s\n",
filename.c_str(), join_strings(", ", missing_globals).c_str());
ClosePlugin(plug);
state = PS_BROKEN;
return false;
}
}
plugin_status = (command_result (*)(color_ostream &, std::string &)) LookupPlugin(plug, "plugin_status"); plugin_status = (command_result (*)(color_ostream &, std::string &)) LookupPlugin(plug, "plugin_status");
plugin_onupdate = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_onupdate"); plugin_onupdate = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_onupdate");
plugin_shutdown = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_shutdown"); plugin_shutdown = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_shutdown");

@ -205,6 +205,7 @@ namespace DFHack
void reset_lua(); void reset_lua();
bool *plugin_is_enabled; bool *plugin_is_enabled;
std::vector<std::string>* plugin_globals;
command_result (*plugin_init)(color_ostream &, std::vector <PluginCommand> &); command_result (*plugin_init)(color_ostream &, std::vector <PluginCommand> &);
command_result (*plugin_status)(color_ostream &, std::string &); command_result (*plugin_status)(color_ostream &, std::string &);
command_result (*plugin_shutdown)(color_ostream &); command_result (*plugin_shutdown)(color_ostream &);
@ -264,7 +265,9 @@ namespace DFHack
#define DFHACK_PLUGIN(plugin_name) \ #define DFHACK_PLUGIN(plugin_name) \
DFhackDataExport const char * version = DFHACK_VERSION;\ DFhackDataExport const char * version = DFHACK_VERSION;\
DFhackDataExport const char * name = plugin_name;\ DFhackDataExport const char * name = plugin_name;\
DFhackDataExport Plugin *plugin_self = NULL; DFhackDataExport Plugin *plugin_self = NULL;\
std::vector<std::string> _plugin_globals;\
DFhackDataExport std::vector<std::string>* plugin_globals = &_plugin_globals;
#define DFHACK_PLUGIN_IS_ENABLED(varname) \ #define DFHACK_PLUGIN_IS_ENABLED(varname) \
DFhackDataExport bool plugin_is_enabled = false; \ DFhackDataExport bool plugin_is_enabled = false; \
@ -281,3 +284,8 @@ namespace DFHack
#define DFHACK_LUA_FUNCTION(name) { #name, df::wrap_function(name,true) } #define DFHACK_LUA_FUNCTION(name) { #name, df::wrap_function(name,true) }
#define DFHACK_LUA_EVENT(name) { #name, &name##_event } #define DFHACK_LUA_EVENT(name) { #name, &name##_event }
#define DFHACK_LUA_END { NULL, NULL } #define DFHACK_LUA_END { NULL, NULL }
#define REQUIRE_GLOBAL(global_name) \
using df::global::global_name; \
static int VARIABLE_IS_NOT_USED CONCAT_TOKENS(required_globals_, __LINE__) = \
(plugin_globals->push_back(#global_name), 0);

@ -41,13 +41,12 @@ using namespace DFHack;
using namespace MapExtras; using namespace MapExtras;
using namespace DFHack::Random; using namespace DFHack::Random;
using df::global::world; DFHACK_PLUGIN("3dveins");
using df::global::gametype; REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(gametype);
command_result cmd_3dveins(color_ostream &out, std::vector <std::string> & parameters); command_result cmd_3dveins(color_ostream &out, std::vector <std::string> & parameters);
DFHACK_PLUGIN("3dveins");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.push_back(PluginCommand( commands.push_back(PluginCommand(