From 89eda89838755902482a0e6619dea77c06fd64a9 Mon Sep 17 00:00:00 2001 From: dbrotz <43593771+dbrotz@users.noreply.github.com> Date: Mon, 9 Sep 2019 12:25:26 -0700 Subject: [PATCH 1/2] Handle tabs after backslash at end of file Commit 6fbb25c added support for tabs between a \ and the newline it escapes, but yy_create_buffer() was not updated to handle tabs. --- src/asm/lexer.c | 5 +++-- test/asm/line-continuation-whitespace.asm | 7 +++++++ test/asm/line-continuation-whitespace.out | 0 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 test/asm/line-continuation-whitespace.asm create mode 100644 test/asm/line-continuation-whitespace.out diff --git a/src/asm/lexer.c b/src/asm/lexer.c index e5fd594e..918bf86e 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -325,8 +325,9 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f) if (pBuffer->nBufferSize >= 2) { size_t pos = pBuffer->nBufferSize - 2; - /* Skip spaces */ - while (pos > 0 && pBuffer->pBufferStart[pos] == ' ') + /* Skip spaces and tabs */ + while (pos > 0 && (pBuffer->pBufferStart[pos] == ' ' + || pBuffer->pBufferStart[pos] == '\t')) pos--; if (pBuffer->pBufferStart[pos] == '\\') diff --git a/test/asm/line-continuation-whitespace.asm b/test/asm/line-continuation-whitespace.asm new file mode 100644 index 00000000..0d00dc8f --- /dev/null +++ b/test/asm/line-continuation-whitespace.asm @@ -0,0 +1,7 @@ +; Test that \ followed by whitespace after a macro invocation at the end of the +; file doesn't cause a segfault. + +bar: MACRO +ENDM + +foo bar baz\ diff --git a/test/asm/line-continuation-whitespace.out b/test/asm/line-continuation-whitespace.out new file mode 100644 index 00000000..e69de29b From f36a3d5b2aab0fdfa9a1db0a10bc58677f18ac80 Mon Sep 17 00:00:00 2001 From: dbrotz <43593771+dbrotz@users.noreply.github.com> Date: Tue, 10 Sep 2019 03:03:04 -0700 Subject: [PATCH 2/2] Fix macro and rept buffer overflows Macro and rept buffers were not always being terminated with newlines and/or were vulnerable to the final newline being escaped, allowing buffer overflows to occur. Now, they are terminated with newlines using the same mechanism as the file buffer. --- src/asm/asmy.y | 5 ++- src/asm/lexer.c | 52 ++++++++++++++++------------ test/asm/line-continuation-macro.asm | 7 ++++ test/asm/line-continuation-macro.out | 0 test/asm/line-continuation-rept.asm | 8 +++++ test/asm/line-continuation-rept.out | 0 6 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 test/asm/line-continuation-macro.asm create mode 100644 test/asm/line-continuation-macro.out create mode 100644 test/asm/line-continuation-rept.asm create mode 100644 test/asm/line-continuation-rept.out diff --git a/src/asm/asmy.y b/src/asm/asmy.y index 35dec3c4..ff8d0fcf 100644 --- a/src/asm/asmy.y +++ b/src/asm/asmy.y @@ -274,14 +274,13 @@ static void copymacro(void) src = pCurrentBuffer->pBuffer; ulNewMacroSize = len; - tzNewMacro = (char *)malloc(ulNewMacroSize+2); + tzNewMacro = (char *)malloc(ulNewMacroSize + 1); if (tzNewMacro == NULL) fatalerror("Not enough memory for MACRO definition."); uint32_t i; - tzNewMacro[ulNewMacroSize] = '\n'; - tzNewMacro[ulNewMacroSize+1] = 0; + tzNewMacro[ulNewMacroSize] = 0; for (i = 0; i < ulNewMacroSize; i += 1) { tzNewMacro[i] = src[i]; if (src[i] == '\n') diff --git a/src/asm/lexer.c b/src/asm/lexer.c index 918bf86e..349a604d 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -158,7 +158,7 @@ void yy_delete_buffer(YY_BUFFER_STATE buf) * 2. The buffer is terminated with 0 * 3. nBufferSize is the size without the terminator */ -static void yy_buffer_append(YY_BUFFER_STATE buf, uint32_t capacity, char c) +static void yy_buffer_append(YY_BUFFER_STATE buf, size_t capacity, char c) { assert(buf->pBufferStart[buf->nBufferSize] == 0); assert(buf->nBufferSize + 1 < capacity); @@ -167,6 +167,27 @@ static void yy_buffer_append(YY_BUFFER_STATE buf, uint32_t capacity, char c) buf->pBufferStart[buf->nBufferSize] = 0; } +static void yy_buffer_append_newlines(YY_BUFFER_STATE buf, size_t capacity) +{ + /* Add newline if file doesn't end with one */ + if (buf->nBufferSize == 0 + || buf->pBufferStart[buf->nBufferSize - 1] != '\n') + yy_buffer_append(buf, capacity, '\n'); + + /* Add newline if \ will eat the last newline */ + if (buf->nBufferSize >= 2) { + size_t pos = buf->nBufferSize - 2; + + /* Skip spaces and tabs */ + while (pos > 0 && (buf->pBufferStart[pos] == ' ' + || buf->pBufferStart[pos] == '\t')) + pos--; + + if (buf->pBufferStart[pos] == '\\') + yy_buffer_append(buf, capacity, '\n'); + } +} + YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size) { YY_BUFFER_STATE pBuffer = malloc(sizeof(struct yy_buffer_state)); @@ -174,7 +195,9 @@ YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size) if (pBuffer == NULL) fatalerror("%s: Out of memory!", __func__); - pBuffer->pBufferRealStart = malloc(size + 1 + SAFETYMARGIN); + size_t capacity = size + 3; /* space for 2 newlines and terminator */ + + pBuffer->pBufferRealStart = malloc(capacity + SAFETYMARGIN); if (pBuffer->pBufferRealStart == NULL) fatalerror("%s: Out of memory for buffer!", __func__); @@ -182,9 +205,10 @@ YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size) pBuffer->pBufferStart = pBuffer->pBufferRealStart + SAFETYMARGIN; pBuffer->pBuffer = pBuffer->pBufferRealStart + SAFETYMARGIN; memcpy(pBuffer->pBuffer, mem, size); - pBuffer->nBufferSize = size; - pBuffer->oAtLineStart = 1; pBuffer->pBuffer[size] = 0; + pBuffer->nBufferSize = size; + yy_buffer_append_newlines(pBuffer, capacity); + pBuffer->oAtLineStart = 1; return pBuffer; } @@ -257,7 +281,7 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f) /* This is added here to make the buffer scaling above easy to express, * while taking the newline space into account - * for the `yy_buffer_append`s below. + * for the yy_buffer_append_newlines() call below. */ capacity += 3; @@ -317,23 +341,7 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f) } } - /* Add newline if file doesn't end with one */ - if (size == 0 || pBuffer->pBufferStart[size - 1] != '\n') - yy_buffer_append(pBuffer, capacity, '\n'); - - /* Add newline if \ will eat the last newline */ - if (pBuffer->nBufferSize >= 2) { - size_t pos = pBuffer->nBufferSize - 2; - - /* Skip spaces and tabs */ - while (pos > 0 && (pBuffer->pBufferStart[pos] == ' ' - || pBuffer->pBufferStart[pos] == '\t')) - pos--; - - if (pBuffer->pBufferStart[pos] == '\\') - yy_buffer_append(pBuffer, capacity, '\n'); - } - + yy_buffer_append_newlines(pBuffer, capacity); pBuffer->oAtLineStart = 1; return pBuffer; } diff --git a/test/asm/line-continuation-macro.asm b/test/asm/line-continuation-macro.asm new file mode 100644 index 00000000..b6b40907 --- /dev/null +++ b/test/asm/line-continuation-macro.asm @@ -0,0 +1,7 @@ +m: MACRO +ENDM + +m2: MACRO + m \ ENDM + + m2 diff --git a/test/asm/line-continuation-macro.out b/test/asm/line-continuation-macro.out new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/line-continuation-rept.asm b/test/asm/line-continuation-rept.asm new file mode 100644 index 00000000..90a354ad --- /dev/null +++ b/test/asm/line-continuation-rept.asm @@ -0,0 +1,8 @@ +m: MACRO +ENDM + +REPT 1 + m ENDR + +REPT 1 + m \ ENDR diff --git a/test/asm/line-continuation-rept.out b/test/asm/line-continuation-rept.out new file mode 100644 index 00000000..e69de29b