Patch: catch_errors() cleanup chain restore
nsd@cygnus.com
nsd@cygnus.com
Sat Apr 1 00:00:00 GMT 2000
Hi,
If a quit happens within catch_errors(RETURN_MASK_ERROR), the cleanup
chain gets lost.
This is the offending sequence of events:
1. catch_errors() calls save_cleanups(), which zeros the cleanup chain.
2. catch_errors() redirects the error longjmp target to a location that
will call restore_cleanups(), but doesn't redirect the quit longjmp
target similarly when RETURN_MASK_ERROR is specified.
3. A subsequent quit event longjmps back to top level, skipping past
the restore_cleanups() call in catch_errors().
An error within catch_errors(RETURN_MASK_QUIT) would have the same effect,
but there aren't any such calls in gdb at the moment.
It's easy to fix by:
1. unconditionally redirecting both the error and quit longjmp targets;
2. calling the function argument;
3. restoring the cleanup chain;
4. calling return_to_top_level() if appropriate.
I've appended a patch to do that. Comments welcome,
Nick Duffek
nsd@cygnus.com
[patch follows]
Index: top.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/top.c,v
retrieving revision 2.176
diff -u -r2.176 top.c
--- top.c 2000/02/09 03:28:18 2.176
+++ top.c 2000/02/11 20:28:52
@@ -580,61 +580,65 @@
char *errstring;
return_mask mask;
{
- SIGJMP_BUF saved_error;
- SIGJMP_BUF saved_quit;
- SIGJMP_BUF tmp_jmp;
+ SIGJMP_BUF saved_error, tmp_error;
+ SIGJMP_BUF saved_quit, tmp_quit;
int val;
struct cleanup *saved_cleanup_chain;
char *saved_error_pre_print;
char *saved_quit_pre_print;
+ int caught = 0;
saved_cleanup_chain = save_cleanups ();
saved_error_pre_print = error_pre_print;
saved_quit_pre_print = quit_pre_print;
+ memcpy ((char *) saved_error, (char *) error_return, sizeof (SIGJMP_BUF));
if (mask & RETURN_MASK_ERROR)
- {
- memcpy ((char *) saved_error, (char *) error_return, sizeof (SIGJMP_BUF));
- error_pre_print = errstring;
- }
+ error_pre_print = errstring;
+
+ memcpy (saved_quit, quit_return, sizeof (SIGJMP_BUF));
if (mask & RETURN_MASK_QUIT)
+ quit_pre_print = errstring;
+
+ if (SIGSETJMP (tmp_error) == 0)
+ memcpy (error_return, tmp_error, sizeof (SIGJMP_BUF));
+ else
{
- memcpy (saved_quit, quit_return, sizeof (SIGJMP_BUF));
- quit_pre_print = errstring;
+ caught = RETURN_MASK_ERROR;
+ goto called;
}
- if (SIGSETJMP (tmp_jmp) == 0)
+ if (SIGSETJMP (tmp_quit) == 0)
+ memcpy (quit_return, tmp_quit, sizeof (SIGJMP_BUF));
+ else
{
- if (mask & RETURN_MASK_ERROR)
- memcpy (error_return, tmp_jmp, sizeof (SIGJMP_BUF));
- if (mask & RETURN_MASK_QUIT)
- memcpy (quit_return, tmp_jmp, sizeof (SIGJMP_BUF));
- val = (*func) (args);
- /* FIXME: cagney/1999-11-05: A correct FUNC implementaton will
- clean things up (restoring the cleanup chain) to the state
- they were just prior to the call. Technically, this means
- that the below restore_cleanups call is redundant.
- Unfortunatly, many FUNC's are not that well behaved.
- restore_cleanups should either be replaced with a do_cleanups
- call (to cover the problem) or an assertion check to detect
- bad FUNCs code. */
+ caught = RETURN_MASK_QUIT;
+ goto called;
}
- else
- val = 0;
+ val = (*func) (args);
+ called:
restore_cleanups (saved_cleanup_chain);
+ memcpy (error_return, saved_error, sizeof (SIGJMP_BUF));
if (mask & RETURN_MASK_ERROR)
- {
- memcpy (error_return, saved_error, sizeof (SIGJMP_BUF));
- error_pre_print = saved_error_pre_print;
- }
+ error_pre_print = saved_error_pre_print;
+
+ memcpy (quit_return, saved_quit, sizeof (SIGJMP_BUF));
if (mask & RETURN_MASK_QUIT)
+ quit_pre_print = saved_quit_pre_print;
+
+ if (!caught)
+ return val;
+
+ if (!(mask & caught))
{
- memcpy (quit_return, saved_quit, sizeof (SIGJMP_BUF));
- quit_pre_print = saved_quit_pre_print;
+ if (caught == RETURN_MASK_ERROR)
+ return_to_top_level (RETURN_ERROR);
+ else
+ return_to_top_level (RETURN_QUIT);
}
- return val;
+ return 0;
}
struct captured_command_args
More information about the Gdb-patches
mailing list