Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MERGED] Fix the array return bug #567

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions source/compiler/sc.h
Expand Up @@ -955,6 +955,8 @@ SC_VDECL int pc_memflags; /* special flags for the stack/heap usage */
SC_VDECL int pc_naked; /* if true mark following function as naked */
SC_VDECL int pc_compat; /* running in compatibility mode? */
SC_VDECL int pc_recursion; /* enable detailed recursion report? */
SC_VDECL int pc_retexpr; /* true if the current expression is a part of a "return" statement */
SC_VDECL int pc_retheap; /* heap space (in bytes) to be manually freed when returning an array returned by another function */

SC_VDECL constvalue_root sc_automaton_tab; /* automaton table */
SC_VDECL constvalue_root sc_state_tab; /* state table */
Expand Down
16 changes: 15 additions & 1 deletion source/compiler/sc1.c
Expand Up @@ -906,6 +906,7 @@ static void resetglobals(void)
sc_curstates=0;
pc_memflags=0;
pc_naked=FALSE;
pc_retexpr=FALSE;
emit_flags=0;
emit_stgbuf_idx=-1;
}
Expand Down Expand Up @@ -5556,8 +5557,16 @@ static int doexpr(int comma,int chkeffect,int allowarray,int mark_endexpr,
errorset(sEXPRMARK,0);
do {
/* on second round through, mark the end of the previous expression */
if (index!=stgidx)
if (index!=stgidx) {
markexpr(sEXPR,NULL,0);
/* also, if this is not the first expression and we are inside a "return"
* statement, we need to manually free the heap space allocated for the
* array returned by the function called in the previous expression */
if (pc_retexpr) {
modheap(pc_retheap);
pc_retheap=0;
} /* if */
} /* if */
pc_sideeffect=FALSE;
pc_ovlassignment=FALSE;
ident=expression(val,tag,symptr,chkfuncresult);
Expand Down Expand Up @@ -7631,7 +7640,11 @@ static void doreturn(void)
/* "return <value>" */
if ((rettype & uRETNONE)!=0)
error(78); /* mix "return;" and "return value;" */
assert(pc_retexpr==FALSE);
pc_retexpr=TRUE;
pc_retheap=0;
ident=doexpr(TRUE,FALSE,TRUE,FALSE,&tag,&sym,TRUE,NULL);
pc_retexpr=FALSE;
needtoken(tTERM);
/* see if this function already has a sub type (an array attached) */
assert(curfunc!=NULL);
Expand Down Expand Up @@ -7738,6 +7751,7 @@ static void doreturn(void)
/* moveto1(); is not necessary, callfunction() does a popreg() */
} /* if */
} /* if */
modheap(pc_retheap);
/* try to use "operator=" if tags don't match */
if (!matchtag(curfunc->tag,tag,TRUE))
check_userop(NULL,tag,curfunc->tag,2,NULL,&tag);
Expand Down
9 changes: 8 additions & 1 deletion source/compiler/sc3.c
Expand Up @@ -711,7 +711,14 @@ SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult)
rvalue(&lval);
/* scrap any arrays left on the heap */
assert(decl_heap>=locheap);
modheap((locheap-decl_heap)*sizeof(cell)); /* remove heap space, so negative delta */
if (!pc_retexpr) {
modheap((locheap-decl_heap)*sizeof(cell));/* remove heap space, so negative delta */
} else {
/* we need to copy the data from the leftover space first (e.g. when used
* from 'return' when returning a string returned by another function),
* so we'll free it manually later */
pc_retheap=(locheap-decl_heap)*sizeof(cell);
} /* if */
decl_heap=locheap;

if (lval.ident==iCONSTEXPR && val!=NULL) /* constant expression */
Expand Down
2 changes: 2 additions & 0 deletions source/compiler/scvars.c
Expand Up @@ -97,6 +97,8 @@ SC_VDEFINE int pc_memflags=0; /* special flags for the stack/heap
SC_VDEFINE int pc_naked=FALSE; /* if true mark following function as naked */
SC_VDEFINE int pc_compat=FALSE; /* running in compatibility mode? */
SC_VDEFINE int pc_recursion=FALSE; /* enable detailed recursion report? */
SC_VDEFINE int pc_retexpr=FALSE; /* true if the current expression is a part of a "return" statement */
SC_VDEFINE int pc_retheap=0; /* heap space (in bytes) to be manually freed when returning an array returned by another function */

SC_VDEFINE constvalue_root sc_automaton_tab = { NULL, NULL}; /* automaton table */
SC_VDEFINE constvalue_root sc_state_tab = { NULL, NULL}; /* state table */
Expand Down
32 changes: 32 additions & 0 deletions source/compiler/tests/gh_567.meta
@@ -0,0 +1,32 @@
{
'test_type': 'pcode_check',
'code_pattern': r"""
[0-9a-f]+ nop
[0-9a-f]+ load.pri [0-9a-f]+
[0-9a-f]+ jzer [0-9a-f]+
[0-9a-f]+ heap 00000030
[0-9a-f]+ push.alt
[0-9a-f]+ push.c 00000000
[0-9a-f]+ call [0-9a-f]+
[0-9a-f]+ pop.pri
[0-9a-f]+ load.s.alt 0000000c
[0-9a-f]+ movs 00000030
[0-9a-f]+ heap ffffffd0
[0-9a-f]+ retn
[0-9a-f]+ heap 00000030
[0-9a-f]+ push.alt
[0-9a-f]+ push.c 00000000
[0-9a-f]+ call [0-9a-f]+
[0-9a-f]+ pop.pri
[0-9a-f]+ heap ffffffd0
[0-9a-f]+ heap 00000030
[0-9a-f]+ push.alt
[0-9a-f]+ push.c 00000000
[0-9a-f]+ call [0-9a-f]+
[0-9a-f]+ pop.pri
[0-9a-f]+ load.s.alt 0000000c
[0-9a-f]+ movs 00000030
[0-9a-f]+ heap ffffffd0
[0-9a-f]+ retn
"""
}
22 changes: 22 additions & 0 deletions source/compiler/tests/gh_567.pwn
@@ -0,0 +1,22 @@
#pragma option -O0
#include <console>

StringOrigin()
{
static const string[] = "Hello world";
return string;
}

ReturnString()
{
static x = 0;
__emit nop; // mark the start of checked P-code
if (x)
return StringOrigin();
return StringOrigin(), StringOrigin();
}

main()
{
print(ReturnString());
}