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]

setjmp/longjmp: Wrong code generation


Hi,

with GCC 4.1 and GCC 4.4 (RHEL 5.9) the example below prints a value
of 1 for netwait (on x86_64 and s390x).  The problem is that the
assignment at /* 2 */ is moved to /* 1 */ during instruction
scheduling.

The quick fix is to make "netwait" volatile.  But according to the C
standard (7.13.2.1) this should only be necessary if the value is
modified between setjmp and longjmp.

http://gcc.gnu.org/onlinedocs/gcc/Incompatibilities.html#Incompatibilities
shows an example which also modifies the variable between
setjmp/longjmp. However, a sentence in the same section is more
general and suggests to always use volatile: "When you use setjmp and
longjmp, the only automatic variables guaranteed to remain valid are
those declared volatile."

I'm wondering whether the behaviour in the example below is accepted
and is supposed to be covered by the paragraph on the
"incompatibilies" page or whether we should try to fix this?  In the
end it is still a standard violation so I think we should?!

A possible fix might be to consider all function calls in the function
scope of setjmp to be full scheduling barriers.

I was not able to reproduce the problem with head GCC. But I couldn't
find anything which addresses the problem either.  So I assume that a
different situation before the scheduling pass hides the problem.

Bye,

-Andreas-


#include <setjmp.h>
#include <stdio.h>

jmp_buf jmpbuf;

void __attribute__((noinline))
  calls_longjmp()
{
  longjmp(jmpbuf, 2);
}

int __attribute__((noinline))
foo ()
{
  return 42;
}

void __attribute__((noinline))
bar (int netwait, int cnt)
{
  int i;
  int err;

  while (netwait)
    {
      netwait = 0;

      for (i = cnt; --i >= 0;)
	{
	  if (setjmp(jmpbuf) == 0)
	    {
	      err = foo ();
	      /* 1 */
	      if (err != 2344)
		calls_longjmp();
	      netwait = 1; /* 2 */
	    }
	  else
	    {
	      printf ("netwait: %d\n", netwait);
	      netwait = 0;
	    }
	}
    }
} 

int
main ()
{
  bar (1, 1);
}


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