From 17114347d1edea798bbaab449abcedd015f2a3b0 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Fri, 15 Aug 2014 17:15:22 +0200 Subject: [PATCH] Compiler: Fix runtime error in variadic functions that return strings. Imported from SM-AM: https://github.com/Zeex/pawn/commit/1d1244c2f04845051ef94f5455b18703b59e113f. "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." --- compiler/libpc300/sc.h | 2 ++ compiler/libpc300/sc1.c | 30 +++++++++++++++++++++++++++++- compiler/libpc300/sc4.c | 22 ++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/compiler/libpc300/sc.h b/compiler/libpc300/sc.h index 76127af5..0678fd86 100755 --- a/compiler/libpc300/sc.h +++ b/compiler/libpc300/sc.h @@ -575,6 +575,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 storereg(cell address,regid reg); @@ -595,6 +596,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/compiler/libpc300/sc1.c b/compiler/libpc300/sc1.c index 9e25c7e6..0b96cdea 100755 --- a/compiler/libpc300/sc1.c +++ b/compiler/libpc300/sc1.c @@ -5288,6 +5288,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) @@ -5392,7 +5408,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/compiler/libpc300/sc4.c b/compiler/libpc300/sc4.c index 982d3a32..e428117a 100755 --- a/compiler/libpc300/sc4.c +++ b/compiler/libpc300/sc4.c @@ -410,6 +410,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). */ @@ -829,6 +839,18 @@ 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.