From 581c46c2136fa18bd3a60cddf6d2732862381023 Mon Sep 17 00:00:00 2001 From: Laubzega Date: Fri, 21 Sep 2018 00:40:05 -0700 Subject: [PATCH] Add checks for risky goto statements. --- src/cc65/asmstmt.c | 4 ++-- src/cc65/expr.c | 2 +- src/cc65/function.c | 41 +++++++++++-------------------------- src/cc65/function.h | 27 ++++++++++++++++++++++-- src/cc65/goto.c | 4 ++-- src/cc65/locals.c | 7 +++++++ src/cc65/stmt.c | 4 ++++ src/cc65/symentry.c | 13 ++++++++++++ src/cc65/symentry.h | 15 +++++++++++++- src/cc65/symtab.c | 50 ++++++++++++++++++++++++++++++++++++++++----- 10 files changed, 125 insertions(+), 42 deletions(-) diff --git a/src/cc65/asmstmt.c b/src/cc65/asmstmt.c index 4dd6628c4..1fc4e3167 100644 --- a/src/cc65/asmstmt.c +++ b/src/cc65/asmstmt.c @@ -238,7 +238,7 @@ static void ParseGVarArg (StrBuf* T, unsigned Arg) } else { /* Static variable */ char Buf [16]; - xsprintf (Buf, sizeof (Buf), "L%04X", Sym->V.Label); + xsprintf (Buf, sizeof (Buf), "L%04X", Sym->V.L.Label); SB_AppendStr (T, Buf); } } @@ -293,7 +293,7 @@ static void ParseLabelArg (StrBuf* T, unsigned Arg attribute ((unused))) SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_REF); /* Append the label name to the buffer */ - SB_AppendStr (T, LocalLabelName (Entry->V.Label)); + SB_AppendStr (T, LocalLabelName (Entry->V.L.Label)); /* Eat the label name */ NextToken (); diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 43971caae..55c6391d2 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -757,7 +757,7 @@ static void Primary (ExprDesc* E) E->Name = (uintptr_t) Sym->Name; } else { E->Flags = E_LOC_STATIC | E_RTYPE_LVAL; - E->Name = Sym->V.Label; + E->Name = Sym->V.L.Label; } } else { /* Local static variable */ diff --git a/src/cc65/function.c b/src/cc65/function.c index 22b305739..6a601db2c 100644 --- a/src/cc65/function.c +++ b/src/cc65/function.c @@ -60,27 +60,6 @@ /*****************************************************************************/ - -/* Enumeration for function flags */ -typedef enum { - FF_NONE = 0x0000, - FF_HAS_RETURN = 0x0001, /* Function has a return statement */ - FF_IS_MAIN = 0x0002, /* This is the main function */ - FF_VOID_RETURN = 0x0004, /* Function returning void */ -} funcflags_t; - -/* Structure that holds all data needed for function activation */ -struct Function { - struct SymEntry* FuncEntry; /* Symbol table entry */ - Type* ReturnType; /* Function return type */ - FuncDesc* Desc; /* Function descriptor */ - int Reserved; /* Reserved local space */ - unsigned RetLab; /* Return code label */ - int TopLevelSP; /* SP at function top level */ - unsigned RegOffs; /* Register variable space offset */ - funcflags_t Flags; /* Function flags */ -}; - /* Pointer to current function */ Function* CurrentFunc = 0; @@ -99,14 +78,17 @@ static Function* NewFunction (struct SymEntry* Sym) Function* F = (Function*) xmalloc (sizeof (Function)); /* Initialize the fields */ - F->FuncEntry = Sym; - F->ReturnType = GetFuncReturn (Sym->Type); - F->Desc = GetFuncDesc (Sym->Type); - F->Reserved = 0; - F->RetLab = GetLocalLabel (); - F->TopLevelSP = 0; - F->RegOffs = RegisterSpace; - F->Flags = IsTypeVoid (F->ReturnType) ? FF_VOID_RETURN : FF_NONE; + F->FuncEntry = Sym; + F->ReturnType = GetFuncReturn (Sym->Type); + F->Desc = GetFuncDesc (Sym->Type); + F->Reserved = 0; + F->RetLab = GetLocalLabel (); + F->TopLevelSP = 0; + F->RegOffs = RegisterSpace; + F->Flags = IsTypeVoid (F->ReturnType) ? FF_VOID_RETURN : FF_NONE; + F->LocalsBlockCount = 0; + + InitCollection (&F->LocalsBlockStack); /* Return the new structure */ return F; @@ -117,6 +99,7 @@ static Function* NewFunction (struct SymEntry* Sym) static void FreeFunction (Function* F) /* Free a function activation structure */ { + DoneCollection (&F->LocalsBlockStack); xfree (F); } diff --git a/src/cc65/function.h b/src/cc65/function.h index 627457277..1b04009d6 100644 --- a/src/cc65/function.h +++ b/src/cc65/function.h @@ -36,13 +36,36 @@ #ifndef FUNCTION_H #define FUNCTION_H - +#include "coll.h" /*****************************************************************************/ -/* data */ +/* Data */ /*****************************************************************************/ +/* Enumeration for function flags */ +typedef enum { + FF_NONE = 0x0000, + FF_HAS_RETURN = 0x0001, /* Function has a return statement */ + FF_IS_MAIN = 0x0002, /* This is the main function */ + FF_VOID_RETURN = 0x0004, /* Function returning void */ +} funcflags_t; + +/* Structure that holds all data needed for function activation */ +struct Function { + struct SymEntry* FuncEntry; /* Symbol table entry */ + Type* ReturnType; /* Function return type */ + FuncDesc* Desc; /* Function descriptor */ + int Reserved; /* Reserved local space */ + unsigned RetLab; /* Return code label */ + int TopLevelSP; /* SP at function top level */ + unsigned RegOffs; /* Register variable space offset */ + funcflags_t Flags; /* Function flags */ + long LocalsBlockCount; /* Number of blocks with local vars */ + Collection LocalsBlockStack; /* Stack of blocks with local vars */ +}; + + /* Structure that holds all data needed for function activation */ typedef struct Function Function; diff --git a/src/cc65/goto.c b/src/cc65/goto.c index 6e282c636..3b1d243e7 100644 --- a/src/cc65/goto.c +++ b/src/cc65/goto.c @@ -64,7 +64,7 @@ void GotoStatement (void) SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_REF); /* Jump to the label */ - g_jump (Entry->V.Label); + g_jump (Entry->V.L.Label); } /* Eat the label name */ @@ -80,7 +80,7 @@ void DoLabel (void) SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_DEF); /* Emit the jump label */ - g_defcodelabel (Entry->V.Label); + g_defcodelabel (Entry->V.L.Label); /* Eat the ident and colon */ NextToken (); diff --git a/src/cc65/locals.c b/src/cc65/locals.c index ffadb1bd5..a231a6003 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -538,6 +538,13 @@ void DeclareLocals (void) /* Be sure to allocate any reserved space for locals */ F_AllocLocalSpace (CurrentFunc); + if (InitialStack != StackPtr) + { + ++CurrentFunc->LocalsBlockCount; + /* Is it ok to abuse Collection in this way? */ + CollAppend (&CurrentFunc->LocalsBlockStack, (void *)CurrentFunc->LocalsBlockCount); + } + /* In case we've allocated local variables in this block, emit a call to ** the stack checking routine if stack checks are enabled. */ diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index c6167fa78..be58e4a7e 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -534,6 +534,10 @@ static int CompoundStatement (void) if (!GotBreak) { g_space (StackPtr - OldStack); } + + if (OldStack != StackPtr) + CollPop (&CurrentFunc->LocalsBlockStack); + StackPtr = OldStack; /* Emit references to imports/exports for this block */ diff --git a/src/cc65/symentry.c b/src/cc65/symentry.c index d6e68d1bb..8091c4d26 100644 --- a/src/cc65/symentry.c +++ b/src/cc65/symentry.c @@ -83,8 +83,21 @@ SymEntry* NewSymEntry (const char* Name, unsigned Flags) void FreeSymEntry (SymEntry* E) /* Free a symbol entry */ { + unsigned i; + TypeFree (E->Type); xfree (E->AsmName); + + if (E->Flags & SC_LABEL) + { + for (i = 0; i < CollCount (E->V.L.DefsOrRefs); i++) + { + xfree (CollAt(E->V.L.DefsOrRefs, i)); + } + + DoneCollection (E->V.L.DefsOrRefs); + } + xfree (E); } diff --git a/src/cc65/symentry.h b/src/cc65/symentry.h index ff136702f..2c22f99a0 100644 --- a/src/cc65/symentry.h +++ b/src/cc65/symentry.h @@ -101,7 +101,17 @@ struct LiteralPool; /* Symbol table entry */ + +typedef struct DefOrRef DefOrRef; + +struct DefOrRef { + unsigned Line; + long LocalsBlockNum; + unsigned Flags; +}; + typedef struct SymEntry SymEntry; + struct SymEntry { SymEntry* NextHash; /* Next entry in hash list */ SymEntry* PrevSym; /* Previous symbol in dl list */ @@ -120,7 +130,10 @@ struct SymEntry { int Offs; /* Label name for static symbols */ - unsigned Label; + struct { + unsigned Label; + Collection *DefsOrRefs; + } L; /* Register bank offset and offset of the saved copy on stack for ** register variables. diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index 3275332c5..51b43b4c9 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -57,6 +57,8 @@ #include "symentry.h" #include "typecmp.h" #include "symtab.h" +#include "function.h" +#include "input.h" @@ -658,10 +660,26 @@ SymEntry* AddConstSym (const char* Name, const Type* T, unsigned Flags, long Val } +DefOrRef* AddDefOrRef(SymEntry* E, unsigned Flags) +/* Add definition or reference to the SymEntry and preserve its attributes */ +{ + DefOrRef *DOR; + + DOR = xmalloc (sizeof (DefOrRef)); + CollAppend (E->V.L.DefsOrRefs, DOR); + DOR->Line = GetCurrentLine (); + DOR->LocalsBlockNum = (long)CollLast (&CurrentFunc->LocalsBlockStack); + DOR->Flags = Flags; + + return DOR; +} + SymEntry* AddLabelSym (const char* Name, unsigned Flags) /* Add a goto label to the label table */ { + unsigned i; + DefOrRef *DOR; /* Do we have an entry with this name already? */ SymEntry* Entry = FindSymInTable (LabelTab, Name, HashStr (Name)); if (Entry) { @@ -670,6 +688,24 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags) /* Trying to define the label more than once */ Error ("Label `%s' is defined more than once", Name); } + + /* Walk through all occurrences of the label so far and check + if any of them is in a region that would be risky to jump from/to + from the place where we are right now. */ + for (i = 0; i < CollCount (Entry->V.L.DefsOrRefs); i++) { + DOR = CollAt (Entry->V.L.DefsOrRefs, i); + /* We are only interested in label occurences of type opposite to + the one currently being added, i.e. if we are processing the + definition, we will only check the gotos; if we are processing + a goto statement, we will only look for the label definition. */ + if (((DOR->Flags & SC_DEF) != (Flags & SC_DEF)) && + (DOR->LocalsBlockNum != (long)CollLast (&CurrentFunc->LocalsBlockStack))) + Warning ("Goto from line %d to label \'%s\' can result in a " + "trashed stack", Flags & SC_DEF ? DOR->Line : GetCurrentLine (), Name); + } + + AddDefOrRef (Entry, Flags); + Entry->Flags |= Flags; } else { @@ -678,10 +714,14 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags) Entry = NewSymEntry (Name, SC_LABEL | Flags); /* Set a new label number */ - Entry->V.Label = GetLocalLabel (); + Entry->V.L.Label = GetLocalLabel (); + + /* Create Collection for label definition and references */ + Entry->V.L.DefsOrRefs = NewCollection (); + AddDefOrRef (Entry, Flags); /* Generate the assembler name of the label */ - Entry->AsmName = xstrdup (LocalLabelName (Entry->V.Label)); + Entry->AsmName = xstrdup (LocalLabelName (Entry->V.L.Label)); /* Add the entry to the label table */ AddSymEntry (LabelTab, Entry); @@ -717,12 +757,12 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs Entry->V.R.RegOffs = Offs; Entry->V.R.SaveOffs = StackPtr; } else if ((Flags & SC_EXTERN) == SC_EXTERN) { - Entry->V.Label = Offs; + Entry->V.L.Label = Offs; SymSetAsmName (Entry); } else if ((Flags & SC_STATIC) == SC_STATIC) { /* Generate the assembler name from the label number */ - Entry->V.Label = Offs; - Entry->AsmName = xstrdup (LocalLabelName (Entry->V.Label)); + Entry->V.L.Label = Offs; + Entry->AsmName = xstrdup (LocalLabelName (Entry->V.L.Label)); } else if ((Flags & SC_STRUCTFIELD) == SC_STRUCTFIELD) { Entry->V.Offs = Offs; } else { -- 2.39.5