Skip to content

Commit fb6ffc7

Browse files
committed
patch 7.4.1827
Problem: No error when invoking a callback when it's not safe. Solution: Add an error message. Avoid the error when freeing a channel.
1 parent cf7ff70 commit fb6ffc7

3 files changed

Lines changed: 36 additions & 2 deletions

File tree

src/channel.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ static void channel_read(channel_T *channel, int part, char *func);
5959
/* Whether a redraw is needed for appending a line to a buffer. */
6060
static int channel_need_redraw = FALSE;
6161

62+
/* Whether we are inside channel_parse_messages() or another situation where it
63+
* is safe to invoke callbacks. */
64+
static int safe_to_invoke_callback = 0;
6265

6366
#ifdef WIN32
6467
static int
@@ -403,8 +406,15 @@ channel_free(channel_T *channel)
403406
{
404407
if (!in_free_unref_items)
405408
{
406-
channel_free_contents(channel);
407-
channel_free_channel(channel);
409+
if (safe_to_invoke_callback == 0)
410+
{
411+
channel->ch_to_be_freed = TRUE;
412+
}
413+
else
414+
{
415+
channel_free_contents(channel);
416+
channel_free_channel(channel);
417+
}
408418
}
409419
}
410420

@@ -444,6 +454,10 @@ free_unused_channels_contents(int copyID, int mask)
444454
int did_free = FALSE;
445455
channel_T *ch;
446456

457+
/* This is invoked from the garbage collector, which only runs at a safe
458+
* point. */
459+
++safe_to_invoke_callback;
460+
447461
for (ch = first_channel; ch != NULL; ch = ch->ch_next)
448462
if (!channel_still_useful(ch)
449463
&& (ch->ch_copyID & mask) != (copyID & mask))
@@ -453,6 +467,8 @@ free_unused_channels_contents(int copyID, int mask)
453467
channel_free_contents(ch);
454468
did_free = TRUE;
455469
}
470+
471+
--safe_to_invoke_callback;
456472
return did_free;
457473
}
458474

@@ -1450,6 +1466,9 @@ invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
14501466
typval_T rettv;
14511467
int dummy;
14521468

1469+
if (safe_to_invoke_callback == 0)
1470+
EMSG("INTERNAL: Invoking callback when it is not safe");
1471+
14531472
argv[0].v_type = VAR_CHANNEL;
14541473
argv[0].vval.v_channel = channel;
14551474

@@ -3515,6 +3534,8 @@ channel_parse_messages(void)
35153534
int r;
35163535
int part = PART_SOCK;
35173536

3537+
++safe_to_invoke_callback;
3538+
35183539
/* Only do this message when another message was given, otherwise we get
35193540
* lots of them. */
35203541
if (did_log_msg)
@@ -3532,6 +3553,13 @@ channel_parse_messages(void)
35323553
channel = first_channel;
35333554
continue;
35343555
}
3556+
if (channel->ch_to_be_freed)
3557+
{
3558+
channel_free(channel);
3559+
/* channel has been freed, start over */
3560+
channel = first_channel;
3561+
continue;
3562+
}
35353563
if (channel->ch_refcount == 0 && !channel_still_useful(channel))
35363564
{
35373565
/* channel is no longer useful, free it */
@@ -3572,6 +3600,8 @@ channel_parse_messages(void)
35723600
redraw_after_callback();
35733601
}
35743602

3603+
--safe_to_invoke_callback;
3604+
35753605
return ret;
35763606
}
35773607

src/structs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,8 @@ struct channel_S {
14191419
int ch_to_be_closed; /* When TRUE reading or writing failed and
14201420
* the channel must be closed when it's safe
14211421
* to invoke callbacks. */
1422+
int ch_to_be_freed; /* When TRUE channel must be freed when it's
1423+
* safe to invoke callbacks. */
14221424
int ch_error; /* When TRUE an error was reported. Avoids
14231425
* giving pages full of error messages when
14241426
* the other side has exited, only mention the

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+
1827,
756758
/**/
757759
1826,
758760
/**/

0 commit comments

Comments
 (0)