vim-patch:8.2.2586: process id may be invalid

Problem:    Process id may be invalid.
Solution:   Use sysinfo.uptime to check for recent reboot. (suggested by Hugo
            van der Sanden, closes vim/vim#7947)

f52f0606ed

test_override() is N/A.

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq
2022-11-17 19:57:16 +08:00
parent 0a4c5cd2b2
commit ec5c1c35c2
2 changed files with 91 additions and 14 deletions

View File

@@ -72,7 +72,7 @@
#include "nvim/memory.h" #include "nvim/memory.h"
#include "nvim/message.h" #include "nvim/message.h"
#include "nvim/option.h" #include "nvim/option.h"
#include "nvim/os/fs_defs.h" #include "nvim/os/fs.h"
#include "nvim/os/input.h" #include "nvim/os/input.h"
#include "nvim/os/os.h" #include "nvim/os/os.h"
#include "nvim/os/process.h" #include "nvim/os/process.h"
@@ -698,6 +698,23 @@ static void add_b0_fenc(ZERO_BL *b0p, buf_T *buf)
} }
} }
/// 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 bool swapfile_process_running(const ZERO_BL *b0p, const char *swap_fname)
{
FileInfo st;
double uptime;
// If the system rebooted after when the swap file was written then the
// process can't be running now.
if (os_fileinfo(swap_fname, &st)
&& uv_uptime(&uptime) == 0
&& (Timestamp)st.stat.st_mtim.tv_sec < os_time() - (Timestamp)uptime) {
return false;
}
return os_proc_running((int)char_to_long(b0p->b0_pid));
}
/// Try to recover curbuf from the .swp file. /// Try to recover curbuf from the .swp file.
/// ///
/// @param checkext if true, check the extension and detect whether it is a /// @param checkext if true, check the extension and detect whether it is a
@@ -1139,7 +1156,7 @@ void ml_recover(bool checkext)
msg(_("Recovery completed. Buffer contents equals file contents.")); msg(_("Recovery completed. Buffer contents equals file contents."));
} }
msg_puts(_("\nYou may want to delete the .swp file now.")); msg_puts(_("\nYou may want to delete the .swp file now."));
if (os_proc_running((int)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 // Warn there could be an active Vim on the same file, the user may
// want to kill it. // want to kill it.
msg_puts(_("\nNote: process STILL RUNNING: ")); msg_puts(_("\nNote: process STILL RUNNING: "));
@@ -1485,7 +1502,7 @@ static time_t swapfile_info(char_u *fname)
if (char_to_long(b0.b0_pid) != 0L) { if (char_to_long(b0.b0_pid) != 0L) {
msg_puts(_("\n process ID: ")); msg_puts(_("\n process ID: "));
msg_outnum(char_to_long(b0.b0_pid)); msg_outnum(char_to_long(b0.b0_pid));
if (os_proc_running((int)char_to_long(b0.b0_pid))) { if (swapfile_process_running(&b0, (const char *)fname)) {
msg_puts(_(" (STILL RUNNING)")); msg_puts(_(" (STILL RUNNING)"));
process_still_running = true; process_still_running = true;
} }
@@ -1555,8 +1572,7 @@ static bool swapfile_unchanged(char *fname)
} }
// process must be known and not running. // process must be known and not running.
long pid = char_to_long(b0.b0_pid); if (char_to_long(b0.b0_pid) == 0L || swapfile_process_running(&b0, fname)) {
if (pid == 0L || os_proc_running((int)pid)) {
ret = false; ret = false;
} }

View File

@@ -1,5 +1,7 @@
" Test :recover " Test :recover
source check.vim
func Test_recover_root_dir() func Test_recover_root_dir()
" This used to access invalid memory. " This used to access invalid memory.
split Xtest split Xtest
@@ -23,6 +25,21 @@ func Test_recover_root_dir()
set dir& set dir&
endfunc 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 " 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. " blocks. Then recovers from the swap file and checks all text is restored.
" "
@@ -40,15 +57,9 @@ func Test_swap_file()
let i += 1 let i += 1
endwhile endwhile
$delete $delete
preserve
" get the name of the swap file let swname = CopySwapfile()
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
new new
only! only!
bwipe! Xtest bwipe! Xtest
@@ -69,3 +80,53 @@ func Test_swap_file()
set undolevels& set undolevels&
enew! | only enew! | only
endfunc 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