1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
From ca074200a9ea12a2d7e9a1e0c370614b4512e2e2 Mon Sep 17 00:00:00 2001
From: Remi Collet <remi@remirepo.net>
Date: Sat, 4 Oct 2025 07:23:52 +0200
Subject: [PATCH] Fix #2678 don't add loadmodule when from config
---
src/config.c | 4 ++--
src/module.c | 17 ++++++++++++-----
src/module.h | 4 ++--
3 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/src/config.c b/src/config.c
index d0158b2c4d..87f4790c23 100644
--- a/src/config.c
+++ b/src/config.c
@@ -572,7 +572,7 @@ void loadServerConfigFromString(sds config) {
goto loaderr;
}
} else if (!strcasecmp(argv[0], "loadmodule") && argc >= 2) {
- moduleEnqueueLoadModule(argv[1], &argv[2], argc - 2);
+ moduleEnqueueLoadModule(argv[1], &argv[2], argc - 2, 1);
} else if (strchr(argv[0], '.')) {
if (argc < 2) {
err = "Module config specified without value";
@@ -1605,7 +1605,7 @@ void rewriteConfigLoadmoduleOption(struct rewriteConfigState *state) {
while ((de = dictNext(di)) != NULL) {
struct ValkeyModule *module = dictGetVal(de);
line = moduleLoadQueueEntryToLoadmoduleOptionStr(module, "loadmodule");
- rewriteConfigRewriteLine(state, "loadmodule", line, 1);
+ if (line) rewriteConfigRewriteLine(state, "loadmodule", line, 1);
}
dictReleaseIterator(di);
/* Mark "loadmodule" as processed in case modules is empty. */
diff --git a/src/module.c b/src/module.c
index e5afa952fa..dd440d1edf 100644
--- a/src/module.c
+++ b/src/module.c
@@ -84,6 +84,7 @@
struct moduleLoadQueueEntry {
sds path;
+ int conf;
int argc;
robj **argv;
};
@@ -670,7 +671,7 @@ void freeClientModuleData(client *c) {
c->module_data = NULL;
}
-void moduleEnqueueLoadModule(sds path, sds *argv, int argc) {
+void moduleEnqueueLoadModule(sds path, sds *argv, int argc, int is_config) {
int i;
struct moduleLoadQueueEntry *loadmod;
@@ -678,6 +679,7 @@ void moduleEnqueueLoadModule(sds path, sds *argv, int argc) {
loadmod->argv = argc ? zmalloc(sizeof(robj *) * argc) : NULL;
loadmod->path = sdsnew(path);
loadmod->argc = argc;
+ loadmod->conf = is_config;
for (i = 0; i < argc; i++) {
loadmod->argv[i] = createRawStringObject(argv[i], sdslen(argv[i]));
}
@@ -688,6 +690,10 @@ sds moduleLoadQueueEntryToLoadmoduleOptionStr(ValkeyModule *module,
const char *config_option_str) {
sds line;
+ if (module->loadmod->conf) {
+ /* no need to add as already from config */
+ return NULL;
+ }
line = sdsnew(config_option_str);
line = sdscatlen(line, " ", 1);
line = sdscatsds(line, module->loadmod->path);
@@ -12350,7 +12356,7 @@ void moduleLoadFromQueue(void) {
listRewind(server.loadmodule_queue, &li);
while ((ln = listNext(&li))) {
struct moduleLoadQueueEntry *loadmod = ln->value;
- if (moduleLoad(loadmod->path, (void **)loadmod->argv, loadmod->argc, 0) == C_ERR) {
+ if (moduleLoad(loadmod->path, (void **)loadmod->argv, loadmod->argc, 0, loadmod->conf) == C_ERR) {
serverLog(LL_WARNING, "Can't load module from %s: server aborting", loadmod->path);
exit(1);
}
@@ -12531,7 +12537,7 @@ void moduleUnregisterCleanup(ValkeyModule *module) {
/* Load a module and initialize it. On success C_OK is returned, otherwise
* C_ERR is returned. */
-int moduleLoad(const char *path, void **module_argv, int module_argc, int is_loadex) {
+int moduleLoad(const char *path, void **module_argv, int module_argc, int is_loadex, int is_config) {
int (*onload)(void *, void **, int);
void *handle;
@@ -12606,6 +12612,7 @@ int moduleLoad(const char *path, void **module_argv, int module_argc, int is_loa
ctx.module->loadmod->path = sdsnew(path);
ctx.module->loadmod->argv = module_argc ? zmalloc(sizeof(robj *) * module_argc) : NULL;
ctx.module->loadmod->argc = module_argc;
+ ctx.module->loadmod->conf = is_config;
for (int i = 0; i < module_argc; i++) {
ctx.module->loadmod->argv[i] = module_argv[i];
incrRefCount(ctx.module->loadmod->argv[i]);
@@ -13529,7 +13536,7 @@ void moduleCommand(client *c) {
argv = &c->argv[3];
}
- if (moduleLoad(c->argv[2]->ptr, (void **)argv, argc, 0) == C_OK)
+ if (moduleLoad(c->argv[2]->ptr, (void **)argv, argc, 0, 0) == C_OK)
addReply(c, shared.ok);
else
addReplyError(c, "Error loading the extension. Please check the server logs.");
@@ -13544,7 +13551,7 @@ void moduleCommand(client *c) {
/* If this is a loadex command we want to populate server.module_configs_queue with
* sds NAME VALUE pairs. We also want to increment argv to just after ARGS, if supplied. */
if (parseLoadexArguments((ValkeyModuleString ***)&argv, &argc) == VALKEYMODULE_OK &&
- moduleLoad(c->argv[2]->ptr, (void **)argv, argc, 1) == C_OK)
+ moduleLoad(c->argv[2]->ptr, (void **)argv, argc, 1, 0) == C_OK)
addReply(c, shared.ok);
else {
dictEmpty(server.module_configs_queue, NULL);
diff --git a/src/module.h b/src/module.h
index f6c266b592..e48a98f4ba 100644
--- a/src/module.h
+++ b/src/module.h
@@ -169,7 +169,7 @@ static inline void moduleInitDigestContext(ValkeyModuleDigest *mdvar) {
memset(mdvar->x, 0, sizeof(mdvar->x));
}
-void moduleEnqueueLoadModule(sds path, sds *argv, int argc);
+void moduleEnqueueLoadModule(sds path, sds *argv, int argc, int is_config);
sds moduleLoadQueueEntryToLoadmoduleOptionStr(ValkeyModule *module,
const char *config_option_str);
ValkeyModuleCtx *moduleAllocateContext(void);
@@ -180,7 +180,7 @@ void moduleFreeContext(ValkeyModuleCtx *ctx);
void moduleInitModulesSystem(void);
void moduleInitModulesSystemLast(void);
void modulesCron(void);
-int moduleLoad(const char *path, void **argv, int argc, int is_loadex);
+int moduleLoad(const char *path, void **argv, int argc, int is_loadex, int is_config);
int moduleUnload(sds name, const char **errmsg);
void moduleLoadFromQueue(void);
int moduleGetCommandKeysViaAPI(struct serverCommand *cmd, robj **argv, int argc, getKeysResult *result);
|