简体   繁体   中英

Is a goto in alloca's function scope valid?

The C standard prohibits a goto into a function scope where a VLA exists.

A VLA and the call to alloca function should have the same result on low level.

(I could be wrong, as I'm just a C, not a low level programmer, but in my imagin that appears to be witty)

So will the following snippet be also undefined behaivng?

int main()
{
    char *p;

    goto label1;

    {
        p = _alloca(1);
label1:
        p = NULL;
    }
}

Ofcourse I cant refference p , but whats about the behaviour?

Actually, the rule 6.8.6.1 states:

  A goto statement is not allowed to jump past any declarations of objects 
  with variably modified types.

In your code, there does not exist an object with variably modified types. alloca does not declare an object (that the compiler has to care of). Thus, there is nothing like a scope for alloca , and no reason for undefined behavior in the sense of rule 6.8.6.1.

EDIT

To elaborate the answer a bit: the "undefinedness" of the behavior in case of VLA is due to the promise of a declaration that an object is "known" within its scope (at language level). In general, a declaration sets a context for code execution. There is no need that it is executed at runtime. However, this is not true in case of VLA: here this promise is implemented partly at runtime, breaking C's static declaration approach. To avoid further conflicts that would lead to a dynamic typing system, rule 6.8.6.1 avoids such conflicts.

In contrast, at language level alloca is simply a function; its call does not constitute any scope. It makes only a promise about its run-time behavior in case it is called. If it isn't called, we do not "expect" anything from a function. Thus, its pure existence does not raise any conflict: both cases (bypassing or non-bypassing) have a well defined semantic.

A VLA and the call to alloca function should have the same result on low level.

There are still a few differences. A VLA object is discarded when the scope where it is declared ends and the memory object allocated by alloca is discarded when the function returns.

This makes a difference because the requirement in c99, 6.8.6.1p1 ( "A goto statement shall not jump from outside the scope of an identifier having a variably modified type to inside the scope of that identifier" ) is concerned by the runtime allocation / deallocation of objects with variably modified type. Here the alloca statement is not executed after goto is performed, so I would not think the goto call would invoke undefined behavior.

The C Standard has nothing to say about the behavior of alloca() . Some compilers use the stack in a very predictable fashion, and access automatic variables using a largely-redundant frame pointer. On such compilers, it's possible to reserve space on the stack by simply subtracting a value from the stack pointer, without the compiler having to know or care about the reservation in question. Such code will break badly, however, if the compiler uses the stack in ways that the application wasn't expecting.

I don't think that something like:

  int *p = 0;
  if (!foo(1,2,3))
    goto skip_alloca;
  p=alloca(46);
skip_alloca:
  bar(4,5,6);
  ...

is apt to be any more dangerous than:

  int *p = 0;
  if (foo(1,2,3))
    p=alloca(46);
  bar(4,5,6);
  ...

If there is no residue on the stack from the function call at the time the alloca() is performed, either operation would likely be safe. If there is residue on the stack at the time of the alloca (eg because the compiler opts to defer cleanup of foo 's arguments until after the call to bar ) that would make alloca() misbehave badly. Using the goto version of the code might actually be safer than the version with if , because it would be harder for a compiler to identify that deferring the cleanup from foo might be advantageous.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM