Fix crash when no macro args are being used

This commit is contained in:
ISSOtm
2020-08-02 14:08:26 +02:00
parent 81a77a9b88
commit adcaf4cd46
2 changed files with 61 additions and 57 deletions

View File

@@ -553,7 +553,7 @@ static void beginExpansion(size_t distance, uint8_t skip,
#define LOOKUP_PRE_NEST(exp) (exp)->totalLen += size #define LOOKUP_PRE_NEST(exp) (exp)->totalLen += size
#define LOOKUP_POST_NEST(exp) do { \ #define LOOKUP_POST_NEST(exp) do { \
if (++depth >= nMaxRecursionDepth) \ if (name && ++depth >= nMaxRecursionDepth) \
fatalerror("Recursion limit (%u) exceeded\n", nMaxRecursionDepth); \ fatalerror("Recursion limit (%u) exceeded\n", nMaxRecursionDepth); \
} while (0) } while (0)
lookupExpansion(parent, distance); lookupExpansion(parent, distance);
@@ -570,7 +570,7 @@ static void beginExpansion(size_t distance, uint8_t skip,
fatalerror("Unable to allocate new expansion: %s\n", strerror(errno)); fatalerror("Unable to allocate new expansion: %s\n", strerror(errno));
(*insertPoint)->firstChild = NULL; (*insertPoint)->firstChild = NULL;
(*insertPoint)->next = NULL; /* Expansions are always performed left to right */ (*insertPoint)->next = NULL; /* Expansions are always performed left to right */
(*insertPoint)->name = strdup(name); (*insertPoint)->name = name ? strdup(name) : NULL;
(*insertPoint)->contents = str; (*insertPoint)->contents = str;
(*insertPoint)->len = size; (*insertPoint)->len = size;
(*insertPoint)->totalLen = size; (*insertPoint)->totalLen = size;
@@ -596,6 +596,21 @@ static void freeExpansion(struct Expansion *expansion)
free(expansion); free(expansion);
} }
static char const *expandMacroArg(char name, size_t distance)
{
char const *str;
if (name == '@')
str = macro_GetUniqueIDStr();
else
str = macro_GetArg(name - '0');
if (!str)
fatalerror("Macro argument '\\%c' not defined\n", name);
beginExpansion(distance, 2, str, strlen(str), NULL);
return str;
}
/* If at any point we need more than 255 characters of lookahead, something went VERY wrong. */ /* If at any point we need more than 255 characters of lookahead, something went VERY wrong. */
static int peek(uint8_t distance) static int peek(uint8_t distance)
{ {
@@ -623,27 +638,23 @@ static int peek(uint8_t distance)
* avoid that duplication. If you have any ideas, please discuss them in an issue or * avoid that duplication. If you have any ideas, please discuss them in an issue or
* pull request. Thank you! * pull request. Thank you!
*/ */
unsigned char c = lexerState->ptr[lexerState->offset + distance];
/* Do not perform expansions while capturing */ /* If not capturing and character is a backslash, check for a macro arg */
if (!lexerState->capturing) { if (!lexerState->capturing && c == '\\') {
/* Scan the new chars for any macro args */ /* We need to read the following character, so check if that's possible */
#define BUF_OFS (lexerState->offset + lexerState->nbChars) if (lexerState->offset + distance + 1 < lexerState->size) {
while (lexerState->nbChars <= distance) { c = lexerState->ptr[lexerState->offset + distance + 1];
char c = lexerState->ptr[BUF_OFS]; if (c == '@' || (c >= '1' && c <= '9'))
/* Expand the argument and return its first character */
lexerState->nbChars++; c = expandMacroArg(c, distance)[0];
if (c == '\\') { /* WARNING: this assumes macro args can't be empty!! */
if (lexerState->size <= BUF_OFS) else
break; /* This was the last char in the buffer */ c = '\\';
c = lexerState->ptr[BUF_OFS];
lexerState->nbChars++;
if ((c >= '1' && c <= '9') || c == '@')
fatalerror("Macro arg expansion is not implemented yet\n");
}
} }
} }
return (unsigned char)lexerState->ptr[lexerState->offset + distance]; return c;
} }
if (lexerState->nbChars <= distance) { if (lexerState->nbChars <= distance) {
@@ -677,45 +688,29 @@ static int peek(uint8_t distance)
#undef readChars #undef readChars
/* Do not perform expansions when capturing */
if (!lexerState->capturing) {
/* Scan the newly-inserted chars for any macro args */
bool escaped = false;
size_t index = (lexerState->index + lexerState->nbChars) % LEXER_BUF_SIZE;
for (ssize_t i = 0; i < totalCharsRead; i++) {
char c = lexerState->buf[index++];
if (escaped) {
escaped = false;
if ((c >= '1' && c <= '9') || c == '@')
fatalerror("Macro arg expansion is not implemented yet\n");
} else if (c == '\\') {
escaped = true;
}
if (index == LEXER_BUF_SIZE) /* Wrap around buffer */
index = 0;
}
/*
* If last char read was a backslash, pretend we didn't read it; this is
* important, otherwise we may miss an expansion that straddles refills
*/
if (escaped) {
totalCharsRead--;
/* However, if that prevents having enough characters, error out */
if (lexerState->nbChars + totalCharsRead <= distance)
fatalerror("Internal lexer error: cannot read far enough due to backslash\n");
}
}
lexerState->nbChars += totalCharsRead; lexerState->nbChars += totalCharsRead;
/* If there aren't enough chars even after refilling, give up */ /* If there aren't enough chars even after refilling, give up */
if (lexerState->nbChars <= distance) if (lexerState->nbChars <= distance)
return EOF; return EOF;
} }
return (unsigned char)lexerState->buf[(lexerState->index + distance) % LEXER_BUF_SIZE]; unsigned char c = lexerState->buf[(lexerState->index + distance) % LEXER_BUF_SIZE];
/* If not capturing and character is a backslash, check for a macro arg */
if (!lexerState->capturing && c == '\\') {
/* We need to read the character at `distance + 1`, so check if that's possible */
if (lexerState->nbChars == distance + 1) /* We know that ...->nbChars > distance */
fatalerror("Internal lexer error: not enough lookahead for macro arg check\n");
c = lexerState->buf[(lexerState->index + distance + 1) % LEXER_BUF_SIZE];
if (c == '@' || (c >= '1' && c <= '9'))
/* Expand the argument and return its first character */
c = expandMacroArg(c, distance)[0];
/* WARNING: this assumes macro args can't be empty!! */
else
c = '\\';
}
return c;
} }
static void shiftChars(uint8_t distance) static void shiftChars(uint8_t distance)
@@ -775,13 +770,13 @@ nextExpansion:
lexerState->offset += distance; lexerState->offset += distance;
} else { } else {
lexerState->index += distance; lexerState->index += distance;
lexerState->colNo += distance;
/* Wrap around if necessary */ /* Wrap around if necessary */
if (lexerState->index >= LEXER_BUF_SIZE) if (lexerState->index >= LEXER_BUF_SIZE)
lexerState->index %= LEXER_BUF_SIZE; lexerState->index %= LEXER_BUF_SIZE;
} }
lexerState->nbChars -= distance; lexerState->nbChars -= distance;
lexerState->colNo += distance;
} }
static int nextChar(void) static int nextChar(void)
@@ -816,12 +811,17 @@ void lexer_DumpStringExpansions(void)
if (!lexerState) if (!lexerState)
return; return;
struct Expansion *stack[nMaxRecursionDepth + 1]; struct Expansion *stack[nMaxRecursionDepth + 1];
struct Expansion *expansion;
unsigned int depth = 0; unsigned int depth = 0;
size_t distance = lexerState->expansionOfs; size_t distance = lexerState->expansionOfs;
#define LOOKUP_PRE_NEST(exp) #define LOOKUP_PRE_NEST(exp) do { \
/* Only register EQUS expansions, not string args */ \
if (expansion->name) \
stack[depth++] = expansion; \
} while (0)
#define LOOKUP_POST_NEST(exp) #define LOOKUP_POST_NEST(exp)
lookupExpansion(stack[depth++], distance); lookupExpansion(expansion, distance);
#undef LOOKUP_PRE_NEST #undef LOOKUP_PRE_NEST
#undef LOOKUP_POST_NEST #undef LOOKUP_POST_NEST
@@ -1513,8 +1513,9 @@ static int yylex_RAW(void)
case '\r': case '\r':
case '\n': /* Do not shift these! */ case '\n': /* Do not shift these! */
case EOF: case EOF:
if (c != ',') /* Empty macro args break their expansion, so prevent that */
lexer_SetMode(LEXER_NORMAL); if (i == 0)
return c;
if (i == sizeof(yylval.tzString)) { if (i == sizeof(yylval.tzString)) {
i--; i--;
warning(WARNING_LONG_STR, "Macro argument too long\n"); warning(WARNING_LONG_STR, "Macro argument too long\n");

View File

@@ -89,6 +89,9 @@ void macro_FreeArgs(struct MacroArgs *args)
char const *macro_GetArg(uint32_t i) char const *macro_GetArg(uint32_t i)
{ {
if (!macroArgs)
return NULL;
uint32_t realIndex = i + macroArgs->shift - 1; uint32_t realIndex = i + macroArgs->shift - 1;
return realIndex >= macroArgs->nbArgs ? NULL return realIndex >= macroArgs->nbArgs ? NULL