summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMichael Smith <mikesmiffy128@gmail.com>2023-11-26 19:17:43 +0000
committerMichael Smith <mikesmiffy128@gmail.com>2023-11-26 21:35:57 +0000
commit852ff29088e08a9f1673a070f5ff151e23e393ec (patch)
treede57f2f0804ffb36aaddd24c37ed17afd598f9e5
parent6ed562049ec6df12d436a7d44cd3d705c523a01c (diff)
Fix CPlugin ABI on newer L4D2 versions
Thanks bill for spotting this issue. It was causing crashes on unload, which is obviously no good.
-rw-r--r--src/engineapi.h13
-rw-r--r--src/sst.c32
2 files changed, 35 insertions, 10 deletions
diff --git a/src/engineapi.h b/src/engineapi.h
index e95e282..44366f5 100644
--- a/src/engineapi.h
+++ b/src/engineapi.h
@@ -137,8 +137,7 @@ extern void *globalvars;
extern void *inputsystem, *vgui;
// XXX: not exactly engine *API* but not curently clear where else to put this
-struct CPlugin {
- char description[128];
+struct CPlugin_common {
bool paused;
void *theplugin; // our own "this" pointer (or whichever other plugin it is)
int ifacever;
@@ -146,6 +145,16 @@ struct CPlugin {
// because CServerPlugin::Load() erroneously shadows this field with a local
void *module;
};
+struct CPlugin {
+ char description[128];
+ union {
+ struct CPlugin_common v1;
+ struct {
+ char basename[128]; // WHY VALVE WHYYYYYYY!!!!
+ struct CPlugin_common common;
+ } v2;
+ };
+};
struct CServerPlugin /* : IServerPluginHelpers */ {
void **vtable;
struct CUtlVector plugins;
diff --git a/src/sst.c b/src/sst.c
index 6b03acf..7dd5839 100644
--- a/src/sst.c
+++ b/src/sst.c
@@ -348,6 +348,15 @@ static con_cmdcb orig_plugin_load_cb, orig_plugin_unload_cb;
static int ownidx; // XXX: super hacky way of getting this to do_unload()
+static bool ispluginv1(const struct CPlugin *plugin) {
+ // basename string is set with strncmp(), so if there's null bytes with more
+ // stuff after, we can't be looking at a v2 struct. and we expect null bytes
+ // in ifacever, since it's a small int value
+ return (plugin->v2.basename[0] == 0 || plugin->v2.basename[0] == 1) &&
+ plugin->v1.theplugin && plugin->v1.ifacever < 256 &&
+ plugin->v1.ifacever;
+}
+
static void hook_plugin_load_cb(const struct con_cmdargs *args) {
if (args->argc == 1) return;
if (!CHECK_AllowPluginLoading(true)) return;
@@ -359,10 +368,15 @@ static void hook_plugin_unload_cb(const struct con_cmdargs *args) {
if (!CHECK_AllowPluginLoading(false)) return;
int idx = atoi(args->argv[1]);
struct CPlugin **plugins = pluginhandler->plugins.m.mem;
- if (idx >= 0 && idx < pluginhandler->plugins.sz &&
- plugins[idx]->theplugin == &plugin_obj) {
- sst_userunloaded = true;
- ownidx = idx;
+ if (idx >= 0 && idx < pluginhandler->plugins.sz) {
+ const struct CPlugin *plugin = plugins[idx];
+ // XXX: *could* memoise the ispluginv1 call, but... meh. effort.
+ const struct CPlugin_common *common = ispluginv1(plugin) ?
+ &plugin->v1: &plugin->v2.common;
+ if (common->theplugin == &plugin_obj) {
+ sst_userunloaded = true;
+ ownidx = idx;
+ }
#ifdef __clang__
// thanks clang for forcing use of return here and THEN warning about it
#pragma clang diagnostic push
@@ -416,12 +430,14 @@ static void do_unload(void) {
cmd_plugin_unload->cb = orig_plugin_unload_cb;
#ifdef _WIN32 // this bit is only relevant in builds that predate linux support
struct CPlugin **plugins = pluginhandler->plugins.m.mem;
- // see comment in CPlugin above. setting this to the real handle right
+ // see comment in CPlugin struct. setting this to the real handle right
// before the engine tries to unload us allows it to actually do so. in
// newer branches this is redundant but doesn't do any harm so it's just
- // unconditional. NOTE: old engines ALSO just leak the handle and never
- // call Unload() if Load() fails; can't really do anything about that.
- plugins[ownidx]->module = ownhandle();
+ // unconditional (for v1). NOTE: old engines ALSO just leak the handle
+ // and never call Unload() if Load() fails; can't really do anything
+ // about that.
+ struct CPlugin *plugin = plugins[ownidx];
+ if (ispluginv1(plugin)) plugins[ownidx]->v1.module = ownhandle();
#endif
}
endfeatures();