Bill Allombert on Mon, 25 Sep 2006 13:34:56 +0200


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

possible fix for hang/segv/corruption after ^C


Hello PARI-dev,

I am investigating the issues of GP misbehaving (hanging, crashing,
etc.) after a SIGINT (Control-C interrupt). Examples can be found in
bugs #458 and #488.

The rather crude patch should improve a lot the situation. It works
by delaying handling of SIGINT that occurs during malloc/realloc/free
calls after the call is completed. 

Please test thoroughly. If it still hang, please try to attach a
debugger and get a backtrace, this would help a lot.

When GP get a SIGINT it will 'try to recover' and then longjmp to the
main loop. The issue is that some part of the memory might be in an
inconsistent state. PARI/GP try hard to avoid that to happen.

The situation is:
- system stack: this is reset by longjmp itself.
- PARI stack: this is reset by GP
- PARI heap: this is recovered by try_to_recover().
- system heap: not recovered.

Since it is not possible to recover system heap, we should delay
handling of SIGINT after functions that operate on the system heap
have completed. The patch take care of the most frequent ones:
malloc/realloc/free. Other functions could be covered if the need
arise.

The patch works by adding two boolean variables, pari_do_sigint and
pari_did_sigint:

pari_do_sigint: whether SIGINT should be handled (1) or deferred(0)
pari_did_sigint: whether there is a pending SIGINT.

User installed handlers are not affected unless they manage these 
variables themselves.

Cheers,
Bill.
Index: src/gp/gp.c
===================================================================
RCS file: /home/cvs/pari/src/gp/gp.c,v
retrieving revision 1.293
diff -u -r1.293 gp.c
--- src/gp/gp.c	25 Sep 2006 08:47:45 -0000	1.293
+++ src/gp/gp.c	25 Sep 2006 09:09:18 -0000
@@ -1499,7 +1499,10 @@
     case SIGBREAK: gp_handle_SIGINT(); return;
 #endif
 #ifdef SIGINT
-    case SIGINT:   gp_handle_SIGINT(); return;
+    case SIGINT:
+      if (pari_do_sigint) gp_handle_SIGINT(); 
+      else pari_did_sigint=1;
+      return;
 #endif
 
 #ifdef SIGSEGV
Index: src/language/anal.h
===================================================================
RCS file: /home/cvs/pari/src/language/anal.h,v
retrieving revision 1.83
diff -u -r1.83 anal.h
--- src/language/anal.h	18 Sep 2006 21:53:40 -0000	1.83
+++ src/language/anal.h	24 Sep 2006 21:57:59 -0000
@@ -76,6 +76,7 @@
 char *term_get_color(long c);
 void hit_return(void);
 
+extern VOLATILE int pari_do_sigint, pari_did_sigint;
 extern THREAD char *gp_function_name;
 extern int  (*whatnow_fun)(char *, int);
 extern void (*sigint_fun)(void);
Index: src/language/init.c
===================================================================
RCS file: /home/cvs/pari/src/language/init.c,v
retrieving revision 1.315
diff -u -r1.315 init.c
--- src/language/init.c	25 Sep 2006 08:47:45 -0000	1.315
+++ src/language/init.c	25 Sep 2006 11:21:02 -0000
@@ -236,12 +236,21 @@
 /*********************************************************************/
 static int var_not_changed; /* altered in reorder() */
 static int try_to_recover = 0;
+VOLATILE int pari_do_sigint = 1, pari_did_sigint = 0;
 static GEN universal_constants;
+static void pari_sighandler(int sig);
 
 void
 gpfree(void *pointer)
 {
+  pari_do_sigint = 0;
   free(pointer);
+  pari_do_sigint = 1;
+  if (pari_did_sigint)
+  {
+    pari_did_sigint=0;
+    raise(SIGINT);
+  }
 }
 
 char*
@@ -249,7 +258,15 @@
 {
   if (size)
   {
-    char *tmp = (char*)malloc(size);
+    char *tmp;
+    pari_do_sigint = 0;
+    tmp = (char*)malloc(size);
+    pari_do_sigint = 1;
+    if (pari_did_sigint)
+    {
+      pari_did_sigint=0;
+      raise(SIGINT);
+    }
     if (!tmp) pari_err(memer);
     return tmp;
   }
@@ -262,8 +279,15 @@
 {
   char *tmp;
 
+  pari_do_sigint = 0;
   if (!pointer) tmp = (char *) malloc(size);
   else tmp = (char *) realloc(pointer,size);
+  pari_do_sigint = 1;
+  if (pari_did_sigint)
+  {
+    pari_did_sigint=0;
+    raise(SIGINT);
+  }
   if (!tmp) pari_err(memer);
   return tmp;
 }
@@ -302,7 +326,10 @@
     case SIGBREAK: pari_handle_SIGINT(); return;
 #endif
 #ifdef SIGINT
-    case SIGINT:   pari_handle_SIGINT(); return;
+    case SIGINT:
+      if (pari_do_sigint) pari_handle_SIGINT();
+      else pari_did_sigint=1;
+      return;
 #endif
 
 #ifdef SIGSEGV