Add checks for risky goto statements.
This commit is contained in:
@@ -238,7 +238,7 @@ static void ParseGVarArg (StrBuf* T, unsigned Arg)
|
|||||||
} else {
|
} else {
|
||||||
/* Static variable */
|
/* Static variable */
|
||||||
char Buf [16];
|
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);
|
SB_AppendStr (T, Buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -293,7 +293,7 @@ static void ParseLabelArg (StrBuf* T, unsigned Arg attribute ((unused)))
|
|||||||
SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_REF);
|
SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_REF);
|
||||||
|
|
||||||
/* Append the label name to the buffer */
|
/* 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 */
|
/* Eat the label name */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|||||||
@@ -757,7 +757,7 @@ static void Primary (ExprDesc* E)
|
|||||||
E->Name = (uintptr_t) Sym->Name;
|
E->Name = (uintptr_t) Sym->Name;
|
||||||
} else {
|
} else {
|
||||||
E->Flags = E_LOC_STATIC | E_RTYPE_LVAL;
|
E->Flags = E_LOC_STATIC | E_RTYPE_LVAL;
|
||||||
E->Name = Sym->V.Label;
|
E->Name = Sym->V.L.Label;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Local static variable */
|
/* Local static variable */
|
||||||
|
|||||||
@@ -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 */
|
/* Pointer to current function */
|
||||||
Function* CurrentFunc = 0;
|
Function* CurrentFunc = 0;
|
||||||
|
|
||||||
@@ -99,14 +78,17 @@ static Function* NewFunction (struct SymEntry* Sym)
|
|||||||
Function* F = (Function*) xmalloc (sizeof (Function));
|
Function* F = (Function*) xmalloc (sizeof (Function));
|
||||||
|
|
||||||
/* Initialize the fields */
|
/* Initialize the fields */
|
||||||
F->FuncEntry = Sym;
|
F->FuncEntry = Sym;
|
||||||
F->ReturnType = GetFuncReturn (Sym->Type);
|
F->ReturnType = GetFuncReturn (Sym->Type);
|
||||||
F->Desc = GetFuncDesc (Sym->Type);
|
F->Desc = GetFuncDesc (Sym->Type);
|
||||||
F->Reserved = 0;
|
F->Reserved = 0;
|
||||||
F->RetLab = GetLocalLabel ();
|
F->RetLab = GetLocalLabel ();
|
||||||
F->TopLevelSP = 0;
|
F->TopLevelSP = 0;
|
||||||
F->RegOffs = RegisterSpace;
|
F->RegOffs = RegisterSpace;
|
||||||
F->Flags = IsTypeVoid (F->ReturnType) ? FF_VOID_RETURN : FF_NONE;
|
F->Flags = IsTypeVoid (F->ReturnType) ? FF_VOID_RETURN : FF_NONE;
|
||||||
|
F->LocalsBlockCount = 0;
|
||||||
|
|
||||||
|
InitCollection (&F->LocalsBlockStack);
|
||||||
|
|
||||||
/* Return the new structure */
|
/* Return the new structure */
|
||||||
return F;
|
return F;
|
||||||
@@ -117,6 +99,7 @@ static Function* NewFunction (struct SymEntry* Sym)
|
|||||||
static void FreeFunction (Function* F)
|
static void FreeFunction (Function* F)
|
||||||
/* Free a function activation structure */
|
/* Free a function activation structure */
|
||||||
{
|
{
|
||||||
|
DoneCollection (&F->LocalsBlockStack);
|
||||||
xfree (F);
|
xfree (F);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,13 +36,36 @@
|
|||||||
#ifndef FUNCTION_H
|
#ifndef FUNCTION_H
|
||||||
#define 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 */
|
/* Structure that holds all data needed for function activation */
|
||||||
typedef struct Function Function;
|
typedef struct Function Function;
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ void GotoStatement (void)
|
|||||||
SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_REF);
|
SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_REF);
|
||||||
|
|
||||||
/* Jump to the label */
|
/* Jump to the label */
|
||||||
g_jump (Entry->V.Label);
|
g_jump (Entry->V.L.Label);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Eat the label name */
|
/* Eat the label name */
|
||||||
@@ -80,7 +80,7 @@ void DoLabel (void)
|
|||||||
SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_DEF);
|
SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_DEF);
|
||||||
|
|
||||||
/* Emit the jump label */
|
/* Emit the jump label */
|
||||||
g_defcodelabel (Entry->V.Label);
|
g_defcodelabel (Entry->V.L.Label);
|
||||||
|
|
||||||
/* Eat the ident and colon */
|
/* Eat the ident and colon */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|||||||
@@ -538,6 +538,13 @@ void DeclareLocals (void)
|
|||||||
/* Be sure to allocate any reserved space for locals */
|
/* Be sure to allocate any reserved space for locals */
|
||||||
F_AllocLocalSpace (CurrentFunc);
|
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
|
/* In case we've allocated local variables in this block, emit a call to
|
||||||
** the stack checking routine if stack checks are enabled.
|
** the stack checking routine if stack checks are enabled.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -534,6 +534,10 @@ static int CompoundStatement (void)
|
|||||||
if (!GotBreak) {
|
if (!GotBreak) {
|
||||||
g_space (StackPtr - OldStack);
|
g_space (StackPtr - OldStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (OldStack != StackPtr)
|
||||||
|
CollPop (&CurrentFunc->LocalsBlockStack);
|
||||||
|
|
||||||
StackPtr = OldStack;
|
StackPtr = OldStack;
|
||||||
|
|
||||||
/* Emit references to imports/exports for this block */
|
/* Emit references to imports/exports for this block */
|
||||||
|
|||||||
@@ -83,8 +83,21 @@ SymEntry* NewSymEntry (const char* Name, unsigned Flags)
|
|||||||
void FreeSymEntry (SymEntry* E)
|
void FreeSymEntry (SymEntry* E)
|
||||||
/* Free a symbol entry */
|
/* Free a symbol entry */
|
||||||
{
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
TypeFree (E->Type);
|
TypeFree (E->Type);
|
||||||
xfree (E->AsmName);
|
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);
|
xfree (E);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,17 @@ struct LiteralPool;
|
|||||||
|
|
||||||
|
|
||||||
/* Symbol table entry */
|
/* Symbol table entry */
|
||||||
|
|
||||||
|
typedef struct DefOrRef DefOrRef;
|
||||||
|
|
||||||
|
struct DefOrRef {
|
||||||
|
unsigned Line;
|
||||||
|
long LocalsBlockNum;
|
||||||
|
unsigned Flags;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct SymEntry SymEntry;
|
typedef struct SymEntry SymEntry;
|
||||||
|
|
||||||
struct SymEntry {
|
struct SymEntry {
|
||||||
SymEntry* NextHash; /* Next entry in hash list */
|
SymEntry* NextHash; /* Next entry in hash list */
|
||||||
SymEntry* PrevSym; /* Previous symbol in dl list */
|
SymEntry* PrevSym; /* Previous symbol in dl list */
|
||||||
@@ -120,7 +130,10 @@ struct SymEntry {
|
|||||||
int Offs;
|
int Offs;
|
||||||
|
|
||||||
/* Label name for static symbols */
|
/* 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 bank offset and offset of the saved copy on stack for
|
||||||
** register variables.
|
** register variables.
|
||||||
|
|||||||
@@ -57,6 +57,8 @@
|
|||||||
#include "symentry.h"
|
#include "symentry.h"
|
||||||
#include "typecmp.h"
|
#include "typecmp.h"
|
||||||
#include "symtab.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)
|
SymEntry* AddLabelSym (const char* Name, unsigned Flags)
|
||||||
/* Add a goto label to the label table */
|
/* Add a goto label to the label table */
|
||||||
{
|
{
|
||||||
|
unsigned i;
|
||||||
|
DefOrRef *DOR;
|
||||||
/* Do we have an entry with this name already? */
|
/* Do we have an entry with this name already? */
|
||||||
SymEntry* Entry = FindSymInTable (LabelTab, Name, HashStr (Name));
|
SymEntry* Entry = FindSymInTable (LabelTab, Name, HashStr (Name));
|
||||||
if (Entry) {
|
if (Entry) {
|
||||||
@@ -670,6 +688,24 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
|
|||||||
/* Trying to define the label more than once */
|
/* Trying to define the label more than once */
|
||||||
Error ("Label `%s' is defined more than once", Name);
|
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;
|
Entry->Flags |= Flags;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -678,10 +714,14 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
|
|||||||
Entry = NewSymEntry (Name, SC_LABEL | Flags);
|
Entry = NewSymEntry (Name, SC_LABEL | Flags);
|
||||||
|
|
||||||
/* Set a new label number */
|
/* 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 */
|
/* 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 */
|
/* Add the entry to the label table */
|
||||||
AddSymEntry (LabelTab, Entry);
|
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.RegOffs = Offs;
|
||||||
Entry->V.R.SaveOffs = StackPtr;
|
Entry->V.R.SaveOffs = StackPtr;
|
||||||
} else if ((Flags & SC_EXTERN) == SC_EXTERN) {
|
} else if ((Flags & SC_EXTERN) == SC_EXTERN) {
|
||||||
Entry->V.Label = Offs;
|
Entry->V.L.Label = Offs;
|
||||||
SymSetAsmName (Entry);
|
SymSetAsmName (Entry);
|
||||||
} else if ((Flags & SC_STATIC) == SC_STATIC) {
|
} else if ((Flags & SC_STATIC) == SC_STATIC) {
|
||||||
/* Generate the assembler name from the label number */
|
/* Generate the assembler name from the label number */
|
||||||
Entry->V.Label = Offs;
|
Entry->V.L.Label = Offs;
|
||||||
Entry->AsmName = xstrdup (LocalLabelName (Entry->V.Label));
|
Entry->AsmName = xstrdup (LocalLabelName (Entry->V.L.Label));
|
||||||
} else if ((Flags & SC_STRUCTFIELD) == SC_STRUCTFIELD) {
|
} else if ((Flags & SC_STRUCTFIELD) == SC_STRUCTFIELD) {
|
||||||
Entry->V.Offs = Offs;
|
Entry->V.Offs = Offs;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user