This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Scopes in which __label__ can appear


On 21-Jul-2003, Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
> Fergus Henderson <fjh@cs.mu.oz.au> writes:
> 
> [...]
> 
> | So the decision to require the use of __label__ to make labels
> | in a containing function accessible in nested functions,
> | though not absolutely essential, is nevertheless fairly strongly
> | motivated and hence quite understandable.
> 
> However, what has been implemented by Zack's patch is not exactly.
> It makes label an automatic variable.

There are two major issues here: scope, and storage duration/lifetime.
Zack's patch gives local labels block scope, but I hope it doesn't
give them the same lifetime as an automatic variable would have.

Labels which are not explicitly declared have "function scope",
just as in standard C, but note that function scope in GNU C does NOT
include nested functions.  For functions which are declared with
"__label__", we need to give them a different scope which does include
the bodies of nested functions.  Zack's patch keeps the property that
there are just four kinds of scopes (file scope, function scope, block
scope, and function prototype scope), by giving functions which are
declared with __label__ block scope.  Another alternative would be to
introduce a fifth kind of scope, which was like function scope, but which
also includes nested functions.  But given that __label__ is already
documented as creating a "local label" and given the documented local
scoping behaviour of __label__ with expression-statements, I think it
is better to reuse "block scope" rather than creating a new kind of scope.

    [Note: there are some minor borderline issues with regard to scope:
    labels which have function scope are not visible in nested function
    bodies, but are they visible in nested function declarations?
    For example, is the following translation unit allowed?

	void foo() {
		void bar(int x[sizeof({goto *lab;0;})]) {}
		lab: ;
	}

    Currently (gcc 2.95.4 and gcc 3.2) the answer is yes, this is allowed;
    function scope includes nested function declarations, but not nested
    function bodies.]

The other major issue is storage duration.  In standard C, only objects
have storage duration.  But in GNU C, it becomes important to consider
the storage duration for labels and functions, since you can take the
address of labels and of nested functions.  What storage duration, and
hence lifetime, should labels and nested functions have?

For nested functions, it's pretty clear: they should have automatic
storage duration.  But the GCC manual has some incorrect documentation
with regard to the lifetime of nested functions.  It says:

 | If you try to call the nested function through its address after the
 | containing function has exited, all hell will break loose.  If you try
 | to call it after a containing scope level has exited, and if it refers
 | to some of the variables that are no longer in scope, you may be lucky,
 | but it's not wise to take the risk.  If, however, the nested function
 | does not refer to anything that has gone out of scope, you should be
 | safe.

The statement "you should be safe" here is not correct.
For example, the following program results in "Illegal Instruction"
on my x86 GNU/Linux system.

	void (*addr_of_inner)(void);

	void outer(void) {
		void inner(void) {}
		addr_of_inner = &inner;
	}

	void wipe_stack(int p1, int p2, int p3, int p4, int p5) {}

	int main(void) {
		outer();
		wipe_stack(1,2,3,4,5);
		(*addr_of_inner)();
	}

In this program, the nested function inner() which is called does not
refer to any variables that are out of scope -- it does not refer
to any variables at all.  But nevertheless, calling (*addr_of_inner)()
fails, because the trampoline code on the stack which addr_of_inner
points to has been overwritten by the call to wipe_stack().

For labels, it's a bit tricker.  IMHO their lifetime should start on entry
to the function, and end on exit from the function.  This is regardless
of whether the label was declared with __label__ or not; I don't think
there is any need to distinguish between the two kinds of labels for
the purpose of determining their lifetime or storage duration.

The lifetime for labels that I have just suggest is equivalent to
automatic storage duration for an object declared in the outermost block
of the function, but it is not the same as automatic storage duration
would be for an object defined at the point where the label is declared
or defined.  Although this does not exactly match the semantics of
automatic storage duration for ordinary objects, I think that labels
should nevertheless have automatic storage duration, since it still
obeys the same stack discipline.  C99 already defines two slightly
different kinds of automatic storage duration, for non-VLAs and VLAs:
non-VLAs begin their lifetime on entry to the containing block, whereas
VLAs begin their lifetime on execution of their declaration (see C99
6.2.4 paragraphs 5 and 5).  The storage duration for labels could be
considered as an additional variant of automatic storage duration.

The lifetime of labels will affect programs which branch to them using
a computed goto from outside their scope.  For example:

	void *addr_of_label;

	int main() {
		{ __label lab; }
		  addr_of_label = &&lab;
		}
		goto *addr_of_label;
	}

If local labels have the same lifetime as variables with automatic
storage duration which are declared at the same place, then this program
would have undefined behaviour, since it jumps to a label whose lifetime
has ended, because the scope in which it was declared has been exited.
However, if local labels have a lifetime which ends on exit from the
containing *function*, as I proposed above, then this program's behaviour
is well defined.

-- 
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]