Extend plugin infrastructure to catch Bro version mismatches at link

time.

People keep running into the problem that they upgrade Bro but forget
to recompile their plugins--which can lead to crashes. While the
plugins' API version was supposed to catch this, it's not reliable as
that check may come too late. This change takes a different tack: We
compile a C function into the Bro binary that has Bro's version number
encoded into its name. A plugin can then reference that function. If
the Bro version changes, the function goes away and the plugin won't
load anymore.

I've integrated that function reference into the plugin skeleton code
so that new plugins get it automatically (unless explicitly removed).
I couldn't see a way to do it transparently for already existing
plugins unfortunately.

The version number used for the function name is slightly normalized
to skip any git revision postfixes (i.e., "2.5-xxx" is always treated
as "2.5-git") so that one doesn't need to recompile all plugins after
every master commit. That seems good enough, usually people run into
this when upgrading to a new release.

If one loads an old plugin into a new Bro, the error message looks
like this:

    $ bro -NN Demo::Foo
    fatal error in /home/robin/bro/master/scripts/base/init-bare.bro, line 1:
    cannot load plugin library /home/robin/tmp/p/build//lib/Demo-Foo.linux-x86_64.so:
    /home/robin/tmp/p/build//lib/Demo-Foo.linux-x86_64.so: undefined symbol: bro_version_2_5_git_debug

Not the prettiest, but better than a crash!

TODO: I'm still unsure if we should remove the plugin API version
altogetger now. This link-time check should catch everything the API
version does, except for master commits.
This commit is contained in:
Robin Sommer 2017-07-07 15:44:53 -07:00
parent ffa7480ce4
commit 8ae30d8aac
5 changed files with 42 additions and 1 deletions

View file

@ -40,12 +40,21 @@ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev.csh
"setenv PATH \"${CMAKE_CURRENT_BINARY_DIR}/src\":$PATH\n")
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" VERSION LIMIT_COUNT 1)
string(REPLACE "." " " version_numbers ${VERSION})
separate_arguments(version_numbers)
list(GET version_numbers 0 VERSION_MAJOR)
list(GET version_numbers 1 VERSION_MINOR)
set(VERSION_MAJ_MIN "${VERSION_MAJOR}.${VERSION_MINOR}")
set(VERSION_C_IDENT "${VERSION}")
string(REGEX REPLACE "-[0-9]*$" "_git" VERSION_C_IDENT "${VERSION_C_IDENT}")
string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" VERSION_C_IDENT "${VERSION_C_IDENT}")
if(${ENABLE_DEBUG})
set(VERSION_C_IDENT "${VERSION_C_IDENT}_debug")
endif()
########################################################################
## Dependency Configuration

@ -1 +1 @@
Subproject commit 43f4b90bbaf87dae1a1073e7bf13301e58866011
Subproject commit 7a38763d7a687dc8974bf6fd212dc75ba4a4b23c

View file

@ -229,3 +229,14 @@
#ifndef BRO_PLUGIN_INTERNAL_BUILD
#define BRO_PLUGIN_INTERNAL_BUILD @BRO_PLUGIN_INTERNAL_BUILD@
#endif
/* A C function that has the Bro version encoded into its name. */
#define BRO_VERSION_FUNCTION bro_version_@VERSION_C_IDENT@
#ifdef __cplusplus
extern "C" {
#endif
extern const char* BRO_VERSION_FUNCTION();
#ifdef __cplusplus
}
#endif

View file

@ -18,6 +18,8 @@
#define BRO_PLUGIN_API_VERSION 5
#endif
#define BRO_PLUGIN_BRO_VERSION BRO_VERSION_FUNCTION
class ODesc;
class Func;
class Event;
@ -93,6 +95,12 @@ public:
// strong hint.). The attribute seems generally available.
inline Configuration() __attribute__((always_inline));
/**
* One can assign BRO_PLUGIN_BRO_VERSION to this to catch
* version mismatches at link(!) time.
*/
const char* (*bro_version)();
private:
friend class Plugin;
int api_version; // Current BRO_PLUGIN_API_VERSION. Automatically set.
@ -103,6 +111,7 @@ inline Configuration::Configuration()
name = "";
description = "";
api_version = BRO_PLUGIN_API_VERSION;
bro_version = 0;
}
/**

View file

@ -1 +1,13 @@
#include "bro-config.h"
char version[] = "@VERSION@";
// A C function that has the current version built into its name.
// One can link a shared library against this to ensure that it won't
// load if the version of the main Bro binary differs compared to
// what the library was compiled against.
const char* BRO_VERSION_FUNCTION()
{
return "@VERSION_C_IDENT@";
}