mirror of
https://github.com/neovim/neovim.git
synced 2025-09-08 20:38:18 +00:00
Merge #5772 from justinmk/fixsegfault
eval.c: set_selfdict(): Fix invalid memory access.
This commit is contained in:
@@ -40,7 +40,7 @@ for details.
|
|||||||
Job control is achieved by calling a combination of the |jobstart()|,
|
Job control is achieved by calling a combination of the |jobstart()|,
|
||||||
|jobsend()| and |jobstop()| functions. Here's an example:
|
|jobsend()| and |jobstop()| functions. Here's an example:
|
||||||
>
|
>
|
||||||
function! s:JobHandler(job_id, data, event)
|
function! s:JobHandler(job_id, data, event) dict
|
||||||
if a:event == 'stdout'
|
if a:event == 'stdout'
|
||||||
let str = self.shell.' stdout: '.join(a:data)
|
let str = self.shell.' stdout: '.join(a:data)
|
||||||
elseif a:event == 'stderr'
|
elseif a:event == 'stderr'
|
||||||
@@ -102,23 +102,23 @@ function. Here's a more object-oriented version of the above:
|
|||||||
>
|
>
|
||||||
let Shell = {}
|
let Shell = {}
|
||||||
|
|
||||||
function Shell.on_stdout(job_id, data)
|
function Shell.on_stdout(job_id, data) dict
|
||||||
call append(line('$'), self.get_name().' stdout: '.join(a:data))
|
call append(line('$'), self.get_name().' stdout: '.join(a:data))
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function Shell.on_stderr(job_id, data)
|
function Shell.on_stderr(job_id, data) dict
|
||||||
call append(line('$'), self.get_name().' stderr: '.join(a:data))
|
call append(line('$'), self.get_name().' stderr: '.join(a:data))
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function Shell.on_exit(job_id, data)
|
function Shell.on_exit(job_id, data) dict
|
||||||
call append(line('$'), self.get_name().' exited')
|
call append(line('$'), self.get_name().' exited')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function Shell.get_name()
|
function Shell.get_name() dict
|
||||||
return 'shell '.self.name
|
return 'shell '.self.name
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function Shell.new(name, ...)
|
function Shell.new(name, ...) dict
|
||||||
let instance = extend(copy(g:Shell), {'name': a:name})
|
let instance = extend(copy(g:Shell), {'name': a:name})
|
||||||
let argv = ['bash']
|
let argv = ['bash']
|
||||||
if a:0 > 0
|
if a:0 > 0
|
||||||
|
@@ -18665,14 +18665,16 @@ handle_subscript (
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_selfdict(typval_T *rettv, dict_T *selfdict) {
|
static void set_selfdict(typval_T *rettv, dict_T *selfdict)
|
||||||
|
{
|
||||||
// Don't do this when "dict.Func" is already a partial that was bound
|
// Don't do this when "dict.Func" is already a partial that was bound
|
||||||
// explicitly (pt_auto is false).
|
// explicitly (pt_auto is false).
|
||||||
if (rettv->v_type == VAR_PARTIAL && !rettv->vval.v_partial->pt_auto
|
if (rettv->v_type == VAR_PARTIAL && !rettv->vval.v_partial->pt_auto
|
||||||
&& rettv->vval.v_partial->pt_dict != NULL) {
|
&& rettv->vval.v_partial->pt_dict != NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char_u *fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
|
char_u *fname = rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING
|
||||||
|
? rettv->vval.v_string
|
||||||
: rettv->vval.v_partial->pt_name;
|
: rettv->vval.v_partial->pt_name;
|
||||||
char_u *tofree = NULL;
|
char_u *tofree = NULL;
|
||||||
ufunc_T *fp;
|
ufunc_T *fp;
|
||||||
@@ -18694,7 +18696,7 @@ static void set_selfdict(typval_T *rettv, dict_T *selfdict) {
|
|||||||
pt->pt_dict = selfdict;
|
pt->pt_dict = selfdict;
|
||||||
(selfdict->dv_refcount)++;
|
(selfdict->dv_refcount)++;
|
||||||
pt->pt_auto = true;
|
pt->pt_auto = true;
|
||||||
if (rettv->v_type == VAR_FUNC) {
|
if (rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING) {
|
||||||
// Just a function: Take over the function name and use selfdict.
|
// Just a function: Take over the function name and use selfdict.
|
||||||
pt->pt_name = rettv->vval.v_string;
|
pt->pt_name = rettv->vval.v_string;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -303,6 +303,26 @@ describe('jobs', function()
|
|||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('requires funcrefs for script-local (s:) functions', function()
|
||||||
|
-- Pass job callback names _without_ `function(...)`.
|
||||||
|
source([[
|
||||||
|
function! s:OnEvent(id, data, event) dict
|
||||||
|
let g:job_result = get(self, 'user')
|
||||||
|
endfunction
|
||||||
|
let s:job = jobstart(['echo'], {
|
||||||
|
\ 'on_stdout': 's:OnEvent',
|
||||||
|
\ 'on_stderr': 's:OnEvent',
|
||||||
|
\ 'on_exit': 's:OnEvent',
|
||||||
|
\ 'user': 2349
|
||||||
|
\ })
|
||||||
|
]])
|
||||||
|
|
||||||
|
-- The behavior is asynchronous, retry until a time limit.
|
||||||
|
helpers.retry(nil, 10000, function()
|
||||||
|
eq("E120:", string.match(eval("v:errmsg"), "E%d*:"))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
describe('jobwait', function()
|
describe('jobwait', function()
|
||||||
it('returns a list of status codes', function()
|
it('returns a list of status codes', function()
|
||||||
source([[
|
source([[
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
require('coxpcall')
|
require('coxpcall')
|
||||||
|
local luv = require('luv')
|
||||||
local lfs = require('lfs')
|
local lfs = require('lfs')
|
||||||
local global_helpers = require('test.helpers')
|
local global_helpers = require('test.helpers')
|
||||||
|
|
||||||
@@ -243,17 +244,24 @@ local function connect(file_or_address)
|
|||||||
return Session.new(stream)
|
return Session.new(stream)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Calls fn() until it returns without error, up to `max` times.
|
-- Calls fn() until it succeeds, up to `max` times or until `max_ms`
|
||||||
local function retry(fn, max)
|
-- milliseconds have passed.
|
||||||
local retries = max and (max - 1) or 2
|
local function retry(max, max_ms, fn)
|
||||||
for _ = 1, retries do
|
local tries = 1
|
||||||
local success = pcall(fn)
|
local timeout = (max_ms and max_ms > 0) and max_ms or 10000
|
||||||
if success then
|
local start_time = luv.now()
|
||||||
return
|
while true do
|
||||||
|
local status, result = pcall(fn)
|
||||||
|
if status then
|
||||||
|
return result
|
||||||
end
|
end
|
||||||
|
if (max and tries >= max) or (luv.now() - start_time > timeout) then
|
||||||
|
break
|
||||||
end
|
end
|
||||||
-- pcall() is not used for the final attempt so failure can bubble up.
|
tries = tries + 1
|
||||||
fn()
|
end
|
||||||
|
-- Do not use pcall() for the final attempt, let the failure bubble up.
|
||||||
|
return fn()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function clear(...)
|
local function clear(...)
|
||||||
|
@@ -98,7 +98,7 @@ describe('undo tree:', function()
|
|||||||
expect_line('123456abc')
|
expect_line('123456abc')
|
||||||
end
|
end
|
||||||
|
|
||||||
helpers.retry(test_earlier_later)
|
helpers.retry(2, nil, test_earlier_later)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('file-write specifications', function()
|
it('file-write specifications', function()
|
||||||
|
Reference in New Issue
Block a user