Compiler: Improve/fix recursion detection.

Imported from Pawn 3.2.3664 and 3.3.3875.
This commit is contained in:
Arkshine 2014-08-17 14:38:18 +02:00
parent a873066466
commit e46785a434

View File

@ -105,7 +105,7 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags,
int fpublic,int fconst,arginfo *arg); int fpublic,int fconst,arginfo *arg);
static void make_report(symbol *root,FILE *log,char *sourcefile); static void make_report(symbol *root,FILE *log,char *sourcefile);
static void reduce_referrers(symbol *root); static void reduce_referrers(symbol *root);
static long max_stacksize(symbol *root); static long max_stacksize(symbol *root, int *recursion);
static int testsymbols(symbol *root,int level,int testlabs,int testconst); static int testsymbols(symbol *root,int level,int testlabs,int testconst);
static void destructsymbols(symbol *root,int level); static void destructsymbols(symbol *root,int level);
static constvalue *find_constval_byval(constvalue *table,cell val); static constvalue *find_constval_byval(constvalue *table,cell val);
@ -718,7 +718,8 @@ cleanup:
#if !defined SC_LIGHT #if !defined SC_LIGHT
if (errnum==0 && strlen(errfname)==0) { if (errnum==0 && strlen(errfname)==0) {
long stacksize=max_stacksize(&glbtab); int recursion;
long stacksize=max_stacksize(&glbtab,&recursion);
int flag_exceed=0; int flag_exceed=0;
if (sc_amxlimit > 0 && (long)(hdrsize+code_idx+glb_declared*sizeof(cell)+sc_stksize*sizeof(cell)) >= sc_amxlimit) if (sc_amxlimit > 0 && (long)(hdrsize+code_idx+glb_declared*sizeof(cell)+sc_stksize*sizeof(cell)) >= sc_amxlimit)
flag_exceed=1; flag_exceed=1;
@ -4247,29 +4248,47 @@ static void reduce_referrers(symbol *root)
} }
#if !defined SC_LIGHT #if !defined SC_LIGHT
static long max_stacksize_recurse(symbol *sourcesym, symbol *sym, long basesize, int *pubfuncparams) static long max_stacksize_recurse(symbol **sourcesym,symbol *sym,long basesize,int *pubfuncparams,int *recursion)
{ {
long size,maxsize; long size,maxsize;
int i; int i,stkpos;
assert(sourcesym!=NULL);
assert(sym!=NULL); assert(sym!=NULL);
assert(sym->ident==iFUNCTN); assert(sym->ident==iFUNCTN);
assert((sym->usage & uNATIVE)==0); assert((sym->usage & uNATIVE)==0);
assert(recursion!=NULL);
maxsize=sym->x.stacksize; maxsize=sym->x.stacksize;
for (i=0; i<sym->numrefers; i++) { for (i=0; i<sym->numrefers; i++) {
if (sym->refer[i]!=NULL) { if (sym->refer[i]!=NULL) {
assert(sym->refer[i]->ident==iFUNCTN); assert(sym->refer[i]->ident==iFUNCTN);
assert((sym->refer[i]->usage & uNATIVE)==0); /* a native function cannot refer to a user-function */ assert((sym->refer[i]->usage & uNATIVE)==0); /* a native function cannot refer to a user-function */
if (sym->refer[i] == sourcesym) for (stkpos=0; sourcesym[stkpos]!=NULL; stkpos++) {
return -1; /* recursion detection */ if (sym->refer[i]==sourcesym[stkpos]) { /* recursion detection */
size = max_stacksize_recurse(sourcesym, sym->refer[i], sym->x.stacksize, pubfuncparams); if ((sc_debug & sSYMBOLIC)!=0 || verbosity>=2) {
if (size<0) char symname[2*sNAMEMAX+16];/* allow space for user defined operators */
return size; /* recursion was detected, quit */ funcdisplayname(symname,sym->name);
if (maxsize<size) errorset(sSETFILE,sym->fnumber);
maxsize=size; errorset(sSETLINE,sym->lnumber);
error(237,symname); /* recursive function */
} /* if */
*recursion=1;
goto break_recursion; /* recursion was detected, quit loop */
} /* if */ } /* if */
} /* for */ } /* for */
/* add this symbol to the stack */
sourcesym[stkpos]=sym;
sourcesym[stkpos+1]=NULL;
/* check size of callee */
size=max_stacksize_recurse(sourcesym,sym->refer[i],sym->x.stacksize,pubfuncparams,recursion);
if (maxsize<size)
maxsize=size;
/* remove this symbol from the stack */
sourcesym[stkpos]=NULL;
} /* if */
} /* for */
break_recursion:
if ((sym->usage & uPUBLIC)!=0) { if ((sym->usage & uPUBLIC)!=0) {
/* Find out how many parameters a public function has, then see if this /* Find out how many parameters a public function has, then see if this
@ -4287,10 +4306,13 @@ static long max_stacksize_recurse(symbol *sourcesym, symbol *sym, long basesize,
*pubfuncparams=count; *pubfuncparams=count;
} /* if */ } /* if */
errorset(sEXPRRELEASE,0); /* clear error data */
errorset(sRESET,0);
return maxsize+basesize; return maxsize+basesize;
} }
static long max_stacksize(symbol *root) static long max_stacksize(symbol *root,int *recursion)
{ {
/* Loop over all non-native functions. For each function, loop /* Loop over all non-native functions. For each function, loop
* over all of its referrers, accumulating the stack requirements. * over all of its referrers, accumulating the stack requirements.
@ -4303,29 +4325,44 @@ static long max_stacksize(symbol *root)
* stack requirements are thus only an estimate. * stack requirements are thus only an estimate.
*/ */
long size,maxsize; long size,maxsize;
int maxparams; int maxparams,numfunctions;
symbol *sym; symbol *sym;
symbol **symstack;
#if !defined NDEBUG assert(root!=NULL);
for (sym=root->next; sym!=NULL; sym=sym->next) assert(recursion!=NULL);
if (sym->ident==iFUNCTN) /* count number of functions (for allocating the stack for recursion detection) */
numfunctions=0;
for (sym=root->next; sym!=NULL; sym=sym->next) {
if (sym->ident==iFUNCTN) {
assert(sym->compound==0); assert(sym->compound==0);
#endif if ((sym->usage & uNATIVE)==0)
numfunctions++;
} /* if */
} /* if */
/* allocate function symbol stack */
symstack=(symbol **)malloc((numfunctions+1)*sizeof(symbol*));
if (symstack==NULL)
error(103); /* insufficient memory (fatal error) */
memset(symstack,0,(numfunctions+1)*sizeof(symbol*));
maxsize=0; maxsize=0;
maxparams=0; maxparams=0;
*recursion=0; /* assume no recursion */
for (sym=root->next; sym!=NULL; sym=sym->next) { for (sym=root->next; sym!=NULL; sym=sym->next) {
/* drop out if this is not a user-implemented function */ /* drop out if this is not a user-implemented function */
if (sym->ident!=iFUNCTN || (sym->usage & uNATIVE)!=0) if (sym->ident!=iFUNCTN || (sym->usage & uNATIVE)!=0)
continue; continue;
/* accumulate stack size for this symbol */ /* accumulate stack size for this symbol */
size=max_stacksize_recurse(sym,sym,0L,&maxparams); symstack[0]=sym;
if (size<0) assert(symstack[1]==NULL);
return size; /* recursion was detected */ size=max_stacksize_recurse(symstack,sym,0L,&maxparams,recursion);
assert(size>=0);
if (maxsize<size) if (maxsize<size)
maxsize=size; maxsize=size;
} /* for */ } /* for */
free((void*)symstack);
maxsize++; /* +1 because a zero cell is always pushed on top maxsize++; /* +1 because a zero cell is always pushed on top
* of the stack to catch stack overwrites */ * of the stack to catch stack overwrites */
return maxsize+(maxparams+1);/* +1 because # of parameters is always pushed on entry */ return maxsize+(maxparams+1);/* +1 because # of parameters is always pushed on entry */