From e30fb7ae039d698dcc833ecfbc3e647a88e055df Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 1 Jun 2024 21:21:41 -0700 Subject: [PATCH] Fix arrays not passing through varargs correctly. Bug: sourcemod issue #2146 Test: new test case --- compiler/code-generator.cpp | 5 ++- tests/regressions/pass-string-as-vararg.out | 2 ++ tests/regressions/pass-string-as-vararg.sp | 14 ++++++++ tests/shell.inc | 3 ++ vm/shell/shell.cpp | 36 +++++++++++++++++++++ 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 tests/regressions/pass-string-as-vararg.out create mode 100644 tests/regressions/pass-string-as-vararg.sp diff --git a/compiler/code-generator.cpp b/compiler/code-generator.cpp index f152568e0..5f08dd686 100644 --- a/compiler/code-generator.cpp +++ b/compiler/code-generator.cpp @@ -1172,7 +1172,10 @@ void CodeGenerator::EmitCallExpr(CallExpr* call) { } if (arg->type_info().is_varargs) { - if (val.ident == iVARIABLE) { + if (val.type()->isArray()) { + if (lvalue) + __ address(val.sym, sPRI); + } else if (val.ident == iVARIABLE) { assert(val.sym); assert(lvalue); /* treat a "const" variable passed to a function with a non-const diff --git a/tests/regressions/pass-string-as-vararg.out b/tests/regressions/pass-string-as-vararg.out new file mode 100644 index 000000000..e176ae8cd --- /dev/null +++ b/tests/regressions/pass-string-as-vararg.out @@ -0,0 +1,2 @@ +1: Ham +TEST diff --git a/tests/regressions/pass-string-as-vararg.sp b/tests/regressions/pass-string-as-vararg.sp new file mode 100644 index 000000000..b0c1d28d9 --- /dev/null +++ b/tests/regressions/pass-string-as-vararg.sp @@ -0,0 +1,14 @@ +#include + +int TestNumber = 0; + +void test(const char[] title) { + TestNumber++; + printf("%d: %s\n", TestNumber, title); +} + +public main() { + test("Ham"); + printf("%s\n", "TEST"); +} + diff --git a/tests/shell.inc b/tests/shell.inc index ec4cdd215..43db54ac6 100644 --- a/tests/shell.inc +++ b/tests/shell.inc @@ -13,6 +13,9 @@ native void report_error(); native void unbound_native(); native int donothing(); +// dumb version of printf(), only supports %f, %d, %s. +native void printf(const char[] fmt, any:...); + // Return arg, but through a dynamically generated native. native int dynamic_native(int arg); diff --git a/vm/shell/shell.cpp b/vm/shell/shell.cpp index 0936fc336..385de977b 100644 --- a/vm/shell/shell.cpp +++ b/vm/shell/shell.cpp @@ -125,6 +125,41 @@ static cell_t PrintNums(IPluginContext* cx, const cell_t* params) return 1; } +static cell_t Printf(IPluginContext* cx, const cell_t* params) { + char* p; + cx->LocalToString(params[1], &p); + + size_t index = 1; + while (*p) { + if (*p == '%') { + char next = *(p + 1); + if (next == 's' || next == 'd' || next == 'f') { + index++; + if (index > params[0]) + return cx->ThrowNativeError("Wrong number of arguments"); + + cell_t* addr; + if (int err = cx->LocalToPhysAddr(params[index], &addr); err != SP_ERROR_NONE) + return cx->ThrowNativeErrorEx(err, "Could not read argument"); + + if (next == 's') + fputs(reinterpret_cast(addr), stdout); + else if (next == 'f') + fprintf(stdout, "%f", *reinterpret_cast(addr)); + else if (next == 'd') + fprintf(stdout, "%d", *addr); + + p += 2; + continue; + } + } + + fputc(*p, stdout); + p++; + } + return 1; +} + static cell_t DoNothing(IPluginContext* cx, const cell_t* params) { return 1; @@ -330,6 +365,7 @@ static int Execute(const char* file) BindNative(rt, "copy_2d_array_to_callback", Copy2dArrayToCallback); BindNative(rt, "call_with_string", CallWithString); BindNative(rt, "assert_eq", AssertEq); + BindNative(rt, "printf", Printf); IPluginFunction* fun = rt->GetFunctionByName("main"); if (!fun)