]> granicus.if.org Git - vim/commitdiff
patch 8.2.2586: process id may be invalid v8.2.2586
authorBram Moolenaar <Bram@vim.org>
Wed, 10 Mar 2021 20:26:37 +0000 (21:26 +0100)
committerBram Moolenaar <Bram@vim.org>
Wed, 10 Mar 2021 20:26:37 +0000 (21:26 +0100)
Problem:    Process id may be invalid.
Solution:   Use sysinfo.uptime to check for recent reboot. (suggested by Hugo
            van der Sanden, closes #7947)

src/auto/configure
src/config.h.in
src/configure.ac
src/globals.h
src/memline.c
src/testdir/test_recover.vim
src/testing.c
src/version.c

index 818349991d00ff188eb318dee6d53867f251f79e..a9e2145d8b5442eed12a083e648cc12e9102dbac 100755 (executable)
@@ -13918,6 +13918,35 @@ $as_echo "no" >&6; }
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysinfo.uptime" >&5
+$as_echo_n "checking for sysinfo.uptime... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/sysinfo.h>
+int
+main ()
+{
+       struct sysinfo sinfo;
+        long ut;
+
+       (void)sysinfo(&sinfo);
+       ut = sinfo.uptime;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_SYSINFO_UPTIME 1" >>confdefs.h
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysconf" >&5
 $as_echo_n "checking for sysconf... " >&6; }
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
index 5d01e2c4f70edef86515733252399e946dedfb93..fbf4b2449c3a056a64ba45fb6b1b8ccd67ef55a2 100644 (file)
 #undef HAVE_SYSCTL
 #undef HAVE_SYSINFO
 #undef HAVE_SYSINFO_MEM_UNIT
+#undef HAVE_SYSINFO_UPTIME
 #undef HAVE_TGETENT
 #undef HAVE_TOWLOWER
 #undef HAVE_TOWUPPER
index 798e9b8942ae19bf5533a23baede59c0dda18f67..0bb5cc557ce615f421511c0fd1b365ac252146c5 100644 (file)
@@ -4095,6 +4095,20 @@ AC_TRY_COMPILE(
        AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSINFO_MEM_UNIT),
        AC_MSG_RESULT(no))
 
+dnl struct sysinfo may have the uptime field or not
+AC_MSG_CHECKING(for sysinfo.uptime)
+AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <sys/sysinfo.h>],
+[      struct sysinfo sinfo;
+        long ut;
+
+       (void)sysinfo(&sinfo);
+       ut = sinfo.uptime;
+       ],
+       AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSINFO_UPTIME),
+       AC_MSG_RESULT(no))
+
 dnl sysconf() may exist but not support what we want to use
 AC_MSG_CHECKING(for sysconf)
 AC_TRY_COMPILE(
index 0fd08b63173af868b857eb885f2c8067fb715b6b..cb3b4f4b76288e65754dea9f7a617c486eca6401 100644 (file)
@@ -1860,6 +1860,7 @@ EXTERN int  nfa_fail_for_testing INIT(= FALSE);
 EXTERN int  no_query_mouse_for_testing INIT(= FALSE);
 EXTERN int  ui_delay_for_testing INIT(= 0);
 EXTERN int  reset_term_props_on_termresponse INIT(= FALSE);
+EXTERN long override_sysinfo_uptime INIT(= -1);
 
 EXTERN int  in_free_unref_items INIT(= FALSE);
 #endif
index c5303bb837a0310983b802ba445ce484309d2a03..4da7b431fc6cf0276b5ffe2a753db0c186bbc9ab 100644 (file)
@@ -1080,6 +1080,32 @@ add_b0_fenc(
     }
 }
 
+#if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO_UPTIME)
+# include <sys/sysinfo.h>
+#endif
+
+/*
+ * Return TRUE if the process with number "b0p->b0_pid" is still running.
+ * "swap_fname" is the name of the swap file, if it's from before a reboot then
+ * the result is FALSE;
+ */
+    static int
+swapfile_process_running(ZERO_BL *b0p, char_u *swap_fname UNUSED)
+{
+#ifdef HAVE_SYSINFO_UPTIME
+    stat_T         st;
+    struct sysinfo  sinfo;
+
+    // If the system rebooted after when the swap file was written then the
+    // process can't be running now.
+    if (mch_stat((char *)swap_fname, &st) != -1
+           && sysinfo(&sinfo) == 0
+           && st.st_mtime < time(NULL) - (override_sysinfo_uptime >= 0
+                                    ? override_sysinfo_uptime : sinfo.uptime))
+       return FALSE;
+#endif
+    return mch_process_running(char_to_long(b0p->b0_pid));
+}
 
 /*
  * Try to recover curbuf from the .swp file.
@@ -1692,7 +1718,7 @@ ml_recover(int checkext)
            msg(_("Recovery completed. Buffer contents equals file contents."));
        msg_puts(_("\nYou may want to delete the .swp file now."));
 #if defined(UNIX) || defined(MSWIN)
-       if (mch_process_running(char_to_long(b0p->b0_pid)))
+       if (swapfile_process_running(b0p, fname_used))
        {
            // Warn there could be an active Vim on the same file, the user may
            // want to kill it.
@@ -2170,7 +2196,7 @@ swapfile_info(char_u *fname)
                    msg_puts(_("\n        process ID: "));
                    msg_outnum(char_to_long(b0.b0_pid));
 #if defined(UNIX) || defined(MSWIN)
-                   if (mch_process_running(char_to_long(b0.b0_pid)))
+                   if (swapfile_process_running(&b0, fname))
                    {
                        msg_puts(_(" (STILL RUNNING)"));
 # ifdef HAVE_PROCESS_STILL_RUNNING
@@ -2213,9 +2239,6 @@ swapfile_unchanged(char_u *fname)
     int                    fd;
     struct block0   b0;
     int                    ret = TRUE;
-#if defined(UNIX) || defined(MSWIN)
-    long           pid;
-#endif
 
     // must be able to stat the swap file
     if (mch_stat((char *)fname, &st) == -1)
@@ -2258,8 +2281,7 @@ swapfile_unchanged(char_u *fname)
     }
 
     // process must be known and not be running
-    pid = char_to_long(b0.b0_pid);
-    if (pid == 0L || mch_process_running(pid))
+    if (char_to_long(b0.b0_pid) == 0L || swapfile_process_running(&b0, fname))
        ret = FALSE;
 #endif
 
index 8408ff369386c232241c9123377436f750c65cd9..621e3152c7a4d9842d316a8ebcad4468a55b6c58 100644 (file)
@@ -1,5 +1,7 @@
 " Test :recover
 
+source check.vim
+
 func Test_recover_root_dir()
   " This used to access invalid memory.
   split Xtest
@@ -21,6 +23,21 @@ func Test_recover_root_dir()
   set dir&
 endfunc
 
+" Make a copy of the current swap file to "Xswap".
+" Return the name of the swap file.
+func CopySwapfile()
+  preserve
+  " get the name of the swap file
+  let swname = split(execute("swapname"))[0]
+  let swname = substitute(swname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', '')
+  " make a copy of the swap file in Xswap
+  set binary
+  exe 'sp ' . swname
+  w! Xswap
+  set nobinary
+  return swname
+endfunc
+
 " Inserts 10000 lines with text to fill the swap file with two levels of pointer
 " blocks.  Then recovers from the swap file and checks all text is restored.
 "
@@ -37,15 +54,9 @@ func Test_swap_file()
     let i += 1
   endwhile
   $delete
-  preserve
-  " get the name of the swap file
-  let swname = split(execute("swapname"))[0]
-  let swname = substitute(swname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', '')
-  " make a copy of the swap file in Xswap
-  set binary
-  exe 'sp ' . swname
-  w! Xswap
-  set nobinary
+
+  let swname = CopySwapfile()
+
   new
   only!
   bwipe! Xtest
@@ -67,4 +78,52 @@ func Test_swap_file()
   enew! | only
 endfunc
 
+func Test_nocatch_process_still_running()
+  " assume Unix means sysinfo.uptime can be used
+  CheckUnix
+  CheckNotGui
+
+  " don't intercept existing swap file here
+  au! SwapExists
+
+  " Edit a file and grab its swapfile.
+  edit Xswaptest
+  call setline(1, ['a', 'b', 'c'])
+  let swname = CopySwapfile()
+
+  " Forget we edited this file
+  new
+  only!
+  bwipe! Xswaptest
+
+  call rename('Xswap', swname)
+  call feedkeys('e', 'tL')
+  redir => editOutput
+  edit Xswaptest
+  redir END
+  call assert_match('E325: ATTENTION', editOutput)
+  call assert_match('file name: .*Xswaptest', editOutput)
+  call assert_match('process ID: \d* (STILL RUNNING)', editOutput)
+
+  " Forget we edited this file
+  new
+  only!
+  bwipe! Xswaptest
+
+  " pretend we rebooted
+  call test_override("uptime", 0)
+  sleep 1
+
+  call rename('Xswap', swname)
+  call feedkeys('e', 'tL')
+  redir => editOutput
+  edit Xswaptest
+  redir END
+  call assert_match('E325: ATTENTION', editOutput)
+  call assert_notmatch('(STILL RUNNING)', editOutput)
+
+  call test_override("ALL", 0)
+  call delete(swname)
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index 6d4f588f8d6e8796b0c5b58a71e6bed960a07329..df19b9eb491a45c962d1bd61474f8244510fdea3 100644 (file)
@@ -970,6 +970,8 @@ f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
            ui_delay_for_testing = val;
        else if (STRCMP(name, (char_u *)"term_props") == 0)
            reset_term_props_on_termresponse = val;
+       else if (STRCMP(name, (char_u *)"uptime") == 0)
+           override_sysinfo_uptime = val;
        else if (STRCMP(name, (char_u *)"ALL") == 0)
        {
            disable_char_avail_for_testing = FALSE;
@@ -979,6 +981,7 @@ f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
            no_query_mouse_for_testing = FALSE;
            ui_delay_for_testing = 0;
            reset_term_props_on_termresponse = FALSE;
+           override_sysinfo_uptime = -1;
            if (save_starting >= 0)
            {
                starting = save_starting;
index b8ce28af882eeb7033e60ad39a1ad8c297762aed..b624a71e13c1cd93341c63ff8aad29a703308863 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2586,
 /**/
     2585,
 /**/