1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-07 23:29:39 +00:00

Add checks for risky goto statements.

This commit is contained in:
Laubzega 2018-09-21 00:40:05 -07:00 committed by Oliver Schmidt
parent df3c43bede
commit 581c46c213
10 changed files with 125 additions and 42 deletions

View File

@ -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 ();

View File

@ -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 */

View File

@ -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);
}

View File

@ -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;

View File

@ -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 ();

View File

@ -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.
*/

View File

@ -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 */

View File

@ -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);
}

View File

@ -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.

View File

@ -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 {