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]

longjmp()/setjmp() difference between gcc 3.3 (Apple) and gcc 3.4.x


Hello,

I'm working on a simple scripting language, in particular on its pointer implementation. In a small nutshell: the only values that are actually passed between callback functions (and that the user sees) are doubles. On a system with 32bit pointers, I can thus create a 'pointer variable' by encoding those 32bits in the 64bit double. I am testing the possibility to catch invalid memory accesses (SEGVs) when determining if a passed value represents indeed a valid pointer by using a setjmp in the parsing routine, and a longjmp in a segv_handler to that position:

segv_handler(int sig)
{
	....
	if( sig==SIGSEGV && parsing_pointer ){
		signal( SIGSEGV, segv_handler );
		longjmp(pa_jmp, 1);
	}
	....
}


void* parse_pointer( value_t value, ... )
{ static short jmpset= False;
	parsing_pointer= True;
	....
	if( /* cast value to a specific struct and check various conditions to be sure it is a pointer */ ){
		if( jmpset || setjmp(pa_jmp)== 0 ){
			jmpset= True;
			/* all OK: return pointer to internal structure */
			if( (++count) == 10 ){
			  /* blunt test if the principle works. */
				raise(SIGSEGV);
			}
		}
		else{
			/* the checking caused a SEGV since value does not represent a pointerr to an internal structure */
			/* return NULL */
		}
	}
	....
}


I use the jmpset state flag since setjmp() turns out to be very expensive: it in fact makes execution on a 1.8Ghz G5 biproc desktop system SLOWER than on a 1.5Ghz G4 laptop (not twice slower, but almost). setjmp() needs to be called only once, I think, and in any case the code sketched above works as intended. However, there is a side effect.

For testing, I raise a SEGV after 10 calls, as shown. The testing, calling code is:

for( n= i= 0; i< LOOPS; i++ ){
	if( !(ptr= parse_pointer(encoded_pointer,...)) ){
		fprintf( stderr, "parse_pointer() failed at loop i==%d, n==%d\n", i, n );
	}
	else{
		fprintf( stderr, " %d ", i );
		n+= 1;
	}
}

When compiled with gcc-3.3 (as included with Apple's XCode 1.5), this loop does what is expected: it prints a message at i==n==9, and after termination, i==LOOPS-1, n==i-1 (1 failure).
When I compile this with gcc 3.4.1 or 3.4.3, I still get the message, but the longjmp() resets n to 0, the value it had when the corresponding setjmp() was first called.

I can see the logic for both solutions, and I assume that this is exactly what is discussed in the gcc info pages concerning non-volatile automatic variables (taking n's address indeed 'solves' the issue).

Two questions:

1) Any idea why the setjmp() call is so expensive on a G5, and is there a better, less expensive way I could implement the catch mechanism?

2) Are there really no assumptions that can be made about how this situation is handled on a given system? I mean, isn't it a bit surprising that 2 versions of the same compiler family give different results on the same system? Equally surprising: the value of the loop counter i was correct all along!

Thanks!

Remy.

PS: it turns out that this parser is exactly 2x faster compiled for G5 with gcc-3.4.3 than with Apple's own gcc-3.3!


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