From 6133e9d1835b642c6b314e70a06619d004d6c69a Mon Sep 17 00:00:00 2001 From: Zeex Date: Wed, 1 Jan 2014 16:22:05 +0700 Subject: [PATCH] Fix compile crash when returning a string literal This fixes a crash during compile-time when returning a string or array literal from a function. Now the compiler will give an error instead. See 1) here: http://forum.sa-mp.com/showthread.php?t=355877 --------- test code -------- native use(...); return_string() { new string[] = "string"; return string; } return_string_literal() { return "string"; // error 029: invalid expression, assumed zero } return_number() { return 0; } main() { new n = return_number(); // OK new s[100]; s = return_string(); // OK s = return_string_literal(); // error 033: array must be indexed (variable "s") use(n, s); } ----- end of test code ----- --- source/compiler/sc1.c | 126 ++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 61 deletions(-) diff --git a/source/compiler/sc1.c b/source/compiler/sc1.c index 1f11455..c364678 100644 --- a/source/compiler/sc1.c +++ b/source/compiler/sc1.c @@ -5621,7 +5621,7 @@ static void doreturn(void) if ((rettype & uRETVALUE)!=0) { int retarray=(ident==iARRAY || ident==iREFARRAY); /* there was an earlier "return" statement in this function */ - if (sub==NULL && retarray || sub!=NULL && !retarray) + if ((sub==NULL && retarray && sym!=NULL) || sub!=NULL && !retarray) error(79); /* mixing "return array;" and "return value;" */ if (retarray && (curfunc->usage & uPUBLIC)!=0) error(90,curfunc->name); /* public function may not return array */ @@ -5634,76 +5634,80 @@ static void doreturn(void) if (ident==iARRAY || ident==iREFARRAY) { int dim[sDIMEN_MAX],numdim; cell arraysize; - assert(sym!=NULL); - if (sub!=NULL) { - assert(sub->ident==iREFARRAY); - /* this function has an array attached already; check that the current - * "return" statement returns exactly the same array - */ - level=sym->dim.array.level; - if (sub->dim.array.level!=level) { - error(48); /* array dimensions must match */ + if (sym==NULL) { + /* array literals cannot be returned directly */ + error(29); /* invalid expression, assumed zero */ + } else { + if (sub!=NULL) { + assert(sub->ident==iREFARRAY); + /* this function has an array attached already; check that the current + * "return" statement returns exactly the same array + */ + level=sym->dim.array.level; + if (sub->dim.array.level!=level) { + error(48); /* array dimensions must match */ + } else { + for (numdim=0; numdim<=level; numdim++) { + dim[numdim]=(int)sub->dim.array.length; + if (sym->dim.array.length!=dim[numdim]) + error(47); /* array sizes must match */ + if (numdimdim.array.level; for (numdim=0; numdim<=level; numdim++) { dim[numdim]=(int)sub->dim.array.length; - if (sym->dim.array.length!=dim[numdim]) - error(47); /* array sizes must match */ + idxtag[numdim]=sub->x.tags.index; if (numdimname); } /* for */ + /* the address of the array is stored in a hidden parameter; the address + * of this parameter is 1 + the number of parameters (times the size of + * a cell) + the size of the stack frame and the return address + * base + 0*sizeof(cell) == previous "base" + * base + 1*sizeof(cell) == function return address + * base + 2*sizeof(cell) == number of arguments + * base + 3*sizeof(cell) == first argument of the function + * ... + * base + ((n-1)+3)*sizeof(cell) == last argument of the function + * base + (n+3)*sizeof(cell) == hidden parameter with array address + */ + assert(curfunc!=NULL); + assert(curfunc->dim.arglist!=NULL); + for (argcount=0; curfunc->dim.arglist[argcount].ident!=0; argcount++) + /* nothing */; + sub=addvariable(curfunc->name,(argcount+3)*sizeof(cell),iREFARRAY,sGLOBAL,curfunc->tag,dim,numdim,idxtag); + sub->parent=curfunc; } /* if */ - } else { - int idxtag[sDIMEN_MAX]; - int argcount; - /* this function does not yet have an array attached; clone the - * returned symbol beneath the current function + /* get the hidden parameter, copy the array (the array is on the heap; + * 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) */ - sub=sym; - assert(sub!=NULL); - level=sub->dim.array.level; - for (numdim=0; numdim<=level; numdim++) { - dim[numdim]=(int)sub->dim.array.length; - idxtag[numdim]=sub->x.tags.index; - if (numdimname); - } /* for */ - /* the address of the array is stored in a hidden parameter; the address - * of this parameter is 1 + the number of parameters (times the size of - * a cell) + the size of the stack frame and the return address - * base + 0*sizeof(cell) == previous "base" - * base + 1*sizeof(cell) == function return address - * base + 2*sizeof(cell) == number of arguments - * base + 3*sizeof(cell) == first argument of the function - * ... - * base + ((n-1)+3)*sizeof(cell) == last argument of the function - * base + (n+3)*sizeof(cell) == hidden parameter with array address - */ - assert(curfunc!=NULL); - assert(curfunc->dim.arglist!=NULL); - for (argcount=0; curfunc->dim.arglist[argcount].ident!=0; argcount++) - /* nothing */; - sub=addvariable(curfunc->name,(argcount+3)*sizeof(cell),iREFARRAY,sGLOBAL,curfunc->tag,dim,numdim,idxtag); - sub->parent=curfunc; + address(sub,sALT); /* ALT = destination */ + arraysize=calc_arraysize(dim,numdim,0); + memcopy(arraysize*sizeof(cell)); /* source already in PRI */ + /* moveto1(); is not necessary, callfunction() does a popreg() */ } /* if */ - /* get the hidden parameter, copy the array (the array is on the heap; - * 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 */ - arraysize=calc_arraysize(dim,numdim,0); - memcopy(arraysize*sizeof(cell)); /* source already in PRI */ - /* moveto1(); is not necessary, callfunction() does a popreg() */ } /* if */ } else { /* this return statement contains no expression */