From 26ddf1ff4df483ddafb2992aa4903902911e6a94 Mon Sep 17 00:00:00 2001 From: Rangi Date: Thu, 29 Jul 2021 18:55:59 -0400 Subject: [PATCH] Prevent defining invalid local labels Fixes #913 --- src/asm/symbol.c | 54 ++++++++++++++++------------- test/asm/empty-local.err | 2 ++ test/asm/multiple-dots-local.asm | 7 ++++ test/asm/multiple-dots-local.err | 2 ++ test/asm/multiple-dots-local.out | 0 test/asm/nested-local-reference.asm | 8 +++++ test/asm/nested-local-reference.err | 2 ++ test/asm/nested-local-reference.out | 0 test/asm/nested-local.asm | 7 ++++ test/asm/nested-local.err | 2 ++ test/asm/nested-local.out | 0 test/asm/remote-local-noexist.asm | 2 +- test/asm/remote-local-noexist.err | 2 -- test/asm/sym-scope.err | 4 +-- 14 files changed, 63 insertions(+), 29 deletions(-) create mode 100644 test/asm/multiple-dots-local.asm create mode 100644 test/asm/multiple-dots-local.err create mode 100644 test/asm/multiple-dots-local.out create mode 100644 test/asm/nested-local-reference.asm create mode 100644 test/asm/nested-local-reference.err create mode 100644 test/asm/nested-local-reference.out create mode 100644 test/asm/nested-local.asm create mode 100644 test/asm/nested-local.err create mode 100644 test/asm/nested-local.out diff --git a/src/asm/symbol.c b/src/asm/symbol.c index 2d6005b1..e13b37b4 100644 --- a/src/asm/symbol.c +++ b/src/asm/symbol.c @@ -245,18 +245,18 @@ struct Symbol *sym_FindUnscopedSymbol(char const *symName) struct Symbol *sym_FindScopedSymbol(char const *symName) { - char const *dotPtr = strchr(symName, '.'); + char const *localName = strchr(symName, '.'); - if (dotPtr) { - if (strchr(dotPtr + 1, '.')) + if (localName) { + if (strchr(localName + 1, '.')) fatalerror("'%s' is a nonsensical reference to a nested local symbol\n", symName); /* If auto-scoped local label, expand the name */ - if (dotPtr == symName) { /* Meaning, the name begins with the dot */ - char fullname[MAXSYMLEN + 1]; + if (localName == symName) { /* Meaning, the name begins with the dot */ + char fullName[MAXSYMLEN + 1]; - fullSymbolName(fullname, sizeof(fullname), symName, labelScope); - return sym_FindExactSymbol(fullname); + fullSymbolName(fullName, sizeof(fullName), symName, labelScope); + return sym_FindExactSymbol(fullName); } } return sym_FindExactSymbol(symName); @@ -533,7 +533,7 @@ static struct Symbol *addLabel(char const *symName) } /* - * Add a local (.name or Parent.name) relocatable symbol + * Add a local (`.name` or `Parent.name`) relocatable symbol */ struct Symbol *sym_AddLocalLabel(char const *symName) { @@ -541,34 +541,40 @@ struct Symbol *sym_AddLocalLabel(char const *symName) error("Local label '%s' in main scope\n", symName); return NULL; } + assert(!strchr(labelScope, '.')); /* Assuming no dots in `labelScope` */ - char fullname[MAXSYMLEN + 1]; + char fullName[MAXSYMLEN + 1]; + char const *localName = strchr(symName, '.'); - if (symName[0] == '.') { - /* If symbol is of the form `.name`, expand to the full `Parent.name` name */ - fullSymbolName(fullname, sizeof(fullname), symName, labelScope); - symName = fullname; /* Use the expanded name instead */ + assert(localName); /* There should be at least one dot in `symName` */ + /* Check for something after the dot in `localName` */ + if (localName[1] == '\0') { + fatalerror("'%s' is a nonsensical reference to an empty local label\n", + symName); + } + /* Check for more than one dot in `localName` */ + if (strchr(localName + 1, '.')) + fatalerror("'%s' is a nonsensical reference to a nested local label\n", + symName); + + if (localName == symName) { + /* Expand `symName` to the full `labelScope.symName` name */ + fullSymbolName(fullName, sizeof(fullName), symName, labelScope); + symName = fullName; } else { size_t i = 0; - /* Otherwise, check that `Parent` is in fact the current scope */ + /* Find where `labelScope` and `symName` first differ */ while (labelScope[i] && symName[i] == labelScope[i]) i++; - /* Assuming no dots in `labelScope` */ - assert(strchr(&symName[i], '.')); /* There should be at least one dot, though */ - size_t parentLen = i + (strchr(&symName[i], '.') - symName); - /* - * Check that `labelScope[i]` ended the check, guaranteeing that `symName` is at - * least as long, and then that this was the entire `Parent` part of `symName`. - */ + /* Check that `symName` starts with `labelScope` and then a '.' */ if (labelScope[i] != '\0' || symName[i] != '.') { + size_t parentLen = localName - symName; + assert(parentLen <= INT_MAX); error("Not currently in the scope of '%.*s'\n", (int)parentLen, symName); } - if (strchr(&symName[parentLen + 1], '.')) /* There will at least be a terminator */ - fatalerror("'%s' is a nonsensical reference to a nested local label\n", - symName); } return addLabel(symName); diff --git a/test/asm/empty-local.err b/test/asm/empty-local.err index e69de29b..f7b05b06 100644 --- a/test/asm/empty-local.err +++ b/test/asm/empty-local.err @@ -0,0 +1,2 @@ +FATAL: empty-local.asm(5): + 'Label.' is a nonsensical reference to an empty local label diff --git a/test/asm/multiple-dots-local.asm b/test/asm/multiple-dots-local.asm new file mode 100644 index 00000000..0821c379 --- /dev/null +++ b/test/asm/multiple-dots-local.asm @@ -0,0 +1,7 @@ +SECTION "sec", ROM0 + +Parent: +Parent.heir: + db 0 +Parent...spare: + db 1 diff --git a/test/asm/multiple-dots-local.err b/test/asm/multiple-dots-local.err new file mode 100644 index 00000000..6c2a3bc2 --- /dev/null +++ b/test/asm/multiple-dots-local.err @@ -0,0 +1,2 @@ +FATAL: multiple-dots-local.asm(6): + 'Parent...spare' is a nonsensical reference to a nested local label diff --git a/test/asm/multiple-dots-local.out b/test/asm/multiple-dots-local.out new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/nested-local-reference.asm b/test/asm/nested-local-reference.asm new file mode 100644 index 00000000..606778f4 --- /dev/null +++ b/test/asm/nested-local-reference.asm @@ -0,0 +1,8 @@ +SECTION "sec", ROM0 + +Parent: +Parent.child: + db 0 +.grandchild: + db 1 + dw Parent.child.grandchild diff --git a/test/asm/nested-local-reference.err b/test/asm/nested-local-reference.err new file mode 100644 index 00000000..7e2ae7b7 --- /dev/null +++ b/test/asm/nested-local-reference.err @@ -0,0 +1,2 @@ +FATAL: nested-local-reference.asm(8): + 'Parent.child.grandchild' is a nonsensical reference to a nested local symbol diff --git a/test/asm/nested-local-reference.out b/test/asm/nested-local-reference.out new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/nested-local.asm b/test/asm/nested-local.asm new file mode 100644 index 00000000..8de26d8e --- /dev/null +++ b/test/asm/nested-local.asm @@ -0,0 +1,7 @@ +SECTION "sec", ROM0 + +Parent: +Parent.child: + db 0 +Parent.child.grandchild: + db 1 diff --git a/test/asm/nested-local.err b/test/asm/nested-local.err new file mode 100644 index 00000000..ceba5a0c --- /dev/null +++ b/test/asm/nested-local.err @@ -0,0 +1,2 @@ +FATAL: nested-local.asm(6): + 'Parent.child.grandchild' is a nonsensical reference to a nested local label diff --git a/test/asm/nested-local.out b/test/asm/nested-local.out new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/remote-local-noexist.asm b/test/asm/remote-local-noexist.asm index 6530d817..491492cf 100644 --- a/test/asm/remote-local-noexist.asm +++ b/test/asm/remote-local-noexist.asm @@ -4,4 +4,4 @@ Parent: .child: db 0 NotParent: - dw Parent.child.fail + dw Parent.orphan diff --git a/test/asm/remote-local-noexist.err b/test/asm/remote-local-noexist.err index 3193664b..e69de29b 100644 --- a/test/asm/remote-local-noexist.err +++ b/test/asm/remote-local-noexist.err @@ -1,2 +0,0 @@ -FATAL: remote-local-noexist.asm(7): - 'Parent.child.fail' is a nonsensical reference to a nested local symbol diff --git a/test/asm/sym-scope.err b/test/asm/sym-scope.err index e77f43bc..561491d8 100644 --- a/test/asm/sym-scope.err +++ b/test/asm/sym-scope.err @@ -3,7 +3,7 @@ ERROR: sym-scope.asm(4): ERROR: sym-scope.asm(5): Local label 'Nice.try' in main scope ERROR: sym-scope.asm(17): - Not currently in the scope of 'Parentheses.check' + Not currently in the scope of 'Parentheses' ERROR: sym-scope.asm(21): - Not currently in the scope of 'Parent.check' + Not currently in the scope of 'Parent' error: Assembly aborted (4 errors)!