[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::decc

Title:DECC
Notice:General DEC C discussions
Moderator:TLE::D_SMITHNTE
Created:Fri Nov 13 1992
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:2212
Total number of notes:11045

2166.0. "setjmp, longjmp confusion" by CSC32::J_HENSON (Don't get even, get ahead!) Mon Apr 28 1997 11:35

dec c v5.5-003 (and -002), ovms v7.1, alpha

I am confused as to what to expect when using setjmp and longjmp.  Should
local variables be affected?

Take the following program as an exmaple.  After a successful call to
setjmp, the local variable a is set to 1.  This is followed by a
call to longjmp with the same environment variable used by the
prior call to setjmp.

At this point, the value in the local variable a is restored to its
value prior to the call to setjmp.  It appears that the optimizer has
saved it's contents in a register, and when the registers get restored
by longjmp, so does a.

This seems reasonable enough when compiling with defaults, but what
should the expected results be when compiled with /nooptimize?  In
this case, the variable a is still being reset to 0 after the call
to longjmp.  Is this right?  

It seems that the only way to NOT have a restored to it's pre-setjmp
value is to declare it volatile.  For the customer reporting this,
this means changing a lot of code versus simply compiling everything
with /noop.

FWIW, when compiling with /noop on dec c v5.3-006 for OpenVMS Vax, 
the value is a is not restored to 0.  Seems like one of these
is wrong.

Please advise.

Jerry

=========================================================================

#include <setjmp.h>
#include <stdio.h>
main()
{
    int     a = 0;
    jmp_buf env;

    if( setjmp( env ) == 0 ) {
        a = 1;
        longjmp( env, 1 );
    } else {
        printf( "%d\n", a );
    }
}

T.RTitleUserPersonal
Name
DateLines
2166.1DECCXL::OUELLETTEmudseason into blackfly seasonMon Apr 28 1997 12:3325
From the ANSI and ISO C language standard.

4.6.2 Restore Calling Environment
4.6.2.1 The longjmp function

Paragraph at line 11:

All accessible objects have values as of the time lonjmp was called, except
that the values of objects of automatic storage duration that are local to
the function containing the invocation of the corresponding setjmp macro
that do not have volatile-qualified type and have been changed between the
setjmp invocation and the longjmp call are indeterminate.

To have portable code, you must qualify those automatic variables which
must stay updated with volatile.

On Windows NT on Alpha there are two setjmp/longjmp pairs.
One interoperates with C++ Exception Handling and C Structured Exception
Handling by unwinding the stack frames to call dtors and finally handlers
as well as perhaps being intercepted by catch or except clauses.
This has the sideeffect of restoring automatics to their most recent value.

Perhaps one of the several setjmp/longjmp implementations on Unix (you are
on Unix right?) does that.  I'll let someone more familliar give a
definitive answer.
2166.2notes collisionSPECXN::DERAMODan D&#039;EramoMon Apr 28 1997 12:3653
>It seems that the only way to NOT have a restored to it's pre-setjmp
>value is to declare it volatile.
        
        Yes.  Actually, static will work too, but beware if the
        routine can be "active" more than once (recursive calls,
        AST's, multiple threads, signals, etc.).  Volatile is
        definitely the way to go.
        
        From topic 935 here:
        
>935.0
>In the ANSI C standard section 4.6.2.1 page 120 it says
>
>          All accessible objects have values as of the time longjmp
>        was called, except that the values of objects of automatic
>        storage duration that are local to the function containing
>        the invocation of the corresponding setjmp macro that do not
>        have volatile-qualified type and have been changed between
>        the setjmp invocation and the longjmp call are indeterminate.
        
        There is similar language in the DEC C Run-Time Library
        Reference Manual for OpenVMS Systems in the "man page" for
        setjmp:
        
>        The setjmp function preserves the hardware general purpose
>        registers, and the longjmp function restores them.  After a
>        longjmp, all variables have their values as of the time of the
>        longjmp except for local automatic variables not marked
>        volatile.  These variables have indeterminate values.
        
        [Hmmm...notice how that promises less than the standard does?]
        
        Note that while the "obvious implementation" of setjmp/longjmp
        will either leave the last assigned value in a local automatic
        nonvolatile variable or will restore its pre-setjmp value, the
        standard does not limit an implementation to just those
        choices.  If it is a local nonstatic nonvolatile variable that
        was modified between the setjmp and longjmp, then after the
        longjmp its value is "indeterminate".
        
        If they left out needed volatile qualifiers then their code is
        broken and they cannot rely upon /NOOPTIMIZE to fix it.  [I
        wouldn't be surprised if the language-specific front-end plus
        common back-end compiler architecture left it out of the C/C++
        compiler teams' hands.  Even if that is not the case, I doubt
        that setjmp/longjmp and /NOOPTIMIZE would have been implemented
        with avoidance of this effect in mind.]  The customers have to
        go through the code and put the volatile qualifiers in.  (Their
        code may not even use setjmp/longjmp directly, they may be using
        setjmp/longjmp via the TRY/CATCH/CATCH_ALL/ENDTRY and
        TRY/FINALLY/ENDTRY macros in the threads exception interface.)
        
        Dan
2166.3ThanksCSC32::J_HENSONDon&#039;t get even, get ahead!Tue Apr 29 1997 11:537
Thanks,

I'll pass it on.

Jerry

P.S.  I'm using OpenVMS, not Unix.
2166.4volatile pointer is ignoredCSC32::J_HENSONDon&#039;t get even, get ahead!Fri May 02 1997 12:2345
Still using Dec C V5.5-003 on OpenVMS Alpha V7.0

I passed on the replies to my customer, and he has come back with another
test case.  This time, it appears that the compiler is ingoring 
pointers that are declared as volatile.  The code is listed below.

When you run this (and it doesn't matter whether it's compiled
/opt or /noop), the value in the volatile int variable a is left alone,
which is what I expect.  However, the value of the volatile int
pointer variable apointer is restored to the value it had prior
to the call to setjmp.  This is not what I expect.

Could someone try this with v5.6 and see if the behavior 's the same?

Also, this appears to be a bug to me, but I've been wrong before (lots
of times).

Thanks,

Jerry

======================================================

#include <setjmp.h>
#include <stdio.h>
main()
{
    volatile int     a = 0;
    volatile int     *apointer = NULL;
    jmp_buf env;

    if( setjmp( env ) == 0 ) {
	apointer =  &a;
        a = 1;
	printf("Before longjmp\n");
	printf("apointer = %x\n",apointer);
        printf( "a = %d\n", a );
        longjmp( env, 1 );
    } else {
	printf("After longjmp\n");
	printf("apointer = %x\n",apointer);
        printf( "a = %d\n", a );
    }
}

2166.5the pointer was not volatile...DECCXL::OUELLETTEmudseason into blackfly seasonFri May 02 1997 13:1629
Your customer in this declaration:

    volatile int     *apointer = NULL;

has declared a pointer to a volatile int.
His intention was probably to declare a volatile pointer to an integer.

    int * volatile apointer = NULL;

Or perhaps a volatile pointer to a volatile int.
In that case:

    volatile int * volatile apointer = NULL;

Most users find writing this with a typedef makes things clearer:

typedef int *pint;
    volatile pint apointer = NULL;

or:

typedef volatile int *pvint;
    volatile pvint apointer = NULL;

"cc test.c -source_listing -Wf,-dump,initial" will make a listing file
(test.lis) with a dump of what the compiler's frontend is telling the
compiler's backend to do.  You can look at the placement of IO_VOLATILE
and MUST_READ, MUST_WRITE attributes on FETCHs and STOREs to educate
yourself on how the qualifiers are interpreted.
2166.6ThanksCSC32::J_HENSONDon&#039;t get even, get ahead!Mon May 05 1997 10:2721
>>    <<< Note 2166.5 by DECCXL::OUELLETTE "mudseason into blackfly season" >>>
>>                      -< the pointer was not volatile... >-

>>Your customer in this declaration:

>>    volatile int     *apointer = NULL;

>>has declared a pointer to a volatile int.
>>His intention was probably to declare a volatile pointer to an integer.

>>    int * volatile apointer = NULL;

>>Or perhaps a volatile pointer to a volatile int.
>>In that case:

>>    volatile int * volatile apointer = NULL;

Thanks.  That was it.  I have always found pointers a bit confusing,
especially in situations such as this.  Thanks for clearing this up.

Jerry