summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-03-10 21:26:37 +0100
committerBram Moolenaar <Bram@vim.org>2021-03-10 21:26:37 +0100
commitf52f0606ed9ea19bcfc3a8343af9958f2d99eaf7 (patch)
tree1fd2ccebf68aca966d10acdacf36a99badea66c5
parentc23555de346c53f8f6c478635c2d9e5f2992dd7f (diff)
patch 8.2.2586: process id may be invalidv8.2.2586
Problem: Process id may be invalid. Solution: Use sysinfo.uptime to check for recent reboot. (suggested by Hugo van der Sanden, closes #7947)
-rwxr-xr-xsrc/auto/configure29
-rw-r--r--src/config.h.in1
-rw-r--r--src/configure.ac14
-rw-r--r--src/globals.h1
-rw-r--r--src/memline.c36
-rw-r--r--src/testdir/test_recover.vim77
-rw-r--r--src/testing.c3
-rw-r--r--src/version.c2
8 files changed, 147 insertions, 16 deletions
diff --git a/src/auto/configure b/src/auto/configure
index 818349991d..a9e2145d8b 100755
--- a/src/auto/configure
+++ b/src/auto/configure
@@ -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
diff --git a/src/config.h.in b/src/config.h.in
index 5d01e2c4f7..fbf4b2449c 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -213,6 +213,7 @@
#undef HAVE_SYSCTL
#undef HAVE_SYSINFO
#undef HAVE_SYSINFO_MEM_UNIT
+#undef HAVE_SYSINFO_UPTIME
#undef HAVE_TGETENT
#undef HAVE_TOWLOWER
#undef HAVE_TOWUPPER
diff --git a/src/configure.ac b/src/configure.ac
index 798e9b8942..0bb5cc557c 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -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(
diff --git a/src/globals.h b/src/globals.h
index 0fd08b6317..cb3b4f4b76 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -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
diff --git a/src/memline.c b/src/memline.c
index c5303bb837..4da7b431fc 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -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
diff --git a/src/testdir/test_recover.vim b/src/testdir/test_recover.vim
index 8408ff3693..621e3152c7 100644
--- a/src/testdir/test_recover.vim
+++ b/src/testdir/test_recover.vim
@@ -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
diff --git a/src/testing.c b/src/testing.c
index 6d4f588f8d..df19b9eb49 100644
--- a/src/testing.c
+++ b/src/testing.c
@@ -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;
diff --git a/src/version.c b/src/version.c
index b8ce28af88..b624a71e13 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2586,
+/**/
2585,
/**/
2584,