mirror of
https://github.com/neovim/neovim.git
synced 2025-09-25 04:28:33 +00:00
api: fix use-after-free in nvim_chan_send
This commit is contained in:
@@ -1333,7 +1333,8 @@ void nvim_chan_send(Integer chan, String data, Error *err)
|
||||
return;
|
||||
}
|
||||
|
||||
channel_send((uint64_t)chan, data.data, data.size, &error);
|
||||
channel_send((uint64_t)chan, data.data, data.size,
|
||||
false, &error);
|
||||
if (error) {
|
||||
api_set_error(err, kErrorTypeValidation, "%s", error);
|
||||
}
|
||||
|
@@ -499,48 +499,54 @@ uint64_t channel_from_stdio(bool rpc, CallbackReader on_output,
|
||||
}
|
||||
|
||||
/// @param data will be consumed
|
||||
size_t channel_send(uint64_t id, char *data, size_t len, const char **error)
|
||||
size_t channel_send(uint64_t id, char *data, size_t len,
|
||||
bool data_owned, const char **error)
|
||||
{
|
||||
Channel *chan = find_channel(id);
|
||||
size_t written = 0;
|
||||
if (!chan) {
|
||||
*error = _(e_invchan);
|
||||
goto err;
|
||||
goto retfree;
|
||||
}
|
||||
|
||||
if (chan->streamtype == kChannelStreamStderr) {
|
||||
if (chan->stream.err.closed) {
|
||||
*error = _("Can't send data to closed stream");
|
||||
goto err;
|
||||
goto retfree;
|
||||
}
|
||||
// unbuffered write
|
||||
size_t written = fwrite(data, len, 1, stderr);
|
||||
xfree(data);
|
||||
return len * written;
|
||||
written = len * fwrite(data, len, 1, stderr);
|
||||
goto retfree;
|
||||
}
|
||||
|
||||
if (chan->streamtype == kChannelStreamInternal && chan->term) {
|
||||
terminal_receive(chan->term, data, len);
|
||||
return len;
|
||||
written = len;
|
||||
goto retfree;
|
||||
}
|
||||
|
||||
|
||||
Stream *in = channel_instream(chan);
|
||||
if (in->closed) {
|
||||
*error = _("Can't send data to closed stream");
|
||||
goto err;
|
||||
goto retfree;
|
||||
}
|
||||
|
||||
if (chan->is_rpc) {
|
||||
*error = _("Can't send raw data to rpc channel");
|
||||
goto err;
|
||||
goto retfree;
|
||||
}
|
||||
|
||||
WBuffer *buf = wstream_new_buffer(data, len, 1, xfree);
|
||||
// write can be delayed indefinitely, so always use an allocated buffer
|
||||
WBuffer *buf = wstream_new_buffer(data_owned ? data : xmemdup(data, len),
|
||||
len, 1, xfree);
|
||||
return wstream_write(in, buf) ? len : 0;
|
||||
|
||||
err:
|
||||
retfree:
|
||||
if (data_owned) {
|
||||
xfree(data);
|
||||
return 0;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
/// Convert binary byte array to a readfile()-style list
|
||||
|
@@ -916,7 +916,7 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
}
|
||||
uint64_t id = argvars[0].vval.v_number;
|
||||
const char *error = NULL;
|
||||
rettv->vval.v_number = channel_send(id, input, input_len, &error);
|
||||
rettv->vval.v_number = channel_send(id, input, input_len, true, &error);
|
||||
if (error) {
|
||||
EMSG(error);
|
||||
}
|
||||
|
@@ -963,8 +963,10 @@ describe('jobs', function()
|
||||
return rv
|
||||
end
|
||||
|
||||
local j
|
||||
local function send(str)
|
||||
nvim('command', 'call jobsend(j, "'..str..'")')
|
||||
-- check no nvim_chan_free double free with pty job (#14198)
|
||||
meths.chan_send(j, str)
|
||||
end
|
||||
|
||||
before_each(function()
|
||||
@@ -979,6 +981,7 @@ describe('jobs', function()
|
||||
nvim('command', 'let g:job_opts.pty = 1')
|
||||
nvim('command', 'let exec = [expand("<cfile>:p")]')
|
||||
nvim('command', "let j = jobstart(exec, g:job_opts)")
|
||||
j = eval'j'
|
||||
eq('tty ready', next_chunk())
|
||||
end)
|
||||
|
||||
|
Reference in New Issue
Block a user