From 55cc46e6cb848c52b068b8cce2e21f21dd3d147c Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Wed, 28 Dec 2011 16:15:52 +0100 Subject: [PATCH] server interface: perform API version check when before loading a plugin, we try to resolve a new symbol: if the symbol api_version can be resolved, it will return the value of sc_plugin_version, which will be incremented whenever binary compatibility changes. if the symbol is not present, we implicitly assume API version 1. Signed-off-by: Tim Blechmann --- include/plugin_interface/SC_InterfaceTable.h | 6 ++++- server/scsynth/SC_Lib_Cintf.cpp | 36 +++++++++++++++++++++------- server/supernova/sc/sc_ugen_factory.cpp | 13 +++++++++- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/include/plugin_interface/SC_InterfaceTable.h b/include/plugin_interface/SC_InterfaceTable.h index 311509210..f18350148 100644 --- a/include/plugin_interface/SC_InterfaceTable.h +++ b/include/plugin_interface/SC_InterfaceTable.h @@ -21,6 +21,8 @@ #ifndef _SC_SynthInterfaceTable_ #define _SC_SynthInterfaceTable_ +static const int sc_api_version = 1; + #include "SC_Types.h" #include "SC_SndBuf.h" #include "SC_Unit.h" @@ -227,7 +229,9 @@ typedef struct InterfaceTable InterfaceTable; #ifdef STATIC_PLUGINS #define PluginLoad(name) void name##_Load(InterfaceTable *inTable) #else - #define PluginLoad(name) C_LINKAGE SC_API_EXPORT void load(InterfaceTable *inTable) + #define PluginLoad(name) \ + C_LINKAGE SC_API_EXPORT int api_version(void) { return sc_api_version; } \ + C_LINKAGE SC_API_EXPORT void load(InterfaceTable *inTable) #endif #define scfft_create (*ft->fSCfftCreate) diff --git a/server/scsynth/SC_Lib_Cintf.cpp b/server/scsynth/SC_Lib_Cintf.cpp index 1afab13c6..1e57a363a 100644 --- a/server/scsynth/SC_Lib_Cintf.cpp +++ b/server/scsynth/SC_Lib_Cintf.cpp @@ -56,10 +56,6 @@ # define SC_PLUGIN_EXT ".scx" #endif -// Symbol of initialization routine when loading plugins -#ifndef SC_PLUGIN_LOAD_SYM -#define SC_PLUGIN_LOAD_SYM "load" -#endif #ifndef _WIN32 # include @@ -242,6 +238,20 @@ void initialize_library(const char *uGensPluginPath) #endif } +typedef int (*InfoFunction)(); + +bool checkAPIVersion(void * f, const char * filename) +{ + if (!f) + return true; + + InfoFunction fn = (InfoFunction)f; + if ((*fn)() == sc_api_version) + return true; + scprintf("*** ERROR: API Version Mismatch: %s\n", filename); + return false; +} + static bool PlugIn_Load(const char *filename) { #ifdef _WIN32 @@ -257,7 +267,13 @@ static bool PlugIn_Load(const char *filename) return false; } - void *ptr = (void *)GetProcAddress( hinstance, SC_PLUGIN_LOAD_SYM ); + void *apiVersionPtr = (void *)GetProcAddress( hinstance, "api_version" ); + if (!checkAPIVersion(apiVersionPtr, filename)) { + FreeLibrary(hinstance); + return false; + } + + void *ptr = (void *)GetProcAddress( hinstance, "load" ); if (!ptr) { char *s; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, @@ -286,11 +302,15 @@ static bool PlugIn_Load(const char *filename) return false; } - void *ptr; + void *apiVersionPtr = (void *)dlsym( handle, "api_version" ); + if (!checkAPIVersion(apiVersionPtr, filename)) { + dlclose(handle); + return false; + } - ptr = dlsym(handle, SC_PLUGIN_LOAD_SYM); + void *ptr = dlsym(handle, "load"); if (!ptr) { - scprintf("*** ERROR: dlsym %s err '%s'\n", SC_PLUGIN_LOAD_SYM, dlerror()); + scprintf("*** ERROR: dlsym load err '%s'\n", dlerror()); dlclose(handle); return false; } diff --git a/server/supernova/sc/sc_ugen_factory.cpp b/server/supernova/sc/sc_ugen_factory.cpp index 182be377a..b379b6492 100644 --- a/server/supernova/sc/sc_ugen_factory.cpp +++ b/server/supernova/sc/sc_ugen_factory.cpp @@ -231,14 +231,25 @@ void sc_ugen_factory::load_plugin_folder (boost::filesystem::path const & path) } } - #ifdef DLOPEN void sc_ugen_factory::load_plugin ( boost::filesystem::path const & path ) { + using namespace std; void * handle = dlopen(path.string().c_str(), RTLD_NOW | RTLD_LOCAL); if (handle == NULL) return; + typedef int (*info_function)(); + + info_function api_version = reinterpret_cast(dlsym(handle, "api_version")); + if (api_version) { + if ((*api_version)() != sc_api_version) { + cerr << "API Version Mismatch: " << path << endl; + dlclose(handle); + return; + } + } + void * load_symbol = dlsym(handle, "load"); if (!load_symbol) { dlclose(handle); -- 2.11.4.GIT