From 1d1244c2f04845051ef94f5455b18703b59e113f Mon Sep 17 00:00:00 2001 From: Zeex Date: Fri, 3 Jan 2014 14:39:08 +0700 Subject: [PATCH] Fix runtime error in variadic functions that return strings This fixes a bug where returning a string from a variadic function caused an invalid memory access error during runtime. It seems like they forgot to update existing string return code for variadic functions. See 11) here: http://forum.sa-mp.com/showthread.php?t=355877 --------- test code -------- native print(const s[]); stock f(...) { new a, b, c; new str[] = "hello"; return str; } main() { print(f(1, 2, 3)); } ----- end of test code ----- --- source/compiler/sc.h | 2 ++ source/compiler/sc1.c | 30 +++++++++++++++++++++++++++++- source/compiler/sc4.c | 20 ++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/source/compiler/sc.h b/source/compiler/sc.h index 056e198a..707b0539 100644 --- a/source/compiler/sc.h +++ b/source/compiler/sc.h @@ -583,6 +583,7 @@ SC_FUNC void startfunc(char *fname); SC_FUNC void endfunc(void); SC_FUNC void alignframe(int numbytes); SC_FUNC void rvalue(value *lval); +SC_FUNC void dereference(void); SC_FUNC void address(symbol *ptr,regid reg); SC_FUNC void store(value *lval); SC_FUNC void loadreg(cell address,regid reg); @@ -604,6 +605,7 @@ SC_FUNC void ffabort(int reason); SC_FUNC void ffbounds(cell size); SC_FUNC void jumplabel(int number); SC_FUNC void defstorage(void); +SC_FUNC void getfrm(void); SC_FUNC void modstk(int delta); SC_FUNC void setstk(cell value); SC_FUNC void modheap(int delta); diff --git a/source/compiler/sc1.c b/source/compiler/sc1.c index c3646784..a7426e9c 100644 --- a/source/compiler/sc1.c +++ b/source/compiler/sc1.c @@ -5599,6 +5599,22 @@ static symbol *fetchlab(char *name) return sym; } +/* isvariadic + * + * Checks if the function is variadic. + */ +static int isvariadic(symbol *sym) +{ + int i; + for (i=0; curfunc->dim.arglist[i].ident!=0; i++) { + /* check whether this is a variadic function */ + if (curfunc->dim.arglist[i].ident==iVARARGS) { + return TRUE; + } /* if */ + } /* for */ + return FALSE; +} + /* doreturn * * Global references: rettype (altered) @@ -5703,7 +5719,19 @@ static void doreturn(void) * it stays on the heap for the moment, and it is removed -usually- at * the end of the expression/statement, see expression() in SC3.C) */ - address(sub,sALT); /* ALT = destination */ + if (isvariadic(sub)) { + pushreg(sPRI); /* save source address stored in PRI */ + sub->addr=2*sizeof(cell); + address(sub,sALT); /* get the number of arguments */ + getfrm(); + addconst(3*sizeof(cell)); + ob_add(); + dereference(); + swap1(); + popreg(sALT); /* ALT = destination */ + } else { + address(sub,sALT); /* ALT = destination */ + } /* if */ arraysize=calc_arraysize(dim,numdim,0); memcopy(arraysize*sizeof(cell)); /* source already in PRI */ /* moveto1(); is not necessary, callfunction() does a popreg() */ diff --git a/source/compiler/sc4.c b/source/compiler/sc4.c index f982b586..a4baafde 100644 --- a/source/compiler/sc4.c +++ b/source/compiler/sc4.c @@ -420,6 +420,16 @@ SC_FUNC void rvalue(value *lval) } /* if */ } +/* dereference + * + * Get a cell from a memory address stored in the primary register + */ +SC_FUNC void dereference(void) +{ + stgwrite("\tload.i\n"); + code_idx+=opcodes(1); +} + /* Get the address of a symbol into the primary or alternate register (used * for arrays, and for passing arguments by reference). */ @@ -805,6 +815,16 @@ SC_FUNC void defstorage(void) stgwrite("dump "); } +/* + * Copies frame address to primary register + */ + +SC_FUNC void getfrm(void) +{ + stgwrite("\tlctrl 5\n"); + code_idx+=opcodes(1)+opargs(1); +} + /* * Inclrement/decrement stack pointer. Note that this routine does * nothing if the delta is zero.