0
0
mirror of https://github.com/vim/vim.git synced 2025-09-29 04:34:16 -04:00

patch 7.4.1906

Problem:    Collapsing channel buffers and searching for NL does not work
            properly. (Xavier de Gary, Ramel Eshed)
Solution:   Do not assume the buffer contains a NUL or not.  Change NUL bytes
            to NL to avoid the string is truncated.
This commit is contained in:
Bram Moolenaar
2016-06-07 22:16:36 +02:00
parent fdd82fe365
commit 5f1032d2a5
4 changed files with 113 additions and 42 deletions

View File

@@ -1549,6 +1549,35 @@ invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
channel_need_redraw = TRUE; channel_need_redraw = TRUE;
} }
/*
* Return the first node from "channel"/"part" without removing it.
* Returns NULL if there is nothing.
*/
readq_T *
channel_peek(channel_T *channel, int part)
{
readq_T *head = &channel->ch_part[part].ch_head;
return head->rq_next;
}
/*
* Return a pointer to the first NL in "node".
* Skips over NUL characters.
* Returns NULL if there is no NL.
*/
char_u *
channel_first_nl(readq_T *node)
{
char_u *buffer = node->rq_buffer;
long_u i;
for (i = 0; i < node->rq_buflen; ++i)
if (buffer[i] == NL)
return buffer + i;
return NULL;
}
/* /*
* Return the first buffer from channel "channel"/"part" and remove it. * Return the first buffer from channel "channel"/"part" and remove it.
* The caller must free it. * The caller must free it.
@@ -1576,6 +1605,7 @@ channel_get(channel_T *channel, int part)
/* /*
* Returns the whole buffer contents concatenated for "channel"/"part". * Returns the whole buffer contents concatenated for "channel"/"part".
* Replaces NUL bytes with NL.
*/ */
static char_u * static char_u *
channel_get_all(channel_T *channel, int part) channel_get_all(channel_T *channel, int part)
@@ -1599,7 +1629,7 @@ channel_get_all(channel_T *channel, int part)
p = res; p = res;
for (node = head->rq_next; node != NULL; node = node->rq_next) for (node = head->rq_next; node != NULL; node = node->rq_next)
{ {
STRCPY(p, node->rq_buffer); mch_memmove(p, node->rq_buffer, node->rq_buflen);
p += node->rq_buflen; p += node->rq_buflen;
} }
*p = NUL; *p = NUL;
@@ -1611,9 +1641,32 @@ channel_get_all(channel_T *channel, int part)
vim_free(p); vim_free(p);
} while (p != NULL); } while (p != NULL);
/* turn all NUL into NL */
while (len > 0)
{
--len;
if (res[len] == NUL)
res[len] = NL;
}
return res; return res;
} }
/*
* Consume "len" bytes from the head of "channel"/"part".
* Caller must check these bytes are available.
*/
void
channel_consume(channel_T *channel, int part, int len)
{
readq_T *head = &channel->ch_part[part].ch_head;
readq_T *node = head->rq_next;
char_u *buf = node->rq_buffer;
mch_memmove(buf, buf + len, node->rq_buflen - len);
node->rq_buflen -= len;
}
/* /*
* Collapses the first and second buffer for "channel"/"part". * Collapses the first and second buffer for "channel"/"part".
* Returns FAIL if that is not possible. * Returns FAIL if that is not possible.
@@ -1637,7 +1690,7 @@ channel_collapse(channel_T *channel, int part, int want_nl)
len = node->rq_buflen + last_node->rq_buflen + 1; len = node->rq_buflen + last_node->rq_buflen + 1;
if (want_nl) if (want_nl)
while (last_node->rq_next != NULL while (last_node->rq_next != NULL
&& vim_strchr(last_node->rq_buffer, NL) == NULL) && channel_first_nl(last_node) == NULL)
{ {
last_node = last_node->rq_next; last_node = last_node->rq_next;
len += last_node->rq_buflen; len += last_node->rq_buflen;
@@ -1646,14 +1699,14 @@ channel_collapse(channel_T *channel, int part, int want_nl)
p = newbuf = alloc(len); p = newbuf = alloc(len);
if (newbuf == NULL) if (newbuf == NULL)
return FAIL; /* out of memory */ return FAIL; /* out of memory */
STRCPY(p, node->rq_buffer); mch_memmove(p, node->rq_buffer, node->rq_buflen);
p += node->rq_buflen; p += node->rq_buflen;
vim_free(node->rq_buffer); vim_free(node->rq_buffer);
node->rq_buffer = newbuf; node->rq_buffer = newbuf;
for (n = node; n != last_node; ) for (n = node; n != last_node; )
{ {
n = n->rq_next; n = n->rq_next;
STRCPY(p, n->rq_buffer); mch_memmove(p, n->rq_buffer, n->rq_buflen);
p += n->rq_buflen; p += n->rq_buflen;
vim_free(n->rq_buffer); vim_free(n->rq_buffer);
} }
@@ -1691,6 +1744,8 @@ channel_save(channel_T *channel, int part, char_u *buf, int len,
node = (readq_T *)alloc(sizeof(readq_T)); node = (readq_T *)alloc(sizeof(readq_T));
if (node == NULL) if (node == NULL)
return FAIL; /* out of memory */ return FAIL; /* out of memory */
/* A NUL is added at the end, because netbeans code expects that.
* Otherwise a NUL may appear inside the text. */
node->rq_buffer = alloc(len + 1); node->rq_buffer = alloc(len + 1);
if (node->rq_buffer == NULL) if (node->rq_buffer == NULL)
{ {
@@ -2283,6 +2338,7 @@ may_invoke_callback(channel_T *channel, int part)
char_u *callback = NULL; char_u *callback = NULL;
partial_T *partial = NULL; partial_T *partial = NULL;
buf_T *buffer = NULL; buf_T *buffer = NULL;
char_u *p;
if (channel->ch_nb_close_cb != NULL) if (channel->ch_nb_close_cb != NULL)
/* this channel is handled elsewhere (netbeans) */ /* this channel is handled elsewhere (netbeans) */
@@ -2375,19 +2431,27 @@ may_invoke_callback(channel_T *channel, int part)
{ {
char_u *nl; char_u *nl;
char_u *buf; char_u *buf;
readq_T *node;
/* See if we have a message ending in NL in the first buffer. If /* See if we have a message ending in NL in the first buffer. If
* not try to concatenate the first and the second buffer. */ * not try to concatenate the first and the second buffer. */
while (TRUE) while (TRUE)
{ {
buf = channel_peek(channel, part); node = channel_peek(channel, part);
nl = vim_strchr(buf, NL); nl = channel_first_nl(node);
if (nl != NULL) if (nl != NULL)
break; break;
if (channel_collapse(channel, part, TRUE) == FAIL) if (channel_collapse(channel, part, TRUE) == FAIL)
return FALSE; /* incomplete message */ return FALSE; /* incomplete message */
} }
if (nl[1] == NUL) buf = node->rq_buffer;
/* Convert NUL to NL, the internal representation. */
for (p = buf; p < nl && p < buf + node->rq_buflen; ++p)
if (*p == NUL)
*p = NL;
if (nl + 1 == buf + node->rq_buflen)
{ {
/* get the whole buffer, drop the NL */ /* get the whole buffer, drop the NL */
msg = channel_get(channel, part); msg = channel_get(channel, part);
@@ -2395,16 +2459,19 @@ may_invoke_callback(channel_T *channel, int part)
} }
else else
{ {
/* Copy the message into allocated memory and remove it from /* Copy the message into allocated memory (excluding the NL)
* the buffer. */ * and remove it from the buffer (including the NL). */
msg = vim_strnsave(buf, (int)(nl - buf)); msg = vim_strnsave(buf, (int)(nl - buf));
mch_memmove(buf, nl + 1, STRLEN(nl + 1) + 1); channel_consume(channel, part, (int)(nl - buf) + 1);
} }
} }
else else
{
/* For a raw channel we don't know where the message ends, just /* For a raw channel we don't know where the message ends, just
* get everything we have. */ * get everything we have.
* Convert NUL to NL, the internal representation. */
msg = channel_get_all(channel, part); msg = channel_get_all(channel, part);
}
if (msg == NULL) if (msg == NULL)
return FALSE; /* out of memory (and avoids Coverity warning) */ return FALSE; /* out of memory (and avoids Coverity warning) */
@@ -2667,20 +2734,6 @@ channel_close(channel_T *channel, int invoke_close_cb)
channel->ch_nb_close_cb = NULL; channel->ch_nb_close_cb = NULL;
} }
/*
* Return the first buffer from "channel"/"part" without removing it.
* Returns NULL if there is nothing.
*/
char_u *
channel_peek(channel_T *channel, int part)
{
readq_T *head = &channel->ch_part[part].ch_head;
if (head->rq_next == NULL)
return NULL;
return head->rq_next->rq_buffer;
}
/* /*
* Clear the read buffer on "channel"/"part". * Clear the read buffer on "channel"/"part".
*/ */
@@ -3043,19 +3096,23 @@ channel_read_block(channel_T *channel, int part, int timeout)
ch_mode_T mode = channel->ch_part[part].ch_mode; ch_mode_T mode = channel->ch_part[part].ch_mode;
sock_T fd = channel->ch_part[part].ch_fd; sock_T fd = channel->ch_part[part].ch_fd;
char_u *nl; char_u *nl;
readq_T *node;
ch_logsn(channel, "Blocking %s read, timeout: %d msec", ch_logsn(channel, "Blocking %s read, timeout: %d msec",
mode == MODE_RAW ? "RAW" : "NL", timeout); mode == MODE_RAW ? "RAW" : "NL", timeout);
while (TRUE) while (TRUE)
{ {
buf = channel_peek(channel, part); node = channel_peek(channel, part);
if (buf != NULL && (mode == MODE_RAW if (node != NULL)
|| (mode == MODE_NL && vim_strchr(buf, NL) != NULL))) {
break; if (mode == MODE_RAW || (mode == MODE_NL
if (buf != NULL && channel_collapse(channel, part, mode == MODE_NL) && channel_first_nl(node) != NULL))
== OK) /* got a complete message */
continue; break;
if (channel_collapse(channel, part, mode == MODE_NL) == OK)
continue;
}
/* Wait for up to the channel timeout. */ /* Wait for up to the channel timeout. */
if (fd == INVALID_FD) if (fd == INVALID_FD)
@@ -3074,8 +3131,17 @@ channel_read_block(channel_T *channel, int part, int timeout)
} }
else else
{ {
nl = vim_strchr(buf, NL); char_u *p;
if (nl[1] == NUL)
buf = node->rq_buffer;
nl = channel_first_nl(node);
/* Convert NUL to NL, the internal representation. */
for (p = buf; p < nl && p < buf + node->rq_buflen; ++p)
if (*p == NUL)
*p = NL;
if (nl + 1 == buf + node->rq_buflen)
{ {
/* get the whole buffer */ /* get the whole buffer */
msg = channel_get(channel, part); msg = channel_get(channel, part);
@@ -3086,7 +3152,7 @@ channel_read_block(channel_T *channel, int part, int timeout)
/* Copy the message into allocated memory and remove it from the /* Copy the message into allocated memory and remove it from the
* buffer. */ * buffer. */
msg = vim_strnsave(buf, (int)(nl - buf)); msg = vim_strnsave(buf, (int)(nl - buf));
mch_memmove(buf, nl + 1, STRLEN(nl + 1) + 1); channel_consume(channel, part, (int)(nl - buf) + 1);
} }
} }
if (log_fd != NULL) if (log_fd != NULL)

View File

@@ -382,18 +382,19 @@ handle_key_queue(void)
void void
netbeans_parse_messages(void) netbeans_parse_messages(void)
{ {
readq_T *node;
char_u *buffer; char_u *buffer;
char_u *p; char_u *p;
int own_node; int own_node;
while (nb_channel != NULL) while (nb_channel != NULL)
{ {
buffer = channel_peek(nb_channel, PART_SOCK); node = channel_peek(nb_channel, PART_SOCK);
if (buffer == NULL) if (node == NULL)
break; /* nothing to read */ break; /* nothing to read */
/* Locate the first line in the first buffer. */ /* Locate the first line in the first buffer. */
p = vim_strchr(buffer, '\n'); p = channel_first_nl(node);
if (p == NULL) if (p == NULL)
{ {
/* Command isn't complete. If there is no following buffer, /* Command isn't complete. If there is no following buffer,
@@ -418,14 +419,14 @@ netbeans_parse_messages(void)
own_node = FALSE; own_node = FALSE;
/* now, parse and execute the commands */ /* now, parse and execute the commands */
nb_parse_cmd(buffer); nb_parse_cmd(node->rq_buffer);
if (own_node) if (own_node)
/* buffer finished, dispose of it */ /* buffer finished, dispose of it */
vim_free(buffer); vim_free(node->rq_buffer);
else else
/* more follows, move it to the start */ /* more follows, move it to the start */
STRMOVE(buffer, p); channel_consume(nb_channel, PART_SOCK, (int)(p - buffer));
} }
} }
} }

View File

@@ -17,14 +17,16 @@ void channel_set_req_callback(channel_T *channel, int part, char_u *callback, pa
void channel_buffer_free(buf_T *buf); void channel_buffer_free(buf_T *buf);
void channel_write_any_lines(void); void channel_write_any_lines(void);
void channel_write_new_lines(buf_T *buf); void channel_write_new_lines(buf_T *buf);
readq_T *channel_peek(channel_T *channel, int part);
char_u *channel_first_nl(readq_T *node);
char_u *channel_get(channel_T *channel, int part); char_u *channel_get(channel_T *channel, int part);
void channel_consume(channel_T *channel, int part, int len);
int channel_collapse(channel_T *channel, int part, int want_nl); int channel_collapse(channel_T *channel, int part, int want_nl);
int channel_can_write_to(channel_T *channel); int channel_can_write_to(channel_T *channel);
int channel_is_open(channel_T *channel); int channel_is_open(channel_T *channel);
char *channel_status(channel_T *channel); char *channel_status(channel_T *channel);
void channel_info(channel_T *channel, dict_T *dict); void channel_info(channel_T *channel, dict_T *dict);
void channel_close(channel_T *channel, int invoke_close_cb); void channel_close(channel_T *channel, int invoke_close_cb);
char_u *channel_peek(channel_T *channel, int part);
void channel_clear(channel_T *channel); void channel_clear(channel_T *channel);
void channel_free_all(void); void channel_free_all(void);
char_u *channel_read_block(channel_T *channel, int part, int timeout); char_u *channel_read_block(channel_T *channel, int part, int timeout);

View File

@@ -753,6 +753,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1906,
/**/ /**/
1905, 1905,
/**/ /**/