Skip to content

Commit

Permalink
Fix compile crash when returning a string literal
Browse files Browse the repository at this point in the history
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 -----
  • Loading branch information
Zeex committed Jan 1, 2014
1 parent c20d9cb commit 6133e9d
Showing 1 changed file with 65 additions and 61 deletions.
126 changes: 65 additions & 61 deletions source/compiler/sc1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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 (numdim<level) {
sym=finddepend(sym);
sub=finddepend(sub);
assert(sym!=NULL && sub!=NULL);
/* ^^^ both arrays have the same dimensions (this was checked
* earlier) so the dependend should always be found
*/
} /* if */
} /* for */
} /* 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
*/
sub=sym;
assert(sub!=NULL);
level=sub->dim.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 (numdim<level) {
sym=finddepend(sym);
sub=finddepend(sub);
assert(sym!=NULL && sub!=NULL);
/* ^^^ both arrays have the same dimensions (this was checked
* earlier) so the dependend should always be found
*/
assert(sub!=NULL);
} /* if */
/* check that all dimensions are known */
if (dim[numdim]<=0)
error(46,sym->name);
} /* 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 (numdim<level) {
sub=finddepend(sub);
assert(sub!=NULL);
} /* if */
/* check that all dimensions are known */
if (dim[numdim]<=0)
error(46,sym->name);
} /* 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 */
Expand Down

2 comments on commit 6133e9d

@Dayvison
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does not work for me
http://prntscr.com/9hbjbi
Using the last version,

@Y-Less
Copy link
Member

@Y-Less Y-Less commented on 6133e9d Dec 22, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That IS working! Read the description of the fix:

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.

You got an error, the thing you were meant to get; not a crash, the bad thing...

Please sign in to comment.