Skip to content

Commit 1766416

Browse files
authored
Allow scripts to support null characters again (#1984)
We made a change during the refactoring of the engine changes that used a strlen on an SDS string. SDS are resizable, but they are binary safe and support NULL characters, which means we are truncating the string at the null character. This is a breaking change for modules, so wanted to raise it for the upcoming patch. An alternative is we could expose the script code as a server object, which would require some construction of the object in the function pathway and freeing. I opted to keep the code flow as similar as possible for the patch. There is a test which only passes now. For some reasons, functions don't support binary data. So as of right now this patch doesn't fix that case. Resolves #1942 --------- Signed-off-by: Madelyn Olson <[email protected]>
1 parent e113a5e commit 1766416

File tree

8 files changed

+55
-13
lines changed

8 files changed

+55
-13
lines changed

src/eval.c

+1
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,7 @@ static int evalRegisterNewScript(client *c, robj *body, char **sha) {
411411
scriptingEngineCallCompileCode(engine,
412412
VMSE_EVAL,
413413
(sds)body->ptr + shebang_len,
414+
sdslen(body->ptr) - shebang_len,
414415
0,
415416
&num_compiled_functions,
416417
&_err);

src/functions.c

+1
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,7 @@ sds functionsCreateWithLibraryCtx(sds code, int replace, sds *err, functionsLibC
10121012
scriptingEngineCallCompileCode(engine,
10131013
VMSE_FUNCTION,
10141014
md.code,
1015+
sdslen(md.code),
10151016
timeout,
10161017
&num_compiled_functions,
10171018
&compile_error);

src/lua/engine_lua.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ static compiledFunction **luaEngineCompileCode(ValkeyModuleCtx *module_ctx,
195195
engineCtx *engine_ctx,
196196
subsystemType type,
197197
const char *code,
198+
size_t code_len,
198199
size_t timeout,
199200
size_t *out_num_compiled_functions,
200201
robj **err) {
@@ -207,7 +208,7 @@ static compiledFunction **luaEngineCompileCode(ValkeyModuleCtx *module_ctx,
207208
if (type == VMSE_EVAL) {
208209
lua_State *lua = lua_engine_ctx->eval_lua;
209210

210-
if (luaL_loadbuffer(lua, code, strlen(code), "@user_script")) {
211+
if (luaL_loadbuffer(lua, code, code_len, "@user_script")) {
211212
sds error = sdscatfmt(sdsempty(), "Error compiling script (new function): %s", lua_tostring(lua, -1));
212213
*err = createObject(OBJ_STRING, error);
213214
lua_pop(lua, 1);

src/scripting_engine.c

+23-9
Original file line numberDiff line numberDiff line change
@@ -217,21 +217,35 @@ static void engineTeardownModuleCtx(scriptingEngine *e) {
217217
compiledFunction **scriptingEngineCallCompileCode(scriptingEngine *engine,
218218
subsystemType type,
219219
const char *code,
220+
size_t code_len,
220221
size_t timeout,
221222
size_t *out_num_compiled_functions,
222223
robj **err) {
223224
serverAssert(type == VMSE_EVAL || type == VMSE_FUNCTION);
224-
225+
compiledFunction **functions = NULL;
225226
engineSetupModuleCtx(engine, NULL);
227+
if (engine->impl.methods.version == 1) {
228+
functions = engine->impl.methods.compile_code_v1(
229+
engine->module_ctx,
230+
engine->impl.ctx,
231+
type,
232+
code,
233+
timeout,
234+
out_num_compiled_functions,
235+
err);
236+
} else {
237+
/* Assume versions greater than 1 use updated interface. */
238+
functions = engine->impl.methods.compile_code(
239+
engine->module_ctx,
240+
engine->impl.ctx,
241+
type,
242+
code,
243+
code_len,
244+
timeout,
245+
out_num_compiled_functions,
246+
err);
247+
}
226248

227-
compiledFunction **functions = engine->impl.methods.compile_code(
228-
engine->module_ctx,
229-
engine->impl.ctx,
230-
type,
231-
code,
232-
timeout,
233-
out_num_compiled_functions,
234-
err);
235249

236250
engineTeardownModuleCtx(engine);
237251

src/scripting_engine.h

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ ValkeyModule *scriptingEngineGetModule(scriptingEngine *engine);
5555
compiledFunction **scriptingEngineCallCompileCode(scriptingEngine *engine,
5656
subsystemType type,
5757
const char *code,
58+
size_t code_len,
5859
size_t timeout,
5960
size_t *out_num_compiled_functions,
6061
robj **err);

src/valkeymodule.h

+19-3
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,8 @@ typedef struct ValkeyModuleScriptingEngineCallableLazyEvalReset {
878878
*
879879
* - `code`: string pointer to the source code.
880880
*
881+
* - `code_len`: The length of the code string.
882+
*
881883
* - `timeout`: timeout for the library creation (0 for no timeout).
882884
*
883885
* - `out_num_compiled_functions`: out param with the number of objects
@@ -889,6 +891,18 @@ typedef struct ValkeyModuleScriptingEngineCallableLazyEvalReset {
889891
* occurred.
890892
*/
891893
typedef ValkeyModuleScriptingEngineCompiledFunction **(*ValkeyModuleScriptingEngineCompileCodeFunc)(
894+
ValkeyModuleCtx *module_ctx,
895+
ValkeyModuleScriptingEngineCtx *engine_ctx,
896+
ValkeyModuleScriptingEngineSubsystemType type,
897+
const char *code,
898+
size_t code_len,
899+
size_t timeout,
900+
size_t *out_num_compiled_functions,
901+
ValkeyModuleString **err);
902+
903+
/* Version one of source code compilation interface. This API does not allow the compiler to
904+
* safely handle binary data. You should use a newer version of the API if possible. */
905+
typedef ValkeyModuleScriptingEngineCompiledFunctionV1 **(*ValkeyModuleScriptingEngineCompileCodeFuncV1)(
892906
ValkeyModuleCtx *module_ctx,
893907
ValkeyModuleScriptingEngineCtx *engine_ctx,
894908
ValkeyModuleScriptingEngineSubsystemType type,
@@ -985,16 +999,18 @@ typedef ValkeyModuleScriptingEngineMemoryInfo (*ValkeyModuleScriptingEngineGetMe
985999
ValkeyModuleScriptingEngineSubsystemType type);
9861000

9871001
/* Current ABI version for scripting engine modules. */
988-
#define VALKEYMODULE_SCRIPTING_ENGINE_ABI_VERSION 1UL
1002+
#define VALKEYMODULE_SCRIPTING_ENGINE_ABI_VERSION 2UL
9891003

9901004
typedef struct ValkeyModuleScriptingEngineMethods {
9911005
uint64_t version; /* Version of this structure for ABI compat. */
9921006

9931007
/* Compile code function callback. When a new script is loaded, this
9941008
* callback will be called with the script code, compiles it, and returns a
9951009
* list of `ValkeyModuleScriptingEngineCompiledFunc` objects. */
996-
ValkeyModuleScriptingEngineCompileCodeFunc compile_code;
997-
1010+
union {
1011+
ValkeyModuleScriptingEngineCompileCodeFuncV1 compile_code_v1;
1012+
ValkeyModuleScriptingEngineCompileCodeFunc compile_code;
1013+
};
9981014
/* Function callback to free the memory of a registered engine function. */
9991015
ValkeyModuleScriptingEngineFreeFunctionFunc free_function;
10001016

tests/modules/helloscripting.c

+2
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,12 @@ static ValkeyModuleScriptingEngineCompiledFunction **createHelloLangEngine(Valke
349349
ValkeyModuleScriptingEngineCtx *engine_ctx,
350350
ValkeyModuleScriptingEngineSubsystemType type,
351351
const char *code,
352+
size_t code_len,
352353
size_t timeout,
353354
size_t *out_num_compiled_functions,
354355
ValkeyModuleString **err) {
355356
VALKEYMODULE_NOT_USED(module_ctx);
357+
VALKEYMODULE_NOT_USED(code_len);
356358
VALKEYMODULE_NOT_USED(type);
357359
VALKEYMODULE_NOT_USED(timeout);
358360
VALKEYMODULE_NOT_USED(err);

tests/unit/scripting.tcl

+6
Original file line numberDiff line numberDiff line change
@@ -2458,4 +2458,10 @@ start_server {tags {"scripting"}} {
24582458
assert { [r memory usage foo] <= $expected_memory};
24592459
}
24602460
}
2461+
2462+
test {EVAL - Scripts support NULL byte} {
2463+
assert_equal [r eval "return \"\x00\";" 0] "\x00"
2464+
# Using a null byte never seemed to work with functions, so
2465+
# we don't have a test for that case.
2466+
}
24612467
}

0 commit comments

Comments
 (0)