Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #70965 > unrolled thread

why "int s = setjmp(env)" fails?

Started byi@introo.me
First post2015-09-19 21:59 -0700
Last post2015-09-20 11:11 -0400
Articles 12 — 8 participants

Back to article view | Back to comp.lang.c


Contents

  why "int s = setjmp(env)" fails? i@introo.me - 2015-09-19 21:59 -0700
    Re: why "int s = setjmp(env)" fails? Nobody <nobody@nowhere.invalid> - 2015-09-20 10:53 +0100
    Re: why "int s = setjmp(env)" fails? Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-09-20 07:47 -0400
      Re: why "int s = setjmp(env)" fails? supercat@casperkitty.com - 2015-09-21 08:51 -0700
        Re: why "int s = setjmp(env)" fails? Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-09-21 12:52 -0400
          Re: why "int s = setjmp(env)" fails? supercat@casperkitty.com - 2015-09-21 11:44 -0700
            Re: why "int s = setjmp(env)" fails? Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-09-21 15:52 -0400
              Re: why "int s = setjmp(env)" fails? supercat@casperkitty.com - 2015-09-22 11:51 -0700
          Re: why "int s = setjmp(env)" fails? Tim Rentsch <txr@alumni.caltech.edu> - 2015-09-26 17:06 -0700
          Re: why "int s = setjmp(env)" fails? Paul N <gw7rib@aol.com> - 2015-09-28 14:28 -0700
    Re: why "int s = setjmp(env)" fails? Keith Thompson <kst-u@mib.org> - 2015-09-20 07:33 -0700
    Re: why "int s = setjmp(env)" fails? James Kuyper <jameskuyper@verizon.net> - 2015-09-20 11:11 -0400

#70965 — why "int s = setjmp(env)" fails?

Fromi@introo.me
Date2015-09-19 21:59 -0700
Subjectwhy "int s = setjmp(env)" fails?
Message-ID<d8e6c449-3aad-405e-b8a2-5fa73ee6a9a3@googlegroups.com>
while(setjmp(env)) will succeed,  (1)

however,

volatile int s = setjmp(env) will fail.  (2)


what's the technical complexity/difficulty that hinders (2) ?

AFAIK, (2) is still a simple statment.

[toc] | [next] | [standalone]


#70971

FromNobody <nobody@nowhere.invalid>
Date2015-09-20 10:53 +0100
Message-ID<pan.2015.09.20.09.53.46.185000@nowhere.invalid>
In reply to#70965
On Sat, 19 Sep 2015 21:59:05 -0700, i wrote:

> while(setjmp(env)) will succeed,  (1)
> 
> however,
> 
> volatile int s = setjmp(env) will fail.  (2)
> 
> 
> what's the technical complexity/difficulty that hinders (2) ?

7.13.1.1 says:

[#4] An invocation of the setjmp macro shall appear only
in one of the following contexts:

 --  the entire controlling expression of a selection or
     iteration statement;
     
 --  one operand of a relational or equality operator with the
     other operand an integer constant expression, with the
     resulting expression being the entire controlling
     expression of a selection or iteration statement;
     
 --  the operand of a unary ! operator with the resulting
     expression being the entire controlling expression of a
     selection or iteration statement; or
     
 --  the entire expression of an expression statement
     (possibly cast to void).

[#5] If the invocation appears in any other context, the
behavior is undefined.

(1) is covered by the first clause of #4. (2) comes under #5.

> AFAIK, (2) is still a simple statment.

(2) isn't any kind of statement, it's a declaration.

[toc] | [prev] | [next] | [standalone]


#70972

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2015-09-20 07:47 -0400
Message-ID<mtm688$rms$1@dont-email.me>
In reply to#70965
On 9/20/2015 12:59 AM, i@introo.me wrote:
> while(setjmp(env)) will succeed,  (1)
>
> however,
>
> volatile int s = setjmp(env) will fail.  (2)
>
>
> what's the technical complexity/difficulty that hinders (2) ?

     "Nobody" has given you the Standard's language covering the
issue.  However, I imagine you were not asking about the existence
of the Standard's peculiar-seeming restrictions, but about the
reasons for them.  The same people who wrote the Standard and who
continue to amend it also maintain a companion document called the
Rationale, which tries to explain some of their thinking.  In the
matter of setjmp() and longjmp(), the Rationale says

	"One proposed requirement on setjmp is that it be usable like
	any other function [...]  Unfortunately, any implementation of
	setjmp as a conventional called function cannot know enough
	about the calling environment to save any temporary registers
	or dynamic stack locations used part way through an expression
	evaluation. [...]  The temporaries may be correct on the
	initial call to setjmp, but are not likely to be on any return
	initiated by a corresponding call to longjmp. These
	considerations dictated the constraint that setjmp be called
	only from within fairly simple expressions, ones not likely to
	need temporary storage.

	"An alternative proposal considered by the C89 Committee was to
	require that implementations recognize that calling setjmp is a
	special case, and hence that they take whatever precautions
	are necessary to restore the setjmp environment properly upon a
	longjmp call. This proposal was rejected on grounds of
	consistency: implementations are currently allowed to implement
	library functions specially, but no other situations require
	special treatment."

     If even this seems unconvincing to you, keep in mind that the
Standard is the product of many authors, who have (collectively) far
wider knowledge of "peculiar" platforms than any one person is likely
to possess.  Somebody in that group, perhaps several somebodies, told
the others about circumstances and machines where a seemingly simple
operation could be anything but, and the others listened to the tale.
See also, for example, the development of the <stdarg.h> facilities,
motivated by the fact that the older <varargs.h> API created problems
for some platforms.

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM

[toc] | [prev] | [next] | [standalone]


#71018

Fromsupercat@casperkitty.com
Date2015-09-21 08:51 -0700
Message-ID<f82143ca-2f45-4ea4-bc78-dc43962cab8b@googlegroups.com>
In reply to#70972
On Sunday, September 20, 2015 at 6:47:22 AM UTC-5, Eric Sosman wrote:
> 	"One proposed requirement on setjmp is that it be usable like
> 	any other function [...]

Would it have been overly burdensome to allow implementations to properly
handle one additional case: assigning the result directly to a volatile-
qualified automatic variable of type "int"?  Anything one might want to
do with the result could be done after such assignment, but the usefulness
of the parameter to "setjmp" is severely limited by an inability to use
the result more than once.  On a 16-bit system one could obtain the result
purely within "Standard C" via:

    int result; // Wouldn't even need to be volatile
    switch(setjmp(env))
    {
      case -32767-1: result = -32767-1; break;
      case -32767: result = -32767; break;
      case -32766: result = -32766; break;
      ...65531 lines omitted
      case 32766: result = 32766; break;
      case 32767: result = 32767; break;
    }

but that approach isn't exactly reasonable even on a 16-bit system; on a
32-bit system it would be even more absurd and on a 64-bit system it would
be downright impossible.  Since the compiler must know where pre-declared volatile-qualified automatic variables are located as soon as control
returns to setjmp, most compilers would not need to do anything more to
support

    volatile int foo;
    foo = setjmp(env);

than would be necessary to support the strictly-conforming:

    volatile int foo;
    foo = 0;
    setjmp(env);
    if (!foo++)  // Can't use any cached value for "foo", and can't use any
                 // cached address unless setjmp/longjmp save/restore it.
    {
      .. first time code that might call something that invokes longjmp
    }
    else
    {
      .. code for use after longjmp
    }


[toc] | [prev] | [next] | [standalone]


#71021

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2015-09-21 12:52 -0400
Message-ID<mtpch6$a2s$1@dont-email.me>
In reply to#71018
On 9/21/2015 11:51 AM, supercat@casperkitty.com wrote:
> On Sunday, September 20, 2015 at 6:47:22 AM UTC-5, Eric Sosman wrote:
>> 	"One proposed requirement on setjmp is that it be usable like
>> 	any other function [...]
>
> Would it have been overly burdensome to allow implementations to properly
> handle one additional case: assigning the result directly to a volatile-
> qualified automatic variable of type "int"?

     The evidence available (the Standard and the Rationale) suggests
that the answer to your question is one of:

	"Yes" -- Some implementor or implementors believed, and
	convinced the others to believe, that it would have been overly
	burdensome.

	"No" -- The authors of the Standard were a bunch of imbeciles,
	not one of whom knew anything about C, compilers, or computers.

     Take your pick.

> Anything one might want to
> do with the result could be done after such assignment, but the usefulness
> of the parameter to "setjmp"

     ITYM the parameter to longjmp().

> is severely limited by an inability to use
> the result more than once.  On a 16-bit system one could obtain the result
> purely within "Standard C" via:
>
>      int result; // Wouldn't even need to be volatile
>      switch(setjmp(env))
>      {
>        case -32767-1: result = -32767-1; break;
>        case -32767: result = -32767; break;
>        case -32766: result = -32766; break;
>        ...65531 lines omitted
>        case 32766: result = 32766; break;
>        case 32767: result = 32767; break;
>      }

     Where is it written that the value returned by setjmp() is the
one and only value available to the code?

	jmp_buf env;
	int result;
	if (setjmp(env) == 0) {
	    do_things(env, &result);
	} else {
	    printf("longjmp'ed for reason #%d\n", result);
	}
	...
	void do_things(jmp_buf env, int *result) {
	    ...
	    // Bail out!
	    *result = 42;
	    longjmp(env, 1);
	}

Observe that `result' could, if desired, be of any (complete) type
at all: int, double, struct foobar, ...

     The fact that a preordained signalling channel is available does
not mean you cannot also use other and less restrictive channels.

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM

[toc] | [prev] | [next] | [standalone]


#71025

Fromsupercat@casperkitty.com
Date2015-09-21 11:44 -0700
Message-ID<fb16b8a6-ef68-4214-b2ae-78a401efb339@googlegroups.com>
In reply to#71021
On Monday, September 21, 2015 at 11:52:57 AM UTC-5, Eric Sosman wrote:
> 	"No" -- The authors of the Standard were a bunch of imbeciles,
> 	not one of whom knew anything about C, compilers, or computers.

Or else the authors made their decision at a time when there would have
been no difficulty with simply using a global variable for the purpose (and
thus not much benefit to allowing the indicated usage), and have
not re-evaluated that decision in the light of things like threading which
have become much more relevant in years since.

Given that compilers are required to handle "setjmp" as a switch() operand,
I find it hard to imagine an implementation where an assignment to an
automatic volatile variable would be problematic.

>      Where is it written that the value returned by setjmp() is the
> one and only value available to the code?

> Observe that `result' could, if desired, be of any (complete) type
> at all: int, double, struct foobar, ...

That style requires either that all functions between the "setjmp" and the
"longjmp" pass the necessary address.  Using a static or thread-static
variable may sometimes be more practical in cases where the jmp_buff itself
is such a variable, but may itself be somewhat icky.

>      The fact that a preordained signalling channel is available does
> not mean you cannot also use other and less restrictive channels.

I guess I'm curious as to the intended usage of the longjmp() parameter.  I
guess in the scenario where one wants to distinguish two kinds of longjmp()
actions, one could pass values of 1 and 2, use an automatic volatile
variable to distinguish the first and second returns from setjmp(), and
thus compare the return value of "longjmp" against 1 (and in the case where
it isn't 1, use the other automatic variable to distinguish cases where it
would have returned zero) but it seems rather more awkward than just being
able to store the return to a local variable.

[toc] | [prev] | [next] | [standalone]


#71033

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2015-09-21 15:52 -0400
Message-ID<mtpn33$nb7$1@dont-email.me>
In reply to#71025
On 9/21/2015 2:44 PM, supercat@casperkitty.com wrote:
> On Monday, September 21, 2015 at 11:52:57 AM UTC-5, Eric Sosman wrote:
>> 	"No" -- The authors of the Standard were a bunch of imbeciles,
>> 	not one of whom knew anything about C, compilers, or computers.
>
> Or else the authors made their decision at a time when there would have
> been no difficulty with simply using a global variable for the purpose (and
> thus not much benefit to allowing the indicated usage), and have
> not re-evaluated that decision in the light of things like threading which
> have become much more relevant in years since.

     Thread-local storage exists for a reason.

> Given that compilers are required to handle "setjmp" as a switch() operand,
> I find it hard to imagine an implementation where an assignment to an
> automatic volatile variable would be problematic.

     Okay: You find it hard to imagine.  Apparently, the Committee's
imagination roamed more widely than yours.

>>       Where is it written that the value returned by setjmp() is the
>> one and only value available to the code?
>
>> Observe that `result' could, if desired, be of any (complete) type
>> at all: int, double, struct foobar, ...
>
> That style requires either that all functions between the "setjmp" and the
> "longjmp" pass the necessary address.  Using a static or thread-static
> variable may sometimes be more practical in cases where the jmp_buff itself
> is such a variable, but may itself be somewhat icky.

     Observe that the `jmp_buf' must also be communicated from the
setjmp() caller to the longjmp() caller, so passing a result slot
incurs no ickiness beyond whatever is already present.  Put both
the `jmp_buf' and the result in a single struct, if you like.

>>       The fact that a preordained signalling channel is available does
>> not mean you cannot also use other and less restrictive channels.
>
> I guess I'm curious as to the intended usage of the longjmp() parameter.  I
> guess in the scenario where one wants to distinguish two kinds of longjmp()
> actions, one could pass values of 1 and 2, use an automatic volatile
> variable to distinguish the first and second returns from setjmp(), and
> thus compare the return value of "longjmp" against 1 (and in the case where
> it isn't 1, use the other automatic variable to distinguish cases where it
> would have returned zero) but it seems rather more awkward than just being
> able to store the return to a local variable.

     Sure, it's more awkward.  It's a weird-on-the-face-of-it set of
restrictions.  But then, setjmp() itself is pretty weird, too.

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM

[toc] | [prev] | [next] | [standalone]


#71107

Fromsupercat@casperkitty.com
Date2015-09-22 11:51 -0700
Message-ID<27503c1b-c304-4c19-8081-c289588e014f@googlegroups.com>
In reply to#71033
On Monday, September 21, 2015 at 2:53:03 PM UTC-5, Eric Sosman wrote:
>      Okay: You find it hard to imagine.  Apparently, the Committee's
> imagination roamed more widely than yours.

I tend to think I have a pretty good imagination about such things.  Were
it not for the requirement to support "switch()", I could imagine platforms
where it might be difficult for longjmp to pass more than a bit, which would
translate "if (setjmp(env) == 34)..." as 

  env.interesting_value = 34;
  if (__setjmp(env)) ...

but since "switch" can detect an arbitrary number of values I don't see how
a system could support that without being able to have an integer get
stored into a volatile automatic variable.

My personal guess is that the authors of the Standard realized there were
cases which would be problematic (including storing to a non-volatile
variable), conducted a survey of all the code they could find to see what
forms people were using, and declared as legitimate all the non-problematic
forms that were already in use.  If all the existing code which stored to
a local variable was written for systems where use of a non-volatile
variable would pose no problem, the Committee may not have felt a need to
authorize a form (storing to a volatile-qualified variable) that nobody
was using.

>      Observe that the `jmp_buf' must also be communicated from the
> setjmp() caller to the longjmp() caller, so passing a result slot
> incurs no ickiness beyond whatever is already present.  Put both
> the `jmp_buf' and the result in a single struct, if you like.

If all layers through which the jmp_buf must be passed are under the
control of the code at both ends, that will work fine.  If some of the
the mid-layer code passes a jmp_buf but does not have a provision to
pass anything else, things may be more problematic.

>      Sure, it's more awkward.  It's a weird-on-the-face-of-it set of
> restrictions.  But then, setjmp() itself is pretty weird, too.

True that.  

[toc] | [prev] | [next] | [standalone]


#71246

FromTim Rentsch <txr@alumni.caltech.edu>
Date2015-09-26 17:06 -0700
Message-ID<kfnbncoeneu.fsf@x-alumni2.alumni.caltech.edu>
In reply to#71021
Eric Sosman <esosman@comcast-dot-net.invalid> writes:

> On 9/21/2015 11:51 AM, supercat@casperkitty.com wrote:
>> On Sunday, September 20, 2015 at 6:47:22 AM UTC-5, Eric Sosman wrote:
>>> 	"One proposed requirement on setjmp is that it be usable like
>>> 	any other function [...]
>>
>> Would it have been overly burdensome to allow implementations to properly
>> handle one additional case:  assigning the result directly to a volatile-
>> qualified automatic variable of type "int"?
>
>     The evidence available (the Standard and the Rationale) suggests
> that the answer to your question is one of:
>
>     "Yes" -- Some implementor or implementors believed, and
>     convinced the others to believe, that it would have been overly
>     burdensome.
>
>     "No" -- The authors of the Standard were a bunch of imbeciles,
>     not one of whom knew anything about C, compilers, or computers.
>
> [and no others]

I don't agree with this conclusion.  Looking at those two
sources, I think the authors might have thought this case was
overly burdensome;  or they might have thought it wasn't
important to provide it, without considering how burdensome
it would be;  or they might have simply overlooked it and
not thought about it at all (possibly because there were
no examples of prior use, which is only natural considering
the status of 'volatile' at the time).  I can get into the
why's and wherefore's if someone is interested, but for now
I just wanted to note that it might bear more discussion.

[toc] | [prev] | [next] | [standalone]


#71394

FromPaul N <gw7rib@aol.com>
Date2015-09-28 14:28 -0700
Message-ID<13c29d95-4d5a-4618-83a8-26d6d8c290d8@googlegroups.com>
In reply to#71021
On Monday, 21 September 2015 17:52:57 UTC+1, Eric Sosman  wrote:
>      The evidence available (the Standard and the Rationale) suggests
> that the answer to your question is one of:
> 
> 	"Yes" -- Some implementor or implementors believed, and
> 	convinced the others to believe, that it would have been overly
> 	burdensome.
> 
> 	"No" -- The authors of the Standard were a bunch of imbeciles,
> 	not one of whom knew anything about C, compilers, or computers.
> 
>      Take your pick.

If you believe that a group of intelligent programmers won't spend a lot of time doing completely unnecessary work in their programs, without even realising how unnecessary it is, may I suggest that you google "MakeProcInstance"?

[toc] | [prev] | [next] | [standalone]


#70973

FromKeith Thompson <kst-u@mib.org>
Date2015-09-20 07:33 -0700
Message-ID<lnwpvlcg9m.fsf@kst-u.example.com>
In reply to#70965
i@introo.me writes:
> while(setjmp(env)) will succeed,  (1)
>
> however,
>
> volatile int s = setjmp(env) will fail.  (2)

What do you mean by "fail"?  The standard doesn't define the behavior,
but that deons't *necessarily* mean it won't "work".

> what's the technical complexity/difficulty that hinders (2) ?
>
> AFAIK, (2) is still a simple statment.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#70977

FromJames Kuyper <jameskuyper@verizon.net>
Date2015-09-20 11:11 -0400
Message-ID<55FECC86.9@verizon.net>
In reply to#70965
On 09/20/2015 12:59 AM, i@introo.me wrote:
> while(setjmp(env)) will succeed,  (1)
> 
> however,
> 
> volatile int s = setjmp(env) will fail.  (2)
> 
> 
> what's the technical complexity/difficulty that hinders (2) ?
> 
> AFAIK, (2) is still a simple statment.

"Nobody" has already cited for you the relevant rules, and Eric Sosman
have given you the general context of why those rules were written that
way. But neither has explained specifically what the problem is. If you
look at the rules "Nobody" cited, you notice a common thread: every
place where setjmp() calls don't have undefined behavior falls into one
of two categories: the return value from setjmp is either completely
ignored, or is used immediately to determine how the code will branch,
without being stored anywhere, not even as a temporary in a more
complicated expression. It would appear to be the case that it's the
storage of the return value that the committee considered to be
problematic. Why? I don't know, I'm not an implementor, and the reason
isn't obvious to me - but that does seem to be the relevant issue.

If you want to know which value setjmp() returned, make it the
controlling expression of a switch() statement, and provide case:
statements for each value you're interested in distinguishing from the
default: case.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web