Prevent defining invalid local labels

Fixes #913
This commit is contained in:
Rangi
2021-07-29 18:55:59 -04:00
committed by Eldred Habert
parent 20fd6eabbb
commit 26ddf1ff4d
14 changed files with 63 additions and 29 deletions

View File

@@ -245,18 +245,18 @@ struct Symbol *sym_FindUnscopedSymbol(char const *symName)
struct Symbol *sym_FindScopedSymbol(char const *symName) struct Symbol *sym_FindScopedSymbol(char const *symName)
{ {
char const *dotPtr = strchr(symName, '.'); char const *localName = strchr(symName, '.');
if (dotPtr) { if (localName) {
if (strchr(dotPtr + 1, '.')) if (strchr(localName + 1, '.'))
fatalerror("'%s' is a nonsensical reference to a nested local symbol\n", fatalerror("'%s' is a nonsensical reference to a nested local symbol\n",
symName); symName);
/* If auto-scoped local label, expand the name */ /* If auto-scoped local label, expand the name */
if (dotPtr == symName) { /* Meaning, the name begins with the dot */ if (localName == symName) { /* Meaning, the name begins with the dot */
char fullname[MAXSYMLEN + 1]; char fullName[MAXSYMLEN + 1];
fullSymbolName(fullname, sizeof(fullname), symName, labelScope); fullSymbolName(fullName, sizeof(fullName), symName, labelScope);
return sym_FindExactSymbol(fullname); return sym_FindExactSymbol(fullName);
} }
} }
return sym_FindExactSymbol(symName); 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) 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); error("Local label '%s' in main scope\n", symName);
return NULL; 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] == '.') { assert(localName); /* There should be at least one dot in `symName` */
/* If symbol is of the form `.name`, expand to the full `Parent.name` name */ /* Check for something after the dot in `localName` */
fullSymbolName(fullname, sizeof(fullname), symName, labelScope); if (localName[1] == '\0') {
symName = fullname; /* Use the expanded name instead */ 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 { } else {
size_t i = 0; 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]) while (labelScope[i] && symName[i] == labelScope[i])
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 `symName` starts with `labelScope` and then a '.' */
* 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`.
*/
if (labelScope[i] != '\0' || symName[i] != '.') { if (labelScope[i] != '\0' || symName[i] != '.') {
size_t parentLen = localName - symName;
assert(parentLen <= INT_MAX); assert(parentLen <= INT_MAX);
error("Not currently in the scope of '%.*s'\n", (int)parentLen, symName); 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); return addLabel(symName);

View File

@@ -0,0 +1,2 @@
FATAL: empty-local.asm(5):
'Label.' is a nonsensical reference to an empty local label

View File

@@ -0,0 +1,7 @@
SECTION "sec", ROM0
Parent:
Parent.heir:
db 0
Parent...spare:
db 1

View File

@@ -0,0 +1,2 @@
FATAL: multiple-dots-local.asm(6):
'Parent...spare' is a nonsensical reference to a nested local label

View File

View File

@@ -0,0 +1,8 @@
SECTION "sec", ROM0
Parent:
Parent.child:
db 0
.grandchild:
db 1
dw Parent.child.grandchild

View File

@@ -0,0 +1,2 @@
FATAL: nested-local-reference.asm(8):
'Parent.child.grandchild' is a nonsensical reference to a nested local symbol

View File

View File

@@ -0,0 +1,7 @@
SECTION "sec", ROM0
Parent:
Parent.child:
db 0
Parent.child.grandchild:
db 1

View File

@@ -0,0 +1,2 @@
FATAL: nested-local.asm(6):
'Parent.child.grandchild' is a nonsensical reference to a nested local label

View File

View File

@@ -4,4 +4,4 @@ Parent:
.child: .child:
db 0 db 0
NotParent: NotParent:
dw Parent.child.fail dw Parent.orphan

View File

@@ -1,2 +0,0 @@
FATAL: remote-local-noexist.asm(7):
'Parent.child.fail' is a nonsensical reference to a nested local symbol

View File

@@ -3,7 +3,7 @@ ERROR: sym-scope.asm(4):
ERROR: sym-scope.asm(5): ERROR: sym-scope.asm(5):
Local label 'Nice.try' in main scope Local label 'Nice.try' in main scope
ERROR: sym-scope.asm(17): 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): 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)! error: Assembly aborted (4 errors)!