Proper warnings for "risky" gotos.
This commit is contained in:
@@ -87,7 +87,6 @@ static Function* NewFunction (struct SymEntry* Sym)
|
||||
F->TopLevelSP = 0;
|
||||
F->RegOffs = RegisterSpace;
|
||||
F->Flags = IsTypeVoid (F->ReturnType) ? FF_VOID_RETURN : FF_NONE;
|
||||
F->LocalsBlockCount = 0;
|
||||
|
||||
InitCollection (&F->LocalsBlockStack);
|
||||
|
||||
@@ -524,6 +523,8 @@ void NewFunc (SymEntry* Func)
|
||||
|
||||
/* Need a starting curly brace */
|
||||
ConsumeLCurly ();
|
||||
|
||||
/* Make sure there is always something on the stack of local variable blocks */
|
||||
CollAppend (&CurrentFunc->LocalsBlockStack, 0);
|
||||
|
||||
/* Parse local variable declarations if any */
|
||||
|
||||
@@ -61,7 +61,6 @@ struct Function {
|
||||
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 */
|
||||
};
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "standard.h"
|
||||
#include "symtab.h"
|
||||
#include "typeconv.h"
|
||||
#include "input.h"
|
||||
|
||||
|
||||
|
||||
@@ -270,6 +271,12 @@ static void ParseAutoDecl (Declaration* Decl)
|
||||
/* Mark the variable as referenced */
|
||||
Sym->Flags |= SC_REF;
|
||||
|
||||
/* Make note of auto variables initialized in current block.
|
||||
We abuse the Collection somewhat by using it to store line
|
||||
numbers. */
|
||||
CollReplace (&CurrentFunc->LocalsBlockStack, (void *)(long)GetCurrentLine (),
|
||||
CollCount (&CurrentFunc->LocalsBlockStack) - 1);
|
||||
|
||||
} else {
|
||||
/* Non-initialized local variable. Just keep track of
|
||||
** the space needed.
|
||||
@@ -489,6 +496,9 @@ void DeclareLocals (void)
|
||||
/* Remember the current stack pointer */
|
||||
int InitialStack = StackPtr;
|
||||
|
||||
/* A place to store info about potential initializations of auto variables */
|
||||
CollAppend (&CurrentFunc->LocalsBlockStack, 0);
|
||||
|
||||
/* Loop until we don't find any more variables */
|
||||
while (1) {
|
||||
|
||||
@@ -538,10 +548,9 @@ 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);
|
||||
/* No auto variables were inited. No new block on the stack then. */
|
||||
if (CollLast (&CurrentFunc->LocalsBlockStack) == NULL) {
|
||||
CollPop (&CurrentFunc->LocalsBlockStack);
|
||||
}
|
||||
|
||||
/* In case we've allocated local variables in this block, emit a call to
|
||||
|
||||
@@ -513,6 +513,7 @@ static int CompoundStatement (void)
|
||||
|
||||
/* Remember the stack at block entry */
|
||||
int OldStack = StackPtr;
|
||||
long OldBlockStackSize = CollCount (&CurrentFunc->LocalsBlockStack);
|
||||
|
||||
/* Enter a new lexical level */
|
||||
EnterBlockLevel ();
|
||||
@@ -535,7 +536,9 @@ static int CompoundStatement (void)
|
||||
g_space (StackPtr - OldStack);
|
||||
}
|
||||
|
||||
if (OldStack != StackPtr) {
|
||||
/* If the segment had autoinited variables, let's pop it of a stack
|
||||
of such blocks. */
|
||||
if (OldBlockStackSize != CollCount (&CurrentFunc->LocalsBlockStack)) {
|
||||
CollPop (&CurrentFunc->LocalsBlockStack);
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ void FreeSymEntry (SymEntry* E)
|
||||
|
||||
if (E->Flags & SC_LABEL) {
|
||||
for (i = 0; i < CollCount (E->V.L.DefsOrRefs); i++) {
|
||||
xfree (CollAt(E->V.L.DefsOrRefs, i));
|
||||
xfree (CollAt (E->V.L.DefsOrRefs, i));
|
||||
}
|
||||
|
||||
DoneCollection (E->V.L.DefsOrRefs);
|
||||
|
||||
@@ -105,7 +105,7 @@ struct LiteralPool;
|
||||
typedef struct DefOrRef DefOrRef;
|
||||
struct DefOrRef {
|
||||
unsigned Line;
|
||||
long LocalsBlockNum;
|
||||
long LocalsBlockId;
|
||||
unsigned Flags;
|
||||
int StackPtr;
|
||||
unsigned Depth;
|
||||
|
||||
@@ -668,7 +668,7 @@ DefOrRef* AddDefOrRef(SymEntry* E, unsigned Flags)
|
||||
DOR = xmalloc (sizeof (DefOrRef));
|
||||
CollAppend (E->V.L.DefsOrRefs, DOR);
|
||||
DOR->Line = GetCurrentLine ();
|
||||
DOR->LocalsBlockNum = (long)CollLast (&CurrentFunc->LocalsBlockStack);
|
||||
DOR->LocalsBlockId = (long)CollLast (&CurrentFunc->LocalsBlockStack);
|
||||
DOR->Flags = Flags;
|
||||
DOR->StackPtr = StackPtr;
|
||||
DOR->Depth = CollCount (&CurrentFunc->LocalsBlockStack);
|
||||
@@ -677,12 +677,13 @@ DefOrRef* AddDefOrRef(SymEntry* E, unsigned Flags)
|
||||
return DOR;
|
||||
}
|
||||
|
||||
|
||||
SymEntry* AddLabelSym (const char* Name, unsigned Flags)
|
||||
/* Add a goto label to the label table */
|
||||
{
|
||||
unsigned i;
|
||||
DefOrRef *DOR, *NewDOR;
|
||||
/* We juggle it so much that a shortcut will help with clarity */
|
||||
Collection *AIC = &CurrentFunc->LocalsBlockStack;
|
||||
|
||||
/* Do we have an entry with this name already? */
|
||||
SymEntry* Entry = FindSymInTable (LabelTab, Name, HashStr (Name));
|
||||
@@ -700,35 +701,40 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
|
||||
for (i = 0; i < CollCount (Entry->V.L.DefsOrRefs); i++) {
|
||||
DOR = CollAt (Entry->V.L.DefsOrRefs, i);
|
||||
|
||||
if((DOR->Flags & SC_DEF) && (Flags & SC_REF)) {
|
||||
if ((DOR->Flags & SC_DEF) && (Flags & SC_REF)) {
|
||||
/* We're processing a goto and here is its destination label.
|
||||
This means the difference between SP values is already known,
|
||||
so we simply emit the SP adjustment code. */
|
||||
if(StackPtr != DOR->StackPtr)
|
||||
if (StackPtr != DOR->StackPtr) {
|
||||
g_space (StackPtr - DOR->StackPtr);
|
||||
}
|
||||
|
||||
/* Are we jumping into same or deeper nesting region? That's risky,
|
||||
so let's emit a warning. */
|
||||
if (CollCount (&CurrentFunc->LocalsBlockStack) <= DOR->Depth &&
|
||||
DOR->LocalsBlockNum != (long)CollLast (&CurrentFunc->LocalsBlockStack)) {
|
||||
Warning ("Goto from line %d to label \'%s\' can result in a "
|
||||
"trashed stack", DOR->Line, Name);
|
||||
/* Are we jumping into a block with initalization of an object that
|
||||
has automatic storage duration? Let's emit a warning. */
|
||||
if ((long)CollLast (AIC) != DOR->LocalsBlockId &&
|
||||
(CollCount (AIC) < DOR->Depth ||
|
||||
(long)CollAt (AIC, DOR->Depth - 1) != DOR->LocalsBlockId)) {
|
||||
Warning ("Goto at line %d to label %s jumps into a block with "
|
||||
"initialization of an object that has automatic storage duration.",
|
||||
GetCurrentLine (), Name);
|
||||
}
|
||||
}
|
||||
|
||||
if((DOR->Flags & SC_REF) && (Flags & SC_DEF)) {
|
||||
|
||||
if ((DOR->Flags & SC_REF) && (Flags & SC_DEF)) {
|
||||
/* We're processing a label, let's update all gotos encountered
|
||||
so far */
|
||||
g_defdatalabel (DOR->LateSP_Label);
|
||||
g_defdata (CF_CONST | CF_INT, StackPtr - DOR->StackPtr, 0);
|
||||
|
||||
/* Are we jumping into same or deeper nesting region? That's risky,
|
||||
so let's emit a warning. */
|
||||
if (CollCount (&CurrentFunc->LocalsBlockStack) >= DOR->Depth &&
|
||||
DOR->LocalsBlockNum != (long)CollLast (&CurrentFunc->LocalsBlockStack)) {
|
||||
Warning ("Goto from line %d to label \'%s\' can result in a "
|
||||
"trashed stack", DOR->Line, Name);
|
||||
}
|
||||
/* Are we jumping into a block with initalization of an object that
|
||||
has automatic storage duration? Let's emit a warning. */
|
||||
if ((long)CollLast (AIC) != DOR->LocalsBlockId &&
|
||||
(CollCount (AIC) >= DOR->Depth ||
|
||||
(long)CollLast (AIC) >= DOR->Line))
|
||||
Warning ("Goto at line %d to label %s jumps into a block with "
|
||||
"initialization of an object that has automatic storage duration.",
|
||||
DOR->Line, Name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user