summaryrefslogtreecommitdiffhomepage
path: root/src
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 /src
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.
Diffstat (limited to 'src')
-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();