Skip to content

Commit

Permalink
Fix runtime error in variadic functions that return strings
Browse files Browse the repository at this point in the history
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 -----
  • Loading branch information
Zeex committed Jan 3, 2014
1 parent eba8474 commit 1d1244c
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 1 deletion.
2 changes: 2 additions & 0 deletions source/compiler/sc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
30 changes: 29 additions & 1 deletion source/compiler/sc1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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() */
Expand Down
20 changes: 20 additions & 0 deletions source/compiler/sc4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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).
*/
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 1d1244c

Please sign in to comment.