Module events: Fail RM_SubscribeToServerEvent if event is too new (#9987)
We must fail RM_SubscribeToServerEvent in case a module, that was compiled with a new redismodule.h, tries to subscribe to an event that doesn't exist on an old redis-server
This commit is contained in:
parent
39feee8e3a
commit
5009b43dc6
31
src/module.c
31
src/module.c
@ -8923,6 +8923,28 @@ void ModuleForkDoneHandler(int exitcode, int bysignal) {
|
||||
* ## Server hooks implementation
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
/* This must be synced with REDISMODULE_EVENT_*
|
||||
* We use -1 (MAX_UINT64) to denote that this event doesn't have
|
||||
* a data structure associated with it. We use MAX_UINT64 on purpose,
|
||||
* in order to pass the check in RedisModule_SubscribeToServerEvent. */
|
||||
static uint64_t moduleEventVersions[] = {
|
||||
REDISMODULE_REPLICATIONINFO_VERSION, /* REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED */
|
||||
-1, /* REDISMODULE_EVENT_PERSISTENCE */
|
||||
REDISMODULE_FLUSHINFO_VERSION, /* REDISMODULE_EVENT_FLUSHDB */
|
||||
-1, /* REDISMODULE_EVENT_LOADING */
|
||||
REDISMODULE_CLIENTINFO_VERSION, /* REDISMODULE_EVENT_CLIENT_CHANGE */
|
||||
-1, /* REDISMODULE_EVENT_SHUTDOWN */
|
||||
-1, /* REDISMODULE_EVENT_REPLICA_CHANGE */
|
||||
-1, /* REDISMODULE_EVENT_MASTER_LINK_CHANGE */
|
||||
REDISMODULE_CRON_LOOP_VERSION, /* REDISMODULE_EVENT_CRON_LOOP */
|
||||
REDISMODULE_MODULE_CHANGE_VERSION, /* REDISMODULE_EVENT_MODULE_CHANGE */
|
||||
REDISMODULE_LOADING_PROGRESS_VERSION, /* REDISMODULE_EVENT_LOADING_PROGRESS */
|
||||
REDISMODULE_SWAPDBINFO_VERSION, /* REDISMODULE_EVENT_SWAPDB */
|
||||
-1, /* REDISMODULE_EVENT_REPL_BACKUP */
|
||||
-1, /* REDISMODULE_EVENT_FORK_CHILD */
|
||||
-1, /* REDISMODULE_EVENT_REPL_ASYNC_LOAD */
|
||||
};
|
||||
|
||||
/* Register to be notified, via a callback, when the specified server event
|
||||
* happens. The callback is called with the event as argument, and an additional
|
||||
* argument which is a void pointer and should be cased to a specific type
|
||||
@ -9180,6 +9202,7 @@ int RM_SubscribeToServerEvent(RedisModuleCtx *ctx, RedisModuleEvent event, Redis
|
||||
/* Protect in case of calls from contexts without a module reference. */
|
||||
if (ctx->module == NULL) return REDISMODULE_ERR;
|
||||
if (event.id >= _REDISMODULE_EVENT_NEXT) return REDISMODULE_ERR;
|
||||
if (event.dataver > moduleEventVersions[event.id]) return REDISMODULE_ERR; /* Module compiled with a newer redismodule.h than we support */
|
||||
|
||||
/* Search an event matching this module and event ID. */
|
||||
listIter li;
|
||||
@ -9302,11 +9325,10 @@ void moduleFireServerEvent(uint64_t eid, int subid, void *data) {
|
||||
|
||||
/* Event specific context and data pointer setup. */
|
||||
if (eid == REDISMODULE_EVENT_CLIENT_CHANGE) {
|
||||
modulePopulateClientInfoStructure(&civ1,data,
|
||||
el->event.dataver);
|
||||
serverAssert(modulePopulateClientInfoStructure(&civ1,data, el->event.dataver) == REDISMODULE_OK);
|
||||
moduledata = &civ1;
|
||||
} else if (eid == REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED) {
|
||||
modulePopulateReplicationInfoStructure(&riv1,el->event.dataver);
|
||||
serverAssert(modulePopulateReplicationInfoStructure(&riv1,el->event.dataver) == REDISMODULE_OK);
|
||||
moduledata = &riv1;
|
||||
} else if (eid == REDISMODULE_EVENT_FLUSHDB) {
|
||||
moduledata = data;
|
||||
@ -9510,6 +9532,9 @@ void moduleInitModulesSystem(void) {
|
||||
/* Setup the event listeners data structures. */
|
||||
RedisModule_EventListeners = listCreate();
|
||||
|
||||
/* Making sure moduleEventVersions is synced with the number of events. */
|
||||
serverAssert(sizeof(moduleEventVersions)/sizeof(moduleEventVersions[0]) == _REDISMODULE_EVENT_NEXT);
|
||||
|
||||
/* Our thread-safe contexts GIL must start with already locked:
|
||||
* it is just unlocked when it's safe. */
|
||||
pthread_mutex_lock(&moduleGIL);
|
||||
|
@ -259,7 +259,8 @@ typedef enum {
|
||||
|
||||
/* Server events definitions.
|
||||
* Those flags should not be used directly by the module, instead
|
||||
* the module should use RedisModuleEvent_* variables */
|
||||
* the module should use RedisModuleEvent_* variables.
|
||||
* Note: This must be synced with moduleEventVersions */
|
||||
#define REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED 0
|
||||
#define REDISMODULE_EVENT_PERSISTENCE 1
|
||||
#define REDISMODULE_EVENT_FLUSHDB 2
|
||||
@ -286,6 +287,32 @@ struct RedisModuleCtx;
|
||||
struct RedisModuleDefragCtx;
|
||||
typedef void (*RedisModuleEventCallback)(struct RedisModuleCtx *ctx, RedisModuleEvent eid, uint64_t subevent, void *data);
|
||||
|
||||
/* IMPORTANT: When adding a new version of one of below structures that contain
|
||||
* event data (RedisModuleFlushInfoV1 for example) we have to avoid renaming the
|
||||
* old RedisModuleEvent structure.
|
||||
* For example, if we want to add RedisModuleFlushInfoV2, the RedisModuleEvent
|
||||
* structures should be:
|
||||
* RedisModuleEvent_FlushDB = {
|
||||
* REDISMODULE_EVENT_FLUSHDB,
|
||||
* 1
|
||||
* },
|
||||
* RedisModuleEvent_FlushDBV2 = {
|
||||
* REDISMODULE_EVENT_FLUSHDB,
|
||||
* 2
|
||||
* }
|
||||
* and NOT:
|
||||
* RedisModuleEvent_FlushDBV1 = {
|
||||
* REDISMODULE_EVENT_FLUSHDB,
|
||||
* 1
|
||||
* },
|
||||
* RedisModuleEvent_FlushDB = {
|
||||
* REDISMODULE_EVENT_FLUSHDB,
|
||||
* 2
|
||||
* }
|
||||
* The reason for that is forward-compatibility: We want that module that
|
||||
* compiled with a new redismodule.h to be able to work with a old server,
|
||||
* unless the author explicitly decided to use the newer event type.
|
||||
*/
|
||||
static const RedisModuleEvent
|
||||
RedisModuleEvent_ReplicationRoleChanged = {
|
||||
REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED,
|
||||
|
Loading…
x
Reference in New Issue
Block a user