diff --git a/include/asm/fstack.h b/include/asm/fstack.h index f3e8a878..627c8325 100644 --- a/include/asm/fstack.h +++ b/include/asm/fstack.h @@ -35,7 +35,7 @@ struct sContext { uint32_t nREPTBlockSize; }; -extern unsigned int nMaxFileStackDepth; +extern unsigned int nMaxRecursionDepth; void fstk_RunInclude(char *tzFileName); void fstk_RunMacroArg(int32_t s); diff --git a/include/asm/lexer.h b/include/asm/lexer.h index 3a86a773..c4e845b5 100644 --- a/include/asm/lexer.h +++ b/include/asm/lexer.h @@ -40,6 +40,13 @@ enum eLexerState { LEX_STATE_MACROARGS }; +struct sStringExpansionPos { + char *tzName; + char *pBuffer; + char *pBufferPos; + struct sStringExpansionPos *pParent; +}; + #define INITIAL 0 #define macroarg 3 @@ -62,6 +69,7 @@ void lex_FloatDeleteSecondRange(uint32_t id, uint16_t start, uint16_t end); void lex_Init(void); void lex_AddStrings(const struct sLexInitString *lex); void lex_SetBuffer(char *buffer, uint32_t len); +void lex_BeginStringExpansion(const char *tzName); int yywrap(void); int yylex(void); void yyunput(char c); @@ -70,6 +78,7 @@ void yyskipbytes(uint32_t count); void yyunputbytes(uint32_t count); extern YY_BUFFER_STATE pCurrentBuffer; +extern struct sStringExpansionPos *pCurrentStringExpansion; void upperstring(char *s); void lowerstring(char *s); diff --git a/src/asm/fstack.c b/src/asm/fstack.c index b471cdd6..fbe1459c 100644 --- a/src/asm/fstack.c +++ b/src/asm/fstack.c @@ -29,7 +29,7 @@ static struct sContext *pFileStack; static unsigned int nFileStackDepth; -unsigned int nMaxFileStackDepth; +unsigned int nMaxRecursionDepth; static struct sSymbol *pCurrentMacro; static YY_BUFFER_STATE CurrentFlexHandle; static FILE *pCurrentFile; @@ -62,8 +62,8 @@ static void pushcontext(void) { struct sContext **ppFileStack; - if (++nFileStackDepth > nMaxFileStackDepth) - fatalerror("Recursion limit (%d) exceeded", nMaxFileStackDepth); + if (++nFileStackDepth > nMaxRecursionDepth) + fatalerror("Recursion limit (%d) exceeded", nMaxRecursionDepth); ppFileStack = &pFileStack; while (*ppFileStack) diff --git a/src/asm/globlex.c b/src/asm/globlex.c index 98786a34..066cd9d1 100644 --- a/src/asm/globlex.c +++ b/src/asm/globlex.c @@ -279,6 +279,8 @@ uint32_t ParseSymbol(char *src, uint32_t size) if (!oDontExpandStrings && sym_isString(dest)) { char *s; + lex_BeginStringExpansion(dest); + /* Feed the symbol's contents into the buffer */ yyunputstr(s = sym_GetStringValue(dest)); diff --git a/src/asm/lexer.c b/src/asm/lexer.c index cdaaaf55..212a1f06 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -51,6 +51,9 @@ uint32_t tFloatingChars[256]; uint32_t nFloating; enum eLexerState lexerstate = LEX_STATE_NORMAL; +struct sStringExpansionPos *pCurrentStringExpansion; +static unsigned int nNbStringExpansions; + /* UTF-8 byte order mark */ static const unsigned char bom[BOM_SIZE] = { 0xEF, 0xBB, 0xBF }; @@ -102,6 +105,31 @@ void yyunputstr(const char *s) 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) { pCurrentBuffer = buf; @@ -424,6 +452,9 @@ void lex_Init(void) nLexMaxLength = 0; nFloating = 0; + + pCurrentStringExpansion = NULL; + nNbStringExpansions = 0; } void lex_AddStrings(const struct sLexInitString *lex) @@ -968,12 +999,30 @@ static uint32_t yylex_MACROARGS(void) int yylex(void) { + int returnedChar; switch (lexerstate) { case LEX_STATE_NORMAL: - return yylex_NORMAL(); + returnedChar = yylex_NORMAL(); + break; case LEX_STATE_MACROARGS: - return yylex_MACROARGS(); + returnedChar = yylex_MACROARGS(); + break; default: 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; } diff --git a/src/asm/main.c b/src/asm/main.c index 0d928e92..a1829347 100644 --- a/src/asm/main.c +++ b/src/asm/main.c @@ -315,7 +315,7 @@ int main(int argc, char *argv[]) /* yydebug=1; */ - nMaxFileStackDepth = 64; + nMaxRecursionDepth = 64; DefaultOptions.gbgfx[0] = '0'; DefaultOptions.gbgfx[1] = '1'; @@ -389,7 +389,7 @@ int main(int argc, char *argv[]) break; case 'r': - nMaxFileStackDepth = strtoul(optarg, &ep, 0); + nMaxRecursionDepth = strtoul(optarg, &ep, 0); if (optarg[0] == '\0' || *ep != '\0') errx(1, "Invalid argument for option 'r'");