]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Update some stuff related to the syscalls change:
authorJeremy Fitzhardinge <jeremy@valgrind.org>
Thu, 30 Oct 2003 07:21:44 +0000 (07:21 +0000)
committerJeremy Fitzhardinge <jeremy@valgrind.org>
Thu, 30 Oct 2003 07:21:44 +0000 (07:21 +0000)
 - restart syscalls which return ERESETARTSYS
 - make code to restart a syscall common
 - keep a process-wide pending signal set to store as-yet
   undelivered signals (only used in 2.4 mode; TODO: siginfo, queues)
 - make execve work a bit better - it is impossible to recover from
   execve failing, so we try to check that it will before running the
   syscall itself (also fixes bug with SuSE 8.2 kernel)

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1964

coregrind/vg_include.h
coregrind/vg_mylibc.c
coregrind/vg_signals.c
coregrind/vg_syscalls.c
include/vg_kerneliface.h
include/vg_skin.h

index f3cae125d56dbbdb0c0134103bf433b3dcc804d9..e8f53d3811e955004e344fa6cf412050ab24223b 100644 (file)
@@ -1530,6 +1530,7 @@ extern void VG_(init_dataseg_end_for_brk) ( void );
 
 extern Bool VG_(pre_syscall) ( ThreadId tid );
 extern void VG_(post_syscall)( ThreadId tid );
+extern void VG_(restart_syscall) ( ThreadId tid );
 
 extern Bool VG_(is_kerror) ( Int res );
 
index 92addf434c877dc7a7950ac4f53539f0a43d2189..34fe6cc1855903848788d18e80c752405eb710cc 100644 (file)
@@ -1209,7 +1209,7 @@ Int VG_(stat) ( Char* file_name, struct vki_stat* buf )
 {
    Int res;
    res = VG_(do_syscall)(__NR_stat, (UInt)file_name, (UInt)buf);
-   return VG_(is_kerror)(res) ? (-1) : 0;
+   return res;                 /* return -ve error */
 }
 
 Int VG_(fstat) ( Int fd, struct vki_stat* buf )
index bdbd8419d08ca586b547b935e4fb7ca2ab089b21..2a68ef2472836a6f012df23d627bf9b04dafe3f1 100644 (file)
@@ -112,6 +112,12 @@ static const Char *signame(Int sigNo);
    thing with signals and LWPs, so we need to do our own. */
 Bool VG_(do_signal_routing) = False;
 
+/* Set of signal which are pending for the whole process.  This is
+   only used when we're doing signal routing, and this is a place to
+   remember pending signals which we can't keep actually pending for
+   some reason. */
+static vki_ksigset_t proc_pending; /* process-wide pending signals */
+
 /* Since we use a couple of RT signals, we need to handle allocating
    the rest for application use. */
 Int VG_(sig_rtmin) = VKI_SIGRTUSERMIN;
@@ -1419,8 +1425,7 @@ void VG_(deliver_signal) ( ThreadId tid, const vki_ksiginfo_t *info, Bool async
 
       if (tst->m_eax == -VKI_ERESTARTSYS) {
          if (handler->scss_flags & VKI_SA_RESTART) {
-            tst->m_eax = tst->syscallno;
-            tst->m_eip -= 2;           /* sizeof(int $0x80) */
+            VG_(restart_syscall)(tid);
          } else
             tst->m_eax = -VKI_EINTR;
       } else {
@@ -1619,38 +1624,17 @@ void vg_sync_signalhandler ( Int sigNo, vki_ksiginfo_t *info, struct vki_ucontex
    if (info->si_code <= VKI_SI_USER) {
       /* 
         OK, one of sync signals was sent from user-mode, so try to
-        deliver it to someone who cares.  We've currently got the
-        signal blocked because we're in the handler, so some other
-        thread will pick it up if they want it.  If all the other
-        threads have this signal blocked, it will remain pending.
-        wait for .01sec to see if someone picks it up, then eat it if
-        not (otherwise we will just keep spinning, since we *can't*
-        block these signals).
-
-        XXX This is crap.  All the proxy LWPs could easily be
-        blocking this signal transiently (say, waiting for us to
-        respond to a SigACK), but want it eventually.  Maybe we
-        should just bite the bullet and scan the per-thread block
-        sets and decide who to deliver it to.
-       */
-      static const struct vki_timespec ts = { 0, (Int)(.01 * 1000000000) };
-      static const struct vki_timespec zero = { 0, 0 };
-      vki_ksigset_t set;
-      vki_ksiginfo_t si;
-      Bool dropped = False;
-
-      VG_(kkill)(VG_(main_pid), sigNo);
-      VG_(nanosleep)(&ts, NULL);
-      VG_(ksigemptyset)(&set);
-      VG_(ksigaddset)(&set, sigNo);
-      while(VG_(ksigtimedwait)(&set, &si, &zero) == sigNo)
-        dropped = True;
-
-      if (dropped)
-        VG_(message)(Vg_UserMsg,
-                     "Dropped pending signal %d (%s) because all threads were blocking it,"
-                     "but we cannot block it forever.",
-                     sigNo, signame(sigNo));
+        deliver it to someone who cares.  Just add it to the
+        process-wide pending signal set - signal routing will deliver
+        it to someone eventually.
+
+        The only other place which touches proc_pending is
+        VG_(route_signals), and it has signals blocked while doing
+        so, so there's no race.
+      */
+      VG_(message)(Vg_DebugMsg, 
+                  "adding signal %d to pending set", sigNo);
+      VG_(ksigaddset)(&proc_pending, sigNo);
    } else {
       /* 
         A bad signal came from the kernel (indicating an instruction
@@ -1729,7 +1713,6 @@ void VG_(route_signals)(void)
    static const struct vki_timespec zero = { 0, 0 };
    static ThreadId start_tid = 1;      /* tid to start scanning from */
    vki_ksigset_t set;
-   vki_ksigset_t resend;
    vki_ksiginfo_t si;
    Int sigNo;
 
@@ -1739,23 +1722,29 @@ void VG_(route_signals)(void)
    if (!VG_(do_signal_routing))
       return;
 
-   VG_(ksigemptyset)(&resend);
-
    /* get the scheduler LWP's signal mask, and use it as the set of
-      signals we're polling for */
-   VG_(ksigprocmask)(VKI_SIG_SETMASK, NULL, &set);
+      signals we're polling for - also block all signals to prevent
+      races */
+   VG_(block_all_host_signals) ( &set );
 
-   while(VG_(ksigtimedwait)(&set, &si, &zero) > 0) {
+   /* grab any pending signals and add them to the pending signal set */
+   while(VG_(ksigtimedwait)(&set, &si, &zero) > 0)
+      VG_(ksigaddset)(&proc_pending, si.si_signo);
+
+   /* transfer signals from the process pending set to a particular
+      thread which has it unblocked */
+   for(sigNo = 0; sigNo < VKI_KNSIG; sigNo++) {
       ThreadId tid;
       ThreadId end_tid;
       Int target = -1;
       
+      if (!VG_(ksigismember)(&proc_pending, sigNo))
+        continue;
+
       end_tid = start_tid - 1;
       if (end_tid < 0 || end_tid >= VG_N_THREADS)
              end_tid = VG_N_THREADS-1;
 
-      sigNo = si.si_signo;
-
       /* look for a suitable thread to deliver it to */
       for(tid = start_tid;
          tid != end_tid;
@@ -1773,22 +1762,18 @@ void VG_(route_signals)(void)
         }
       }
       
+      /* found one - deliver it and be done */
       if (target != -1) {
         if (VG_(clo_trace_signals))
            VG_(message)(Vg_DebugMsg, "Routing signal %d to tid %d",
                         sigNo, tid);
-        VG_(proxy_sendsig)(tid, sigNo);
-      } else {
-        if (VG_(clo_trace_signals))
-           VG_(message)(Vg_DebugMsg, "Adding signal %d to pending set",
-                        sigNo);
-        VG_(ksigaddset)(&resend, sigNo);
+        VG_(proxy_sendsig)(target, sigNo);
+        VG_(ksigdelset)(&proc_pending, sigNo);
       }
    }
 
-   for(sigNo = 0; sigNo < VKI_KNSIG; sigNo++)
-      if (VG_(ksigismember)(&resend, sigNo))
-        VG_(ktkill)(VG_(main_pid), sigNo);
+   /* restore signal mask */
+   VG_(restore_all_host_signals) (&set);
 }
 
 /* At startup, copy the process' real signal state to the SCSS.
@@ -1808,6 +1793,9 @@ void VG_(sigstartup_actions) ( void )
    */
    VG_(block_all_host_signals)( &saved_procmask );
 
+   /* clear process-wide pending signal set */
+   VG_(ksigemptyset)(&proc_pending);
+
    /* Set the signal mask which the scheduler LWP should maintain from
       now on. */
    set_main_sigmask();
index 43cdbd00dd1516ba9f642dc591bec171809b4c9f..e0cf79121f8e437ad52e18755609de503d50d8c0 100644 (file)
@@ -1223,9 +1223,35 @@ PRE(execve)
       char *const envp[]); */
    MAYBE_PRINTF("execve ( %p(%s), %p, %p ) --- NOT CHECKED\n", 
                arg1, arg1, arg2, arg3);
-   /* Resistance is futile.  Nuke all other threads.  POSIX
-      mandates this. */
-   VG_(nuke_all_threads_except)( tid );
+
+   /* Erk.  If the exec fails, then the following will have made a
+      mess of things which makes it hard for us to continue.  The
+      right thing to do is piece everything together again in
+      POST(execve), but that's hard work.  Instead, we make an effort
+      to check that the execve will work before actually calling
+      exec. */
+   {
+      struct vki_stat st;
+      Int ret = VG_(stat)((Char *)arg1, &st);
+
+      if (ret < 0) {
+        res = ret;
+        return;
+      }
+      /* just look for any X bit set
+        XXX do proper permissions check?
+       */
+      if ((st.st_mode & 0111) == 0) {
+        res = -VKI_EACCES;
+        return;
+      }
+   }
+
+   /* Resistance is futile.  Nuke all other threads.  POSIX mandates
+      this. (Really, nuke them all, since the new process will make
+      its own new thread.) */
+   VG_(nuke_all_threads_except)( VG_INVALID_THREADID );
+
    /* Make any binding for LD_PRELOAD disappear, so that child
       processes don't get traced into. */
    if (!VG_(clo_trace_children)) {
@@ -1242,15 +1268,15 @@ PRE(execve)
       VG_(mash_LD_PRELOAD_and_LD_LIBRARY_PATH)(
         ld_preload_str, ld_library_path_str );
    }
-}
 
-POST(execve)
-{
-   /* Should we still be alive here?  Don't think so. */
-   /* Actually, above comment is wrong.  execve can fail, just
-      like any other syscall -- typically the file to exec does
-      not exist.  Hence: */
-   vg_assert(VG_(is_kerror)(res));
+   res = VG_(do_syscall)(__NR_execve, arg1, arg2, arg3);
+
+   /* If we got here, then the execve failed.  We've already made too much of a mess
+      of ourselves to continue, so we have to abort. */
+   VG_(message)(Vg_UserMsg, "execve(%p \"%s\", %p, %p) failed, errno %d",
+               arg1, arg1, arg2, arg3, -res);
+   VG_(core_panic)("EXEC FAILED: I can't recover from execve() failing, so I'm dying.\n"
+                  "Add more stringent tests in PRE(execve), or work out how to recover.");   
 }
 
 PRE(access)
@@ -4099,6 +4125,8 @@ static const struct sys_info special_sys[] = {
 
    SYSB_(modify_ldt,           False),
 
+   SYSB_(execve,               False),
+
 #if SIGNAL_SIMULATION
    SYSBA(sigaltstack,          False),
    SYSBA(rt_sigaction,         False),
@@ -4184,7 +4212,6 @@ static const struct sys_info sys_info[] = {
    SYSB_(ioperm,               False),
    SYSBA(capget,               False),
    SYSB_(capset,               False),
-   SYSBA(execve,               False),
    SYSB_(access,               False),
    SYSBA(brk,                  False),
    SYSB_(chdir,                        False),
@@ -4467,12 +4494,33 @@ void VG_(post_syscall) ( ThreadId tid )
       VGP_POPCC(VgpSkinSysWrap);
    }
 
+   if (tst->m_eax == -VKI_ERESTARTSYS) {
+      /* Applications never expect to see this, so we should actually
+        restart the syscall (it means the signal happened before the
+        syscall made any progress, so we can safely restart it and
+        pretend the signal happened before the syscall even
+        started)  */
+      VG_(restart_syscall)(tid);
+   }
+
    tst->status = VgTs_Runnable;        /* runnable again */
    tst->syscallno = -1;
 
    VGP_POPCC(VgpCoreSysWrap);
 }
 
+void VG_(restart_syscall)(ThreadId tid)
+{
+   ThreadState* tst;
+   tst = VG_(get_ThreadState)(tid);
+
+   vg_assert(tst != NULL);
+   vg_assert(tst->status == VgTs_WaitSys);
+   vg_assert(tst->syscallno != -1);
+
+   tst->m_eax = tst->syscallno;
+   tst->m_eip -= 2;            /* sizeof(int $0x80) */
+}
 
 /*--------------------------------------------------------------------*/
 /*--- end                                            vg_syscalls.c ---*/
index a12dfee4a9b41c549d8ea464decdf5a77472bb8b..43256ea9d4e437c56b91ef8ef98a797b3372bc6d 100644 (file)
@@ -358,6 +358,7 @@ struct vki_ucontext {
 #define VKI_ENOMEM          12      /* Out of memory */
 #define VKI_EWOULDBLOCK     VKI_EAGAIN  /* Operation would block */
 #define VKI_EAGAIN          11      /* Try again */
+#define        VKI_EACCES          13      /* Permission denied */
 #define        VKI_EFAULT          14      /* Bad address */
 #define VKI_EEXIST         17      /* File exists */
 #define VKI_EINVAL          22      /* Invalid argument */
index 081bd6cc2d3e99541d3731dc57ac330a072b2fca..79ad4aae5a78de850e672024a58fe573698fd14f 100644 (file)
@@ -435,6 +435,7 @@ extern Int  VG_(pipe)   ( Int fd[2] );
 extern Int  VG_(unlink) ( Char* file_name );
 extern Int  VG_(stat)   ( Char* file_name, struct vki_stat* buf );
 extern Int  VG_(fstat)  ( Int   fd,        struct vki_stat* buf );
+extern Int  VG_(dup2)   ( Int oldfd, Int newfd );
 
 extern Char* VG_(getcwd) ( Char* buf, Int size );
 
@@ -514,7 +515,6 @@ extern Int VG_(waitpid)          ( Int pid, Int *status, Int options );
 /* other, randomly useful functions */
 extern UInt VG_(read_millisecond_timer) ( void );
 
-
 /*====================================================================*/
 /*=== UCode definition                                             ===*/
 /*====================================================================*/