Skip to content

Commit

Permalink
Fix arrays not passing through varargs correctly.
Browse files Browse the repository at this point in the history
Bug: sourcemod issue #2146
Test: new test case
  • Loading branch information
dvander committed Jun 2, 2024
1 parent c0cf678 commit 08d4d0c
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 1 deletion.
5 changes: 4 additions & 1 deletion compiler/code-generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions tests/regressions/pass-string-as-vararg.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1: Ham
TEST
14 changes: 14 additions & 0 deletions tests/regressions/pass-string-as-vararg.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <shell>

int TestNumber = 0;

void test(const char[] title) {
TestNumber++;
printf("%d: %s\n", TestNumber, title);
}

public main() {
test("Ham");
printf("%s\n", "TEST");
}

3 changes: 3 additions & 0 deletions tests/shell.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
36 changes: 36 additions & 0 deletions vm/shell/shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const char*>(addr), stdout);
else if (next == 'f')
fprintf(stdout, "%f", *reinterpret_cast<float*>(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;
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 08d4d0c

Please sign in to comment.