mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-21 02:32:06 +00:00
Merge pull request #411 from ISSOtm/recursion_limit
Add a recursion limit
This commit is contained in:
@@ -35,6 +35,8 @@ struct sContext {
|
|||||||
uint32_t nREPTBlockSize;
|
uint32_t nREPTBlockSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern unsigned int nMaxRecursionDepth;
|
||||||
|
|
||||||
void fstk_RunInclude(char *tzFileName);
|
void fstk_RunInclude(char *tzFileName);
|
||||||
void fstk_RunMacroArg(int32_t s);
|
void fstk_RunMacroArg(int32_t s);
|
||||||
void fstk_Init(char *s);
|
void fstk_Init(char *s);
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ enum eLexerState {
|
|||||||
LEX_STATE_MACROARGS
|
LEX_STATE_MACROARGS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sStringExpansionPos {
|
||||||
|
char *tzName;
|
||||||
|
char *pBuffer;
|
||||||
|
char *pBufferPos;
|
||||||
|
struct sStringExpansionPos *pParent;
|
||||||
|
};
|
||||||
|
|
||||||
#define INITIAL 0
|
#define INITIAL 0
|
||||||
#define macroarg 3
|
#define macroarg 3
|
||||||
|
|
||||||
@@ -62,14 +69,16 @@ void lex_FloatDeleteSecondRange(uint32_t id, uint16_t start, uint16_t end);
|
|||||||
void lex_Init(void);
|
void lex_Init(void);
|
||||||
void lex_AddStrings(const struct sLexInitString *lex);
|
void lex_AddStrings(const struct sLexInitString *lex);
|
||||||
void lex_SetBuffer(char *buffer, uint32_t len);
|
void lex_SetBuffer(char *buffer, uint32_t len);
|
||||||
|
void lex_BeginStringExpansion(const char *tzName);
|
||||||
int yywrap(void);
|
int yywrap(void);
|
||||||
int yylex(void);
|
int yylex(void);
|
||||||
void yyunput(char c);
|
void yyunput(char c);
|
||||||
void yyunputstr(char *s);
|
void yyunputstr(const char *s);
|
||||||
void yyskipbytes(uint32_t count);
|
void yyskipbytes(uint32_t count);
|
||||||
void yyunputbytes(uint32_t count);
|
void yyunputbytes(uint32_t count);
|
||||||
|
|
||||||
extern YY_BUFFER_STATE pCurrentBuffer;
|
extern YY_BUFFER_STATE pCurrentBuffer;
|
||||||
|
extern struct sStringExpansionPos *pCurrentStringExpansion;
|
||||||
|
|
||||||
void upperstring(char *s);
|
void upperstring(char *s);
|
||||||
void lowerstring(char *s);
|
void lowerstring(char *s);
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
static struct sContext *pFileStack;
|
static struct sContext *pFileStack;
|
||||||
|
static unsigned int nFileStackDepth;
|
||||||
|
unsigned int nMaxRecursionDepth;
|
||||||
static struct sSymbol *pCurrentMacro;
|
static struct sSymbol *pCurrentMacro;
|
||||||
static YY_BUFFER_STATE CurrentFlexHandle;
|
static YY_BUFFER_STATE CurrentFlexHandle;
|
||||||
static FILE *pCurrentFile;
|
static FILE *pCurrentFile;
|
||||||
@@ -51,6 +53,8 @@ uint32_t ulMacroReturnValue;
|
|||||||
#define STAT_isMacroArg 2
|
#define STAT_isMacroArg 2
|
||||||
#define STAT_isREPTBlock 3
|
#define STAT_isREPTBlock 3
|
||||||
|
|
||||||
|
/* Max context stack size */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Context push and pop
|
* Context push and pop
|
||||||
*/
|
*/
|
||||||
@@ -58,6 +62,9 @@ static void pushcontext(void)
|
|||||||
{
|
{
|
||||||
struct sContext **ppFileStack;
|
struct sContext **ppFileStack;
|
||||||
|
|
||||||
|
if (++nFileStackDepth > nMaxRecursionDepth)
|
||||||
|
fatalerror("Recursion limit (%d) exceeded", nMaxRecursionDepth);
|
||||||
|
|
||||||
ppFileStack = &pFileStack;
|
ppFileStack = &pFileStack;
|
||||||
while (*ppFileStack)
|
while (*ppFileStack)
|
||||||
ppFileStack = &((*ppFileStack)->pNext);
|
ppFileStack = &((*ppFileStack)->pNext);
|
||||||
@@ -154,6 +161,8 @@ static int32_t popcontext(void)
|
|||||||
fatalerror("%s: Internal error.", __func__);
|
fatalerror("%s: Internal error.", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nFileStackDepth--;
|
||||||
|
|
||||||
free(*ppLastFile);
|
free(*ppLastFile);
|
||||||
*ppLastFile = NULL;
|
*ppLastFile = NULL;
|
||||||
yy_switch_to_buffer(CurrentFlexHandle);
|
yy_switch_to_buffer(CurrentFlexHandle);
|
||||||
@@ -413,6 +422,7 @@ void fstk_Init(char *pFileName)
|
|||||||
if (pCurrentFile == NULL)
|
if (pCurrentFile == NULL)
|
||||||
err(1, "Unable to open file '%s'", pFileName);
|
err(1, "Unable to open file '%s'", pFileName);
|
||||||
}
|
}
|
||||||
|
nFileStackDepth = 0;
|
||||||
|
|
||||||
nMacroCount = 0;
|
nMacroCount = 0;
|
||||||
nCurrentStatus = STAT_isInclude;
|
nCurrentStatus = STAT_isInclude;
|
||||||
|
|||||||
@@ -188,11 +188,11 @@ uint32_t ParseNumber(char *s, uint32_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the symbol name ends before the end of the macro arg, return true
|
* If the symbol name ends before the end of the macro arg,
|
||||||
* and point "rest" to the rest of the macro arg.
|
* return a pointer to the rest of the macro arg.
|
||||||
* Otherwise, return false.
|
* Otherwise, return NULL.
|
||||||
*/
|
*/
|
||||||
bool AppendMacroArg(char whichArg, char *dest, size_t *destIndex, char **rest)
|
char *AppendMacroArg(char whichArg, char *dest, size_t *destIndex)
|
||||||
{
|
{
|
||||||
char *marg;
|
char *marg;
|
||||||
|
|
||||||
@@ -222,14 +222,13 @@ bool AppendMacroArg(char whichArg, char *dest, size_t *destIndex, char **rest)
|
|||||||
dest[*destIndex] = ch;
|
dest[*destIndex] = ch;
|
||||||
(*destIndex)++;
|
(*destIndex)++;
|
||||||
} else {
|
} else {
|
||||||
*rest = marg;
|
return marg;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
marg++;
|
marg++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ParseSymbol(char *src, uint32_t size)
|
uint32_t ParseSymbol(char *src, uint32_t size)
|
||||||
@@ -251,7 +250,9 @@ uint32_t ParseSymbol(char *src, uint32_t size)
|
|||||||
*/
|
*/
|
||||||
ch = src[srcIndex++];
|
ch = src[srcIndex++];
|
||||||
|
|
||||||
if (AppendMacroArg(ch, dest, &destIndex, &rest))
|
rest = AppendMacroArg(ch, dest, &destIndex);
|
||||||
|
/* If the symbol's end was in the middle of the token */
|
||||||
|
if (rest)
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
if (destIndex >= MAXSYMLEN)
|
if (destIndex >= MAXSYMLEN)
|
||||||
@@ -262,28 +263,35 @@ uint32_t ParseSymbol(char *src, uint32_t size)
|
|||||||
|
|
||||||
dest[destIndex] = 0;
|
dest[destIndex] = 0;
|
||||||
|
|
||||||
|
/* Tell the lexer we read all bytes that we did */
|
||||||
|
yyskipbytes(srcIndex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If an escape's expansion left some chars after the symbol's end,
|
||||||
|
* such as the `::` in a `Backup\1` expanded to `BackupCamX::`,
|
||||||
|
* put those into the buffer.
|
||||||
|
* Note that this NEEDS to be done after the `yyskipbytes` above.
|
||||||
|
*/
|
||||||
|
if (rest)
|
||||||
|
yyunputstr(rest);
|
||||||
|
|
||||||
|
/* If the symbol is an EQUS, expand it */
|
||||||
if (!oDontExpandStrings && sym_isString(dest)) {
|
if (!oDontExpandStrings && sym_isString(dest)) {
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
yyskipbytes(srcIndex);
|
lex_BeginStringExpansion(dest);
|
||||||
|
|
||||||
if (rest)
|
|
||||||
yyunputstr(rest);
|
|
||||||
|
|
||||||
|
/* Feed the symbol's contents into the buffer */
|
||||||
yyunputstr(s = sym_GetStringValue(dest));
|
yyunputstr(s = sym_GetStringValue(dest));
|
||||||
|
|
||||||
|
/* Lines inserted this way shall not increase nLineNo */
|
||||||
while (*s) {
|
while (*s) {
|
||||||
if (*s++ == '\n')
|
if (*s++ == '\n')
|
||||||
nLineNo -= 1;
|
nLineNo--;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
yyskipbytes(srcIndex);
|
|
||||||
|
|
||||||
if (rest)
|
|
||||||
yyunputstr(rest);
|
|
||||||
|
|
||||||
strcpy(yylval.tzSym, dest);
|
strcpy(yylval.tzSym, dest);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ uint32_t tFloatingChars[256];
|
|||||||
uint32_t nFloating;
|
uint32_t nFloating;
|
||||||
enum eLexerState lexerstate = LEX_STATE_NORMAL;
|
enum eLexerState lexerstate = LEX_STATE_NORMAL;
|
||||||
|
|
||||||
|
struct sStringExpansionPos *pCurrentStringExpansion;
|
||||||
|
static unsigned int nNbStringExpansions;
|
||||||
|
|
||||||
/* UTF-8 byte order mark */
|
/* UTF-8 byte order mark */
|
||||||
static const unsigned char bom[BOM_SIZE] = { 0xEF, 0xBB, 0xBF };
|
static const unsigned char bom[BOM_SIZE] = { 0xEF, 0xBB, 0xBF };
|
||||||
|
|
||||||
@@ -88,17 +91,49 @@ void yyunput(char c)
|
|||||||
*(--pLexBuffer) = c;
|
*(--pLexBuffer) = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void yyunputstr(char *s)
|
void yyunputstr(const char *s)
|
||||||
{
|
{
|
||||||
int32_t i, len;
|
int32_t len;
|
||||||
|
|
||||||
len = strlen(s);
|
len = strlen(s);
|
||||||
|
|
||||||
if (pLexBuffer - len < pLexBufferRealStart)
|
/*
|
||||||
|
* It would be undefined behavior to subtract `len` from pLexBuffer and
|
||||||
|
* potentially have it point outside of pLexBufferRealStart's buffer,
|
||||||
|
* this is why the check is done this way.
|
||||||
|
* Refer to https://github.com/rednex/rgbds/pull/411#discussion_r319779797
|
||||||
|
*/
|
||||||
|
if (pLexBuffer - pLexBufferRealStart < len)
|
||||||
fatalerror("Buffer safety margin exceeded");
|
fatalerror("Buffer safety margin exceeded");
|
||||||
|
|
||||||
for (i = len - 1; i >= 0; i--)
|
pLexBuffer -= len;
|
||||||
*(--pLexBuffer) = s[i];
|
|
||||||
|
memcpy(pLexBuffer, s, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Marks that a new string expansion with name `tzName` ends here
|
||||||
|
* Enforces recursion depth
|
||||||
|
*/
|
||||||
|
void lex_BeginStringExpansion(const char *tzName)
|
||||||
|
{
|
||||||
|
if (++nNbStringExpansions > nMaxRecursionDepth)
|
||||||
|
fatalerror("Recursion limit (%d) exceeded", nMaxRecursionDepth);
|
||||||
|
|
||||||
|
struct sStringExpansionPos *pNewStringExpansion =
|
||||||
|
malloc(sizeof(*pNewStringExpansion));
|
||||||
|
char *tzNewExpansionName = strdup(tzName);
|
||||||
|
|
||||||
|
if (!pNewStringExpansion || !tzNewExpansionName)
|
||||||
|
fatalerror("Could not allocate memory to expand '%s'",
|
||||||
|
tzName);
|
||||||
|
|
||||||
|
pNewStringExpansion->tzName = tzNewExpansionName;
|
||||||
|
pNewStringExpansion->pBuffer = pLexBufferRealStart;
|
||||||
|
pNewStringExpansion->pBufferPos = pLexBuffer;
|
||||||
|
pNewStringExpansion->pParent = pCurrentStringExpansion;
|
||||||
|
|
||||||
|
pCurrentStringExpansion = pNewStringExpansion;
|
||||||
}
|
}
|
||||||
|
|
||||||
void yy_switch_to_buffer(YY_BUFFER_STATE buf)
|
void yy_switch_to_buffer(YY_BUFFER_STATE buf)
|
||||||
@@ -423,6 +458,9 @@ void lex_Init(void)
|
|||||||
|
|
||||||
nLexMaxLength = 0;
|
nLexMaxLength = 0;
|
||||||
nFloating = 0;
|
nFloating = 0;
|
||||||
|
|
||||||
|
pCurrentStringExpansion = NULL;
|
||||||
|
nNbStringExpansions = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lex_AddStrings(const struct sLexInitString *lex)
|
void lex_AddStrings(const struct sLexInitString *lex)
|
||||||
@@ -967,12 +1005,30 @@ static uint32_t yylex_MACROARGS(void)
|
|||||||
|
|
||||||
int yylex(void)
|
int yylex(void)
|
||||||
{
|
{
|
||||||
|
int returnedChar;
|
||||||
switch (lexerstate) {
|
switch (lexerstate) {
|
||||||
case LEX_STATE_NORMAL:
|
case LEX_STATE_NORMAL:
|
||||||
return yylex_NORMAL();
|
returnedChar = yylex_NORMAL();
|
||||||
|
break;
|
||||||
case LEX_STATE_MACROARGS:
|
case LEX_STATE_MACROARGS:
|
||||||
return yylex_MACROARGS();
|
returnedChar = yylex_MACROARGS();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fatalerror("%s: Internal error.", __func__);
|
fatalerror("%s: Internal error.", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if string expansions were fully read */
|
||||||
|
while (pCurrentStringExpansion
|
||||||
|
&& pCurrentStringExpansion->pBuffer == pLexBufferRealStart
|
||||||
|
&& pCurrentStringExpansion->pBufferPos <= pLexBuffer) {
|
||||||
|
struct sStringExpansionPos *pParent =
|
||||||
|
pCurrentStringExpansion->pParent;
|
||||||
|
free(pCurrentStringExpansion->tzName);
|
||||||
|
free(pCurrentStringExpansion);
|
||||||
|
|
||||||
|
pCurrentStringExpansion = pParent;
|
||||||
|
nNbStringExpansions--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnedChar;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -289,7 +289,8 @@ static void print_usage(void)
|
|||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
"usage: rgbasm [-EhLVvw] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
|
"usage: rgbasm [-EhLVvw] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
|
||||||
" [-M dependfile] [-o outfile] [-p pad_value] file.asm\n");
|
" [-M dependfile] [-o outfile] [-p pad_value]\n"
|
||||||
|
" [-r recursion_depth] file.asm\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,6 +317,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
/* yydebug=1; */
|
/* yydebug=1; */
|
||||||
|
|
||||||
|
nMaxRecursionDepth = 64;
|
||||||
|
|
||||||
DefaultOptions.gbgfx[0] = '0';
|
DefaultOptions.gbgfx[0] = '0';
|
||||||
DefaultOptions.gbgfx[1] = '1';
|
DefaultOptions.gbgfx[1] = '1';
|
||||||
DefaultOptions.gbgfx[2] = '2';
|
DefaultOptions.gbgfx[2] = '2';
|
||||||
@@ -333,7 +336,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
newopt = CurrentOptions;
|
newopt = CurrentOptions;
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "b:D:Eg:hi:LM:o:p:Vvw")) != -1) {
|
while ((ch = getopt(argc, argv, "b:D:Eg:hi:LM:o:p:r:Vvw")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'b':
|
case 'b':
|
||||||
if (strlen(optarg) == 2) {
|
if (strlen(optarg) == 2) {
|
||||||
@@ -387,6 +390,12 @@ int main(int argc, char *argv[])
|
|||||||
errx(1, "Argument for option 'p' must be between 0 and 0xFF");
|
errx(1, "Argument for option 'p' must be between 0 and 0xFF");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
nMaxRecursionDepth = strtoul(optarg, &ep, 0);
|
||||||
|
|
||||||
|
if (optarg[0] == '\0' || *ep != '\0')
|
||||||
|
errx(1, "Invalid argument for option 'r'");
|
||||||
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
printf("rgbasm %s\n", get_package_version_string());
|
printf("rgbasm %s\n", get_package_version_string());
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
.Op Fl M Ar dependfile
|
.Op Fl M Ar dependfile
|
||||||
.Op Fl o Ar outfile
|
.Op Fl o Ar outfile
|
||||||
.Op Fl p Ar pad_value
|
.Op Fl p Ar pad_value
|
||||||
|
.Op Fl r Ar recursion_depth
|
||||||
.Ar file
|
.Ar file
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
@@ -77,6 +78,8 @@ Write an object file to the given filename.
|
|||||||
.It Fl p Ar pad_value
|
.It Fl p Ar pad_value
|
||||||
When padding an image, pad with this value.
|
When padding an image, pad with this value.
|
||||||
The default is 0x00.
|
The default is 0x00.
|
||||||
|
.It Fl r Ar recursion_depth
|
||||||
|
Specifies the recursion depth at which RGBASM will assume being in an infinite loop.
|
||||||
.It Fl V
|
.It Fl V
|
||||||
Print the version of the program and exit.
|
Print the version of the program and exit.
|
||||||
.It Fl v
|
.It Fl v
|
||||||
|
|||||||
@@ -455,8 +455,7 @@ String equates can't be exported or imported.
|
|||||||
.Sy Important note :
|
.Sy Important note :
|
||||||
An EQUS can be expanded to a string that contains another EQUS
|
An EQUS can be expanded to a string that contains another EQUS
|
||||||
and it will be expanded as well.
|
and it will be expanded as well.
|
||||||
This means that, if you aren't careful, you may trap the assembler into an
|
If this creates an infinite loop, RGBASM will error out once a certain depth is reached. See the -r command-line option.
|
||||||
infinite loop if there's a circular dependency in the expansions.
|
|
||||||
Also, a MACRO can have inside an EQUS which references the same MACRO, which has
|
Also, a MACRO can have inside an EQUS which references the same MACRO, which has
|
||||||
the same problem.
|
the same problem.
|
||||||
.Pp
|
.Pp
|
||||||
|
|||||||
2
test/asm/equs-recursion.asm
Normal file
2
test/asm/equs-recursion.asm
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
recurse EQUS "recurse"
|
||||||
|
recurse
|
||||||
2
test/asm/equs-recursion.out
Normal file
2
test/asm/equs-recursion.out
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: equs-recursion.asm(2):
|
||||||
|
Recursion limit (64) exceeded
|
||||||
2
test/asm/equs-recursion.out.pipe
Normal file
2
test/asm/equs-recursion.out.pipe
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: -(2):
|
||||||
|
Recursion limit (64) exceeded
|
||||||
1
test/asm/include-recursion.asm
Normal file
1
test/asm/include-recursion.asm
Normal file
@@ -0,0 +1 @@
|
|||||||
|
INCLUDE "include-recursion.asm"
|
||||||
2
test/asm/include-recursion.out
Normal file
2
test/asm/include-recursion.out
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1):
|
||||||
|
Recursion limit (64) exceeded
|
||||||
2
test/asm/include-recursion.out.pipe
Normal file
2
test/asm/include-recursion.out.pipe
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: -(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1) -> include-recursion.asm(1):
|
||||||
|
Recursion limit (64) exceeded
|
||||||
4
test/asm/macro-recursion.asm
Normal file
4
test/asm/macro-recursion.asm
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
recurse: MACRO
|
||||||
|
recurse
|
||||||
|
ENDM
|
||||||
|
recurse
|
||||||
2
test/asm/macro-recursion.out
Normal file
2
test/asm/macro-recursion.out
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: macro-recursion.asm(4) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1):
|
||||||
|
Recursion limit (64) exceeded
|
||||||
2
test/asm/macro-recursion.out.pipe
Normal file
2
test/asm/macro-recursion.out.pipe
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: -(4) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1) -> recurse(1):
|
||||||
|
Recursion limit (64) exceeded
|
||||||
Reference in New Issue
Block a user