From: antispam@fricas.org   
      
   EricP wrote:   
   > Niklas Holsti wrote:   
   >> On 2025-11-06 20:28, MitchAlsup wrote:   
   >>>   
   >>> Niklas Holsti posted:   
   >>>   
   >>>> On 2025-11-05 23:28, MitchAlsup wrote:   
   >>>>>   
   >>>>> Niklas Holsti posted:   
   >>>> ----------------   
   >>>>>> But then you could get the problem of a longjmp to a setjmp value that   
   >>>>>> is stale because the targeted function invocation (stack frame) is no   
   >>>>>> longer there.   
   >>>>>   
   >>>>> But YOU had to pass the jumpbuf out of the setjump() scope.   
   >>>>>   
   >>>>> Now, YOU complain there is a hole in your own foot with a smoking gun   
   >>>>> in your own hand.   
   >>>>   
   >>>> That is not the issue. The question is if the semantics of "goto   
   >>>> label-valued-variable" are hard to define, as Ritchie said, or not, as   
   >>>> Anton thinks Stallman said or would have said.   
   >>>   
   >>> So, label-variables are hard to define, but function-variables are not   
   >>> ?!?   
   >>   
   >> Depends on the level at which you want to define it.   
   >>   
   >> At the machine level, where semantics are (usually) defined for each   
   >> instruction separately, a jump to a dynamic address (using a   
   >> "label-variable") is not much different from a call to a dynamic address   
   >> (using a "function-variable"), and the effect of the single instruction   
   >> on the machine state is much the same as for the static address case.   
   >> The higher-level effect on the further execution of the program is out   
   >> of scope, whatever the actual value of the target address in the   
   >> instruction.   
   >>   
   >> It is only if your machine has some semantics for instruction   
   >> combinations, such as your VEC-LOOP pair, that you have to define what   
   >> happens if a jump or call to some address leads to later executing only   
   >> some of those instructions or executing them in the wrong order, such as   
   >> trying to execute a LOOP without having executed a preceding VEC.   
   >>   
   >> At the higher programming-language level, the label case can be much   
   >> harder to define and less useful than the function case, depending on   
   >> the programming language and its abstract model of execution, and also   
   >> depending on what compile-time checks you assume.   
   >>   
   >> Consider an imperative language such as C with no functions nested   
   >> within other functions or other blocks (where by "block" I mean some   
   >> syntactical construct that sets up its local context with local   
   >> variables etc.). If you have a function-variable (that is, a pointer to   
   >> a function) that actually refers to a function with the same parameter   
   >> profile, it is easy to define the semantics of a call via this function   
   >> variable: it is the same as for a call that names the referenced   
   >> function statically, and such a call is always legal. Problems arise   
   >> only if the function-variable has some invalid value such as NULL, or   
   >> the address of a function with a different profile, or some code address   
   >> that does not refer to (the start of) a function. Such invalid values   
   >> can be prevented at compile time, except (usually) for NULL.   
   >>   
   >> In the same language setting, the semantics of a jump using a   
   >> label-variable are easy to define only if the label-variable refers to a   
   >> label in the same block as the jump. A jump from one block into another   
   >> would mess up the context, omitting the set-up of the target block's   
   >> context and/or omitting the tear-down of the source block's context. The   
   >> further results of program execution are machine-dependent and so   
   >> undefined behavior.   
   >>   
   >> A compiler could enforce the label-in-same-block rule, but it seems that   
   >> GNU C does not do so.   
   >>   
   >> In a programming language that allows nested functions the same kind of   
   >> context-crossing problems arise for function-variables. Traditional   
   >> languages solve them by allowing, at compile-time, calls via   
   >> function-variables only if it is certain that the containing context of   
   >> the callee still exists (if the callee is nested), or by (expensively)   
   >> preserving that context as a dynamically constructed closure. In either   
   >> case, the caller's context never needs to be torn down to execute the   
   >> call, differing from the jump case.   
   >>   
   >> In summary, jumps via label-variables are useful only for control   
   >> transfers within one function, and do not help to build up a computation   
   >> by combining several functions -- the main method of program design at   
   >> present. In contrast, calls via function-variables are a useful   
   >> extension to static calls, actually helping to combine several functions   
   >> in a computation, as shown by the general adoption of   
   >> class/object/method coding styles.   
   >>   
   >> Niklas   
   >>   
   >   
   > I was curious about the interaction between dynamic stack allocations   
   > and goto variables to see if it handled the block scoping correctly.   
   > Ada should have the same issues as C.   
   > It appears GCC x86-64 15.2 with -O3 does not properly recover   
   > stack space with dynamic goto's.   
   >   
   > Test1 allocates a dynamic sized buffer and has a static goto Loop   
   > for which GCC generates a jne .L6 to a mov rsp, rbx that recovers   
   > the stack allocation inside the {} block.   
   >   
   > Test2 is the same but does a goto *dest and GCC does not generate   
   > code to recover the inner {} block allocation. It just loops over   
   > the sub rsp, rbx so the stack space just grows.   
   >   
   > long Sub (long len, char buf[]);   
   >   
   > void Test1 (long len)   
   > {   
   > long ok;   
   >   
   > Loop:   
   > {   
   > char buf[len];   
   >   
   > ok = Sub (len, buf);   
   > if (ok)   
   > goto Loop;   
   > }   
   > }   
      
   IIRC there is clear statement in the C standard that you are not   
   allowed to jump into a scope after a dynamic declaration. This   
   restriction is because otherwise compiler would need some twisty   
   logic to run allocation code. With label variables that obvoiusly   
   generalizes to jumps outside of scope of dynamic allocation:   
   compiler does not try to recover allocated storage. Your code   
   does not differ much from infinite recursion. In case of   
   infinte recursion compiler _may_ be able to optimize things   
   so that they run in constant memory, but usually such   
   recursion will lead to stack overflow.   
      
   So natural restriction is: when jumping to label variable   
   dynamic locals may be released only at function exit.   
      
   --   
    Waldek Hebisch   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|