From 20f949289927024e8f64542996af7a4592d437b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20K=C4=85dzio=C5=82ka?= Date: Sun, 3 Mar 2019 23:27:53 +0100 Subject: [PATCH 1/5] Allow using - to indicate input from stdin --- src/asm/fstack.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/asm/fstack.c b/src/asm/fstack.c index 2d5d4cc2..3035ab7c 100644 --- a/src/asm/fstack.c +++ b/src/asm/fstack.c @@ -405,23 +405,25 @@ void fstk_RunRept(uint32_t count) /* * Initialize the filestack routines */ -void fstk_Init(char *s) +void fstk_Init(char *pFileName) { - char tzFileName[_MAX_PATH + 1]; char tzSymFileName[_MAX_PATH + 1 + 2]; - snprintf(tzSymFileName, sizeof(tzSymFileName), "\"%s\"", s); + snprintf(tzSymFileName, sizeof(tzSymFileName), "\"%s\"", pFileName); sym_AddString("__FILE__", tzSymFileName); - strcpy(tzFileName, s); pFileStack = NULL; - pCurrentFile = fopen(tzFileName, "rb"); - if (pCurrentFile == NULL) - err(1, "Unable to open file '%s'", tzFileName); + if (strcmp(pFileName, "-") == 0) { + pCurrentFile = stdin; + } else { + pCurrentFile = fopen(pFileName, "rb"); + if (pCurrentFile == NULL) + err(1, "Unable to open file '%s'", pFileName); + } nMacroCount = 0; nCurrentStatus = STAT_isInclude; - snprintf(tzCurrentFileName, _MAX_PATH + 1, "%s", tzFileName); + snprintf(tzCurrentFileName, _MAX_PATH + 1, "%s", pFileName); CurrentFlexHandle = yy_create_buffer(pCurrentFile); yy_switch_to_buffer(CurrentFlexHandle); nLineNo = 1; From 8d5a53f52950638b4234ce411529ca45f04aad16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20K=C4=85dzio=C5=82ka?= Date: Wed, 5 Jun 2019 20:25:24 +0200 Subject: [PATCH 2/5] Handle non-seekable input correctly --- include/asm/lexer.h | 2 +- src/asm/lexer.c | 36 +++++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/include/asm/lexer.h b/include/asm/lexer.h index b69fc55e..94c2affa 100644 --- a/include/asm/lexer.h +++ b/include/asm/lexer.h @@ -31,7 +31,7 @@ struct yy_buffer_state { /* Address where the data is initially written after a safety margin */ char *pBufferStart; char *pBuffer; - uint32_t nBufferSize; + size_t nBufferSize; uint32_t oAtLineStart; }; diff --git a/src/asm/lexer.c b/src/asm/lexer.c index c339bf49..dbc2c40e 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -156,25 +156,39 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f) if (pBuffer == NULL) fatalerror("%s: Out of memory!", __func__); - uint32_t size; + size_t size = 0, capacity; + char *buf = NULL; fseek(f, 0, SEEK_END); - size = ftell(f); - fseek(f, 0, SEEK_SET); + capacity = ftell(f); + rewind(f); - /* Give extra room for 2 newlines and terminator */ - uint32_t capacity = size + 3; + if (capacity == -1) + capacity = 4096; - pBuffer->pBufferRealStart = malloc(capacity + SAFETYMARGIN); + while (!feof(f)) { + if (buf == NULL || size >= capacity) { + capacity *= 2; + /* Give extra room for 2 newlines and terminator */ + buf = realloc(buf, capacity + SAFETYMARGIN + 3); - if (pBuffer->pBufferRealStart == NULL) - fatalerror("%s: Out of memory for buffer!", __func__); + if (buf == NULL) + fatalerror("%s: Out of memory for buffer!", + __func__); + } - pBuffer->pBufferStart = pBuffer->pBufferRealStart + SAFETYMARGIN; - pBuffer->pBuffer = pBuffer->pBufferRealStart + SAFETYMARGIN; + char *bufpos = buf + SAFETYMARGIN + size; + size_t read_count = fread(bufpos, 1, capacity - size, f); - size = fread(pBuffer->pBuffer, sizeof(uint8_t), size, f); + if (read_count == 0) + fatalerror("%s: fread error", __func__); + size += read_count; + } + + pBuffer->pBufferRealStart = buf; + pBuffer->pBufferStart = buf + SAFETYMARGIN; + pBuffer->pBuffer = buf + SAFETYMARGIN; pBuffer->pBuffer[size] = 0; pBuffer->nBufferSize = size; From f7bc61e874ebde2e29dad4075ab3834d78998df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20K=C4=85dzio=C5=82ka?= Date: Wed, 5 Jun 2019 20:48:27 +0200 Subject: [PATCH 3/5] Automatic tests for input from stdin --- test/asm/bank-noexist.out.pipe | 0 test/asm/divzero-instr.out.pipe | 2 ++ test/asm/divzero-section-bank.out.pipe | 4 +++ test/asm/equ-charmap.out.pipe | 0 test/asm/label-redefinition.out.pipe | 3 ++ test/asm/line-continuation.out.pipe | 2 ++ test/asm/local-wrong-parent.out.pipe | 3 ++ test/asm/macro-@.out.pipe | 2 ++ test/asm/narg-decreases-after-shift.out.pipe | 0 test/asm/null-in-macro.out.pipe | 2 ++ test/asm/reference-undefined-sym.out.pipe | 3 ++ test/asm/remote-local-explicit.out.pipe | 0 test/asm/remote-local-noexist.out.pipe | 2 ++ test/asm/remote-local.out.pipe | 0 test/asm/strlen.out.pipe | 2 ++ test/asm/strsub.out.pipe | 31 ++++++++++++++++++++ test/asm/test.sh | 29 +++++++++++------- test/asm/undefined-dot.out.pipe | 1 + test/asm/utf-8.out.pipe | 0 19 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 test/asm/bank-noexist.out.pipe create mode 100644 test/asm/divzero-instr.out.pipe create mode 100644 test/asm/divzero-section-bank.out.pipe create mode 100644 test/asm/equ-charmap.out.pipe create mode 100644 test/asm/label-redefinition.out.pipe create mode 100644 test/asm/line-continuation.out.pipe create mode 100644 test/asm/local-wrong-parent.out.pipe create mode 100644 test/asm/macro-@.out.pipe create mode 100644 test/asm/narg-decreases-after-shift.out.pipe create mode 100644 test/asm/null-in-macro.out.pipe create mode 100644 test/asm/reference-undefined-sym.out.pipe create mode 100644 test/asm/remote-local-explicit.out.pipe create mode 100644 test/asm/remote-local-noexist.out.pipe create mode 100644 test/asm/remote-local.out.pipe create mode 100644 test/asm/strlen.out.pipe create mode 100644 test/asm/strsub.out.pipe create mode 100644 test/asm/undefined-dot.out.pipe create mode 100644 test/asm/utf-8.out.pipe diff --git a/test/asm/bank-noexist.out.pipe b/test/asm/bank-noexist.out.pipe new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/divzero-instr.out.pipe b/test/asm/divzero-instr.out.pipe new file mode 100644 index 00000000..6a9391a4 --- /dev/null +++ b/test/asm/divzero-instr.out.pipe @@ -0,0 +1,2 @@ +ERROR: -(2): + Division by zero diff --git a/test/asm/divzero-section-bank.out.pipe b/test/asm/divzero-section-bank.out.pipe new file mode 100644 index 00000000..51764978 --- /dev/null +++ b/test/asm/divzero-section-bank.out.pipe @@ -0,0 +1,4 @@ +ERROR: -(1): + Invalid integer constant +ERROR: -(1): + Division by zero diff --git a/test/asm/equ-charmap.out.pipe b/test/asm/equ-charmap.out.pipe new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/label-redefinition.out.pipe b/test/asm/label-redefinition.out.pipe new file mode 100644 index 00000000..ef695055 --- /dev/null +++ b/test/asm/label-redefinition.out.pipe @@ -0,0 +1,3 @@ +ERROR: -(7): + 'Sym' already defined in m(6) +error: Assembly aborted (1 errors)! diff --git a/test/asm/line-continuation.out.pipe b/test/asm/line-continuation.out.pipe new file mode 100644 index 00000000..75ca5841 --- /dev/null +++ b/test/asm/line-continuation.out.pipe @@ -0,0 +1,2 @@ +ERROR: -(2) -> @(-1): + Macro '@' not defined diff --git a/test/asm/local-wrong-parent.out.pipe b/test/asm/local-wrong-parent.out.pipe new file mode 100644 index 00000000..220ddf9e --- /dev/null +++ b/test/asm/local-wrong-parent.out.pipe @@ -0,0 +1,3 @@ +ERROR: -(5): + Not currently in the scope of 'WrongParent' +error: Assembly aborted (1 errors)! diff --git a/test/asm/macro-@.out.pipe b/test/asm/macro-@.out.pipe new file mode 100644 index 00000000..725c38be --- /dev/null +++ b/test/asm/macro-@.out.pipe @@ -0,0 +1,2 @@ +ERROR: -(1) -> @(-1): + Macro '@' not defined diff --git a/test/asm/narg-decreases-after-shift.out.pipe b/test/asm/narg-decreases-after-shift.out.pipe new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/null-in-macro.out.pipe b/test/asm/null-in-macro.out.pipe new file mode 100644 index 00000000..f3f8d1fb --- /dev/null +++ b/test/asm/null-in-macro.out.pipe @@ -0,0 +1,2 @@ +ERROR: -(1): + Unterminated MACRO definition. diff --git a/test/asm/reference-undefined-sym.out.pipe b/test/asm/reference-undefined-sym.out.pipe new file mode 100644 index 00000000..dae036c0 --- /dev/null +++ b/test/asm/reference-undefined-sym.out.pipe @@ -0,0 +1,3 @@ +ERROR: -(4): + 'X' already referenced at -(2) +error: Assembly aborted (1 errors)! diff --git a/test/asm/remote-local-explicit.out.pipe b/test/asm/remote-local-explicit.out.pipe new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/remote-local-noexist.out.pipe b/test/asm/remote-local-noexist.out.pipe new file mode 100644 index 00000000..c096a468 --- /dev/null +++ b/test/asm/remote-local-noexist.out.pipe @@ -0,0 +1,2 @@ +ERROR: -(7): + 'Parent.child.fail' is a nonsensical reference to a nested local symbol diff --git a/test/asm/remote-local.out.pipe b/test/asm/remote-local.out.pipe new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/strlen.out.pipe b/test/asm/strlen.out.pipe new file mode 100644 index 00000000..18620f97 --- /dev/null +++ b/test/asm/strlen.out.pipe @@ -0,0 +1,2 @@ +$3 +$4 diff --git a/test/asm/strsub.out.pipe b/test/asm/strsub.out.pipe new file mode 100644 index 00000000..15e474cf --- /dev/null +++ b/test/asm/strsub.out.pipe @@ -0,0 +1,31 @@ +warning: -(13) -> xstrsub(1): + STRSUB: Length too big: 32 +warning: -(14) -> xstrsub(1): + STRSUB: Length too big: 300 +warning: -(15) -> xstrsub(1): + STRSUB: Position starts at 1 +warning: -(15) -> xstrsub(1): + STRSUB: Length too big: 300 +warning: -(16) -> xstrsub(1): + STRSUB: Position 4 is past the end of the string +warning: -(17) -> xstrsub(1): + STRSUB: Position 4 is past the end of the string +warning: -(17) -> xstrsub(1): + STRSUB: Length too big: 1 +warning: -(20) -> xstrsub(1): + STRSUB: Length too big: 10 +A +B +C +AB +BC +BC +BC +ABC + + +カタ +カナ +カナ +g +g̈ diff --git a/test/asm/test.sh b/test/asm/test.sh index cfd127df..da050652 100755 --- a/test/asm/test.sh +++ b/test/asm/test.sh @@ -6,18 +6,25 @@ after=$(mktemp) rc=0 for i in *.asm; do - ../../rgbasm -o $o $i > $after 2>&1 - diff -u ${i%.asm}.out $after - rc=$(($? || $rc)) - bin=${i%.asm}.out.bin - if [ -f $bin ]; then - ../../rgblink -o $gb $o > $after 2>&1 - head -c $(wc -c < $bin) $gb > $after 2>&1 - hexdump -C $after > $before && mv $before $after - hexdump -C $bin > $before - diff -u $before $after + for variant in '' '.pipe'; do + if [ -z "$variant" ]; then + ../../rgbasm -o $o $i > $after 2>&1 + else + cat $i | ../../rgbasm -o $o - > $after 2>&1 + fi + + diff -u ${i%.asm}.out$variant $after rc=$(($? || $rc)) - fi + bin=${i%.asm}.out.bin + if [ -f $bin ]; then + ../../rgblink -o $gb $o > $after 2>&1 + head -c $(wc -c < $bin) $gb > $after 2>&1 + hexdump -C $after > $before && mv $before $after + hexdump -C $bin > $before + diff -u $before $after + rc=$(($? || $rc)) + fi + done done rm -f $o $gb $before $after diff --git a/test/asm/undefined-dot.out.pipe b/test/asm/undefined-dot.out.pipe new file mode 100644 index 00000000..888222b3 --- /dev/null +++ b/test/asm/undefined-dot.out.pipe @@ -0,0 +1 @@ +error: -(3) : '.' not defined diff --git a/test/asm/utf-8.out.pipe b/test/asm/utf-8.out.pipe new file mode 100644 index 00000000..e69de29b From 0d97b5826534055fd224c61178b483c9c37f2c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20K=C4=85dzio=C5=82ka?= Date: Wed, 3 Jul 2019 15:37:17 +0200 Subject: [PATCH 4/5] Avoid potentially implementation-defined behavior when using a pipe as input --- src/asm/lexer.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/asm/lexer.c b/src/asm/lexer.c index dbc2c40e..ab22fa77 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -156,13 +156,32 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f) if (pBuffer == NULL) fatalerror("%s: Out of memory!", __func__); - size_t size = 0, capacity; + size_t size = 0, capacity = -1; char *buf = NULL; - fseek(f, 0, SEEK_END); - capacity = ftell(f); - rewind(f); + /* + * Check if we can get the file size without implementation-defined + * behavior: + * + * From ftell(3p): + * [On error], ftell() and ftello() shall return −1, and set errno to + * indicate the error. + * + * The ftell() and ftello() functions shall fail if: [...] + * ESPIPE The file descriptor underlying stream is associated with a + * pipe, FIFO, or socket. + * + * From fseek(3p): + * The behavior of fseek() on devices which are incapable of seeking + * is implementation-defined. + */ + if (ftell(f) != -1) { + fseek(f, 0, SEEK_END); + capacity = ftell(f); + rewind(f); + } + // If ftell errored or the block above wasn't executed if (capacity == -1) capacity = 4096; From df15c97b6e85ab622e21889137184038c0476987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20K=C4=85dzio=C5=82ka?= Date: Wed, 3 Jul 2019 16:28:51 +0200 Subject: [PATCH 5/5] Handle zero-byte files gracefully --- src/asm/lexer.c | 14 ++++++++++++-- test/asm/zero-byte-file.asm | 0 test/asm/zero-byte-file.out | 0 test/asm/zero-byte-file.out.pipe | 0 4 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 test/asm/zero-byte-file.asm create mode 100644 test/asm/zero-byte-file.out create mode 100644 test/asm/zero-byte-file.out.pipe diff --git a/src/asm/lexer.c b/src/asm/lexer.c index ab22fa77..a98fef81 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -184,10 +184,14 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f) // If ftell errored or the block above wasn't executed if (capacity == -1) capacity = 4096; + // Handle 0-byte files gracefully + else if (capacity == 0) + capacity = 1; while (!feof(f)) { if (buf == NULL || size >= capacity) { - capacity *= 2; + if (buf) + capacity *= 2; /* Give extra room for 2 newlines and terminator */ buf = realloc(buf, capacity + SAFETYMARGIN + 3); @@ -199,7 +203,7 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f) char *bufpos = buf + SAFETYMARGIN + size; size_t read_count = fread(bufpos, 1, capacity - size, f); - if (read_count == 0) + if (read_count == 0 && !feof(f)) fatalerror("%s: fread error", __func__); size += read_count; @@ -211,6 +215,12 @@ YY_BUFFER_STATE yy_create_buffer(FILE *f) pBuffer->pBuffer[size] = 0; pBuffer->nBufferSize = size; + /* 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. + */ + capacity += 3; + /* Convert all line endings to LF and spaces */ char *mem = pBuffer->pBuffer; diff --git a/test/asm/zero-byte-file.asm b/test/asm/zero-byte-file.asm new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/zero-byte-file.out b/test/asm/zero-byte-file.out new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/zero-byte-file.out.pipe b/test/asm/zero-byte-file.out.pipe new file mode 100644 index 00000000..e69de29b