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:
guybe7 2022-01-11 13:33:39 +01:00 committed by GitHub
parent 39feee8e3a
commit 5009b43dc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 4 deletions

View File

@ -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);

View File

@ -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,