eval.c: set_selfdict(): Fix invalid memory access.

This commit is contained in:
Justin M. Keyes
2016-12-14 16:56:00 +01:00
parent 8c9cccbcb6
commit 43ba7f4d98
4 changed files with 44 additions and 14 deletions

View File

@@ -18665,15 +18665,17 @@ 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_partial->pt_name; ? rettv->vval.v_string
: rettv->vval.v_partial->pt_name;
char_u *tofree = NULL; char_u *tofree = NULL;
ufunc_T *fp; ufunc_T *fp;
char_u fname_buf[FLEN_FIXED + 1]; char_u fname_buf[FLEN_FIXED + 1];
@@ -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 {

View File

@@ -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([[

View File

@@ -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
tries = tries + 1
end end
-- pcall() is not used for the final attempt so failure can bubble up. -- Do not use pcall() for the final attempt, let the failure bubble up.
fn() return fn()
end end
local function clear(...) local function clear(...)

View File

@@ -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()