mirror of
https://github.com/neovim/neovim.git
synced 2026-01-06 19:39:53 +10:00
Merge pull request #21089 from zeertzjq/vim-8.2.2586
vim-patch:8.2.{2586,2587,2589}: process id may be invalid
This commit is contained in:
@@ -72,7 +72,7 @@
|
||||
#include "nvim/memory.h"
|
||||
#include "nvim/message.h"
|
||||
#include "nvim/option.h"
|
||||
#include "nvim/os/fs_defs.h"
|
||||
#include "nvim/os/fs.h"
|
||||
#include "nvim/os/input.h"
|
||||
#include "nvim/os/os.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.
|
||||
///
|
||||
/// @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_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
|
||||
// want to kill it.
|
||||
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) {
|
||||
msg_puts(_("\n process ID: "));
|
||||
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)"));
|
||||
process_still_running = true;
|
||||
}
|
||||
@@ -1555,8 +1572,7 @@ static bool swapfile_unchanged(char *fname)
|
||||
}
|
||||
|
||||
// process must be known and not running.
|
||||
long pid = char_to_long(b0.b0_pid);
|
||||
if (pid == 0L || os_proc_running((int)pid)) {
|
||||
if (char_to_long(b0.b0_pid) == 0L || swapfile_process_running(&b0, fname)) {
|
||||
ret = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,14 @@ func CheckUnix()
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" Command to check for running on Linux
|
||||
command CheckLinux call CheckLinux()
|
||||
func CheckLinux()
|
||||
if !has('linux')
|
||||
throw 'Skipped: only works on Linux'
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" Command to check that making screendumps is supported.
|
||||
" Caller must source screendump.vim
|
||||
command CheckScreendump call CheckScreendump()
|
||||
|
||||
@@ -174,7 +174,12 @@ func RunTheTest(test)
|
||||
if a:test =~ 'Test_nocatch_'
|
||||
" Function handles errors itself. This avoids skipping commands after the
|
||||
" error.
|
||||
let g:skipped_reason = ''
|
||||
exe 'call ' . a:test
|
||||
if g:skipped_reason != ''
|
||||
call add(s:messages, ' Skipped')
|
||||
call add(s:skipped, 'SKIPPED ' . a:test . ': ' . g:skipped_reason)
|
||||
endif
|
||||
else
|
||||
try
|
||||
let s:test = a:test
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
" Test :recover
|
||||
|
||||
source check.vim
|
||||
|
||||
func Test_recover_root_dir()
|
||||
" This used to access invalid memory.
|
||||
split Xtest
|
||||
@@ -23,6 +25,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.
|
||||
"
|
||||
@@ -40,15 +57,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
|
||||
@@ -69,3 +80,62 @@ func Test_swap_file()
|
||||
set undolevels&
|
||||
enew! | only
|
||||
endfunc
|
||||
|
||||
func Test_nocatch_process_still_running()
|
||||
let g:skipped_reason = 'test_override() is N/A'
|
||||
return
|
||||
" sysinfo.uptime probably only works on Linux
|
||||
if !has('linux')
|
||||
let g:skipped_reason = 'only works on Linux'
|
||||
return
|
||||
endif
|
||||
" the GUI dialog can't be handled
|
||||
if has('gui_running')
|
||||
let g:skipped_reason = 'only works in the terminal'
|
||||
return
|
||||
endif
|
||||
|
||||
" 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
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local lfs = require('lfs')
|
||||
local luv = require('luv')
|
||||
local eq, eval, expect, exec =
|
||||
helpers.eq, helpers.eval, helpers.expect, helpers.exec
|
||||
local assert_alive = helpers.assert_alive
|
||||
local clear = helpers.clear
|
||||
local command = helpers.command
|
||||
local feed = helpers.feed
|
||||
local funcs = helpers.funcs
|
||||
local nvim_prog = helpers.nvim_prog
|
||||
local ok = helpers.ok
|
||||
local rmdir = helpers.rmdir
|
||||
@@ -100,7 +102,7 @@ describe('swapfile detection', function()
|
||||
-- attempt to create a swapfile in different directory.
|
||||
local init = [[
|
||||
set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[//
|
||||
set swapfile fileformat=unix undolevels=-1 hidden
|
||||
set swapfile fileformat=unix nomodified undolevels=-1 nohidden
|
||||
]]
|
||||
before_each(function()
|
||||
nvim0 = spawn(new_argv())
|
||||
@@ -263,4 +265,79 @@ describe('swapfile detection', function()
|
||||
]])
|
||||
nvim2:close()
|
||||
end)
|
||||
|
||||
-- oldtest: Test_nocatch_process_still_running()
|
||||
it('allows deleting swapfile created before boot vim-patch:8.2.2586', function()
|
||||
local screen = Screen.new(75, 30)
|
||||
screen:set_default_attr_ids({
|
||||
[0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
|
||||
[1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
|
||||
[2] = {background = Screen.colors.Red, foreground = Screen.colors.White}, -- ErrorMsg
|
||||
})
|
||||
screen:attach()
|
||||
|
||||
exec(init)
|
||||
command('set nohidden')
|
||||
|
||||
exec([=[
|
||||
" 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 ' . fnameescape(swname)
|
||||
w! Xswap
|
||||
set nobinary
|
||||
return swname
|
||||
endfunc
|
||||
]=])
|
||||
|
||||
-- Edit a file and grab its swapfile.
|
||||
exec([[
|
||||
edit Xswaptest
|
||||
call setline(1, ['a', 'b', 'c'])
|
||||
]])
|
||||
local swname = funcs.CopySwapfile()
|
||||
|
||||
-- Forget we edited this file
|
||||
exec([[
|
||||
new
|
||||
only!
|
||||
bwipe! Xswaptest
|
||||
]])
|
||||
|
||||
os.rename('Xswap', swname)
|
||||
|
||||
feed(':edit Xswaptest<CR>')
|
||||
screen:expect({any = table.concat({
|
||||
pesc('{2:E325: ATTENTION}'),
|
||||
'file name: .*Xswaptest',
|
||||
'process ID: %d* %(STILL RUNNING%)',
|
||||
pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: }^'),
|
||||
}, '.*')})
|
||||
|
||||
feed('e')
|
||||
|
||||
-- Forget we edited this file
|
||||
exec([[
|
||||
new
|
||||
only!
|
||||
bwipe! Xswaptest
|
||||
]])
|
||||
|
||||
-- pretend that the swapfile was created before boot
|
||||
lfs.touch(swname, os.time() - luv.uptime() - 10)
|
||||
|
||||
feed(':edit Xswaptest<CR>')
|
||||
screen:expect({any = table.concat({
|
||||
pesc('{2:E325: ATTENTION}'),
|
||||
pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort: }^'),
|
||||
}, '.*')})
|
||||
|
||||
feed('e')
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user