Skip to content

Commit e0f76d0

Browse files
committed
patch 7.4.1828
Problem: May try to access buffer that's already freed. Solution: When freeing a buffer remove it from any channel.
1 parent fb6ffc7 commit e0f76d0

4 files changed

Lines changed: 59 additions & 14 deletions

File tree

src/buffer.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,9 @@ free_buffer(buf_T *buf)
676676
#ifdef FEAT_RUBY
677677
ruby_buffer_free(buf);
678678
#endif
679+
#ifdef FEAT_JOB_CHANNEL
680+
channel_buffer_free(buf);
681+
#endif
679682
#ifdef FEAT_AUTOCMD
680683
aubuflocal_remove(buf);
681684
if (autocmd_busy)

src/channel.c

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,7 @@ channel_set_job(channel_T *channel, job_T *job, jobopt_T *options)
10681068

10691069
/*
10701070
* Find a buffer matching "name" or create a new one.
1071+
* Returns NULL if there is something very wrong (error already reported).
10711072
*/
10721073
static buf_T *
10731074
find_buffer(char_u *name, int err)
@@ -1081,6 +1082,8 @@ find_buffer(char_u *name, int err)
10811082
{
10821083
buf = buflist_new(name == NULL || *name == NUL ? NULL : name,
10831084
NULL, (linenr_T)0, BLN_LISTED);
1085+
if (buf == NULL)
1086+
return NULL;
10841087
buf_copy_options(buf, BCO_ENTER);
10851088
curbuf = buf;
10861089
#ifdef FEAT_QUICKFIX
@@ -1187,37 +1190,54 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
11871190

11881191
if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
11891192
{
1193+
buf_T *buf;
1194+
11901195
/* writing output to a buffer. Default mode is NL. */
11911196
if (!(opt->jo_set & JO_OUT_MODE))
11921197
channel->ch_part[PART_OUT].ch_mode = MODE_NL;
11931198
if (opt->jo_set & JO_OUT_BUF)
1194-
channel->ch_part[PART_OUT].ch_buffer =
1195-
buflist_findnr(opt->jo_io_buf[PART_OUT]);
1199+
{
1200+
buf = buflist_findnr(opt->jo_io_buf[PART_OUT]);
1201+
if (buf == NULL)
1202+
EMSGN(_(e_nobufnr), (long)opt->jo_io_buf[PART_OUT]);
1203+
}
11961204
else
1197-
channel->ch_part[PART_OUT].ch_buffer =
1198-
find_buffer(opt->jo_io_name[PART_OUT], FALSE);
1199-
ch_logs(channel, "writing out to buffer '%s'",
1200-
(char *)channel->ch_part[PART_OUT].ch_buffer->b_ffname);
1205+
{
1206+
buf = find_buffer(opt->jo_io_name[PART_OUT], FALSE);
1207+
}
1208+
if (buf != NULL)
1209+
{
1210+
ch_logs(channel, "writing out to buffer '%s'",
1211+
(char *)buf->b_ffname);
1212+
channel->ch_part[PART_OUT].ch_buffer = buf;
1213+
}
12011214
}
12021215

12031216
if ((opt->jo_set & JO_ERR_IO) && (opt->jo_io[PART_ERR] == JIO_BUFFER
12041217
|| (opt->jo_io[PART_ERR] == JIO_OUT && (opt->jo_set & JO_OUT_IO)
12051218
&& opt->jo_io[PART_OUT] == JIO_BUFFER)))
12061219
{
1220+
buf_T *buf;
1221+
12071222
/* writing err to a buffer. Default mode is NL. */
12081223
if (!(opt->jo_set & JO_ERR_MODE))
12091224
channel->ch_part[PART_ERR].ch_mode = MODE_NL;
12101225
if (opt->jo_io[PART_ERR] == JIO_OUT)
1211-
channel->ch_part[PART_ERR].ch_buffer =
1212-
channel->ch_part[PART_OUT].ch_buffer;
1226+
buf = channel->ch_part[PART_OUT].ch_buffer;
12131227
else if (opt->jo_set & JO_ERR_BUF)
1214-
channel->ch_part[PART_ERR].ch_buffer =
1215-
buflist_findnr(opt->jo_io_buf[PART_ERR]);
1228+
{
1229+
buf = buflist_findnr(opt->jo_io_buf[PART_ERR]);
1230+
if (buf == NULL)
1231+
EMSGN(_(e_nobufnr), (long)opt->jo_io_buf[PART_ERR]);
1232+
}
12161233
else
1217-
channel->ch_part[PART_ERR].ch_buffer =
1218-
find_buffer(opt->jo_io_name[PART_ERR], TRUE);
1219-
ch_logs(channel, "writing err to buffer '%s'",
1220-
(char *)channel->ch_part[PART_ERR].ch_buffer->b_ffname);
1234+
buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE);
1235+
if (buf != NULL)
1236+
{
1237+
ch_logs(channel, "writing err to buffer '%s'",
1238+
(char *)buf->b_ffname);
1239+
channel->ch_part[PART_ERR].ch_buffer = buf;
1240+
}
12211241
}
12221242

12231243
channel->ch_part[PART_OUT].ch_io = opt->jo_io[PART_OUT];
@@ -1387,6 +1407,25 @@ channel_write_in(channel_T *channel)
13871407
buf->b_ml.ml_line_count - lnum + 1);
13881408
}
13891409

1410+
/*
1411+
* Handle buffer "buf" beeing freed, remove it from any channels.
1412+
*/
1413+
void
1414+
channel_buffer_free(buf_T *buf)
1415+
{
1416+
channel_T *channel;
1417+
int part;
1418+
1419+
for (channel = first_channel; channel != NULL; channel = channel->ch_next)
1420+
for (part = PART_SOCK; part <= PART_IN; ++part)
1421+
{
1422+
chanpart_T *ch_part = &channel->ch_part[part];
1423+
1424+
if (ch_part->ch_buffer == buf)
1425+
ch_part->ch_buffer = NULL;
1426+
}
1427+
}
1428+
13901429
/*
13911430
* Write any lines waiting to be written to a channel.
13921431
*/

src/proto/channel.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
1414
void channel_set_job(channel_T *channel, job_T *job, jobopt_T *options);
1515
void channel_set_options(channel_T *channel, jobopt_T *opt);
1616
void channel_set_req_callback(channel_T *channel, int part, char_u *callback, partial_T *partial, int id);
17+
void channel_buffer_free(buf_T *buf);
1718
void channel_write_any_lines(void);
1819
void channel_write_new_lines(buf_T *buf);
1920
char_u *channel_get(channel_T *channel, int part);

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,8 @@ static char *(features[]) =
753753

754754
static int included_patches[] =
755755
{ /* Add new patch number below this line */
756+
/**/
757+
1828,
756758
/**/
757759
1827,
758760
/**/

0 commit comments

Comments
 (0)