Mercurial > vim
comparison src/channel.c @ 9246:6ee88fa405b3 v7.4.1906
commit https://github.com/vim/vim/commit/5f1032d2a55b9417a0a6fa225e35089c98a5a419
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Jun 7 22:16:36 2016 +0200
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.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Tue, 07 Jun 2016 22:30:06 +0200 |
parents | 7d13d180a6ae |
children | 9f97a6290c63 |
comparison
equal
deleted
inserted
replaced
9245:fe03dc56fba7 | 9246:6ee88fa405b3 |
---|---|
1548 clear_tv(&rettv); | 1548 clear_tv(&rettv); |
1549 channel_need_redraw = TRUE; | 1549 channel_need_redraw = TRUE; |
1550 } | 1550 } |
1551 | 1551 |
1552 /* | 1552 /* |
1553 * Return the first node from "channel"/"part" without removing it. | |
1554 * Returns NULL if there is nothing. | |
1555 */ | |
1556 readq_T * | |
1557 channel_peek(channel_T *channel, int part) | |
1558 { | |
1559 readq_T *head = &channel->ch_part[part].ch_head; | |
1560 | |
1561 return head->rq_next; | |
1562 } | |
1563 | |
1564 /* | |
1565 * Return a pointer to the first NL in "node". | |
1566 * Skips over NUL characters. | |
1567 * Returns NULL if there is no NL. | |
1568 */ | |
1569 char_u * | |
1570 channel_first_nl(readq_T *node) | |
1571 { | |
1572 char_u *buffer = node->rq_buffer; | |
1573 long_u i; | |
1574 | |
1575 for (i = 0; i < node->rq_buflen; ++i) | |
1576 if (buffer[i] == NL) | |
1577 return buffer + i; | |
1578 return NULL; | |
1579 } | |
1580 | |
1581 /* | |
1553 * Return the first buffer from channel "channel"/"part" and remove it. | 1582 * Return the first buffer from channel "channel"/"part" and remove it. |
1554 * The caller must free it. | 1583 * The caller must free it. |
1555 * Returns NULL if there is nothing. | 1584 * Returns NULL if there is nothing. |
1556 */ | 1585 */ |
1557 char_u * | 1586 char_u * |
1574 return p; | 1603 return p; |
1575 } | 1604 } |
1576 | 1605 |
1577 /* | 1606 /* |
1578 * Returns the whole buffer contents concatenated for "channel"/"part". | 1607 * Returns the whole buffer contents concatenated for "channel"/"part". |
1608 * Replaces NUL bytes with NL. | |
1579 */ | 1609 */ |
1580 static char_u * | 1610 static char_u * |
1581 channel_get_all(channel_T *channel, int part) | 1611 channel_get_all(channel_T *channel, int part) |
1582 { | 1612 { |
1583 readq_T *head = &channel->ch_part[part].ch_head; | 1613 readq_T *head = &channel->ch_part[part].ch_head; |
1597 if (res == NULL) | 1627 if (res == NULL) |
1598 return NULL; | 1628 return NULL; |
1599 p = res; | 1629 p = res; |
1600 for (node = head->rq_next; node != NULL; node = node->rq_next) | 1630 for (node = head->rq_next; node != NULL; node = node->rq_next) |
1601 { | 1631 { |
1602 STRCPY(p, node->rq_buffer); | 1632 mch_memmove(p, node->rq_buffer, node->rq_buflen); |
1603 p += node->rq_buflen; | 1633 p += node->rq_buflen; |
1604 } | 1634 } |
1605 *p = NUL; | 1635 *p = NUL; |
1606 | 1636 |
1607 /* Free all buffers */ | 1637 /* Free all buffers */ |
1609 { | 1639 { |
1610 p = channel_get(channel, part); | 1640 p = channel_get(channel, part); |
1611 vim_free(p); | 1641 vim_free(p); |
1612 } while (p != NULL); | 1642 } while (p != NULL); |
1613 | 1643 |
1644 /* turn all NUL into NL */ | |
1645 while (len > 0) | |
1646 { | |
1647 --len; | |
1648 if (res[len] == NUL) | |
1649 res[len] = NL; | |
1650 } | |
1651 | |
1614 return res; | 1652 return res; |
1653 } | |
1654 | |
1655 /* | |
1656 * Consume "len" bytes from the head of "channel"/"part". | |
1657 * Caller must check these bytes are available. | |
1658 */ | |
1659 void | |
1660 channel_consume(channel_T *channel, int part, int len) | |
1661 { | |
1662 readq_T *head = &channel->ch_part[part].ch_head; | |
1663 readq_T *node = head->rq_next; | |
1664 char_u *buf = node->rq_buffer; | |
1665 | |
1666 mch_memmove(buf, buf + len, node->rq_buflen - len); | |
1667 node->rq_buflen -= len; | |
1615 } | 1668 } |
1616 | 1669 |
1617 /* | 1670 /* |
1618 * Collapses the first and second buffer for "channel"/"part". | 1671 * Collapses the first and second buffer for "channel"/"part". |
1619 * Returns FAIL if that is not possible. | 1672 * Returns FAIL if that is not possible. |
1635 | 1688 |
1636 last_node = node->rq_next; | 1689 last_node = node->rq_next; |
1637 len = node->rq_buflen + last_node->rq_buflen + 1; | 1690 len = node->rq_buflen + last_node->rq_buflen + 1; |
1638 if (want_nl) | 1691 if (want_nl) |
1639 while (last_node->rq_next != NULL | 1692 while (last_node->rq_next != NULL |
1640 && vim_strchr(last_node->rq_buffer, NL) == NULL) | 1693 && channel_first_nl(last_node) == NULL) |
1641 { | 1694 { |
1642 last_node = last_node->rq_next; | 1695 last_node = last_node->rq_next; |
1643 len += last_node->rq_buflen; | 1696 len += last_node->rq_buflen; |
1644 } | 1697 } |
1645 | 1698 |
1646 p = newbuf = alloc(len); | 1699 p = newbuf = alloc(len); |
1647 if (newbuf == NULL) | 1700 if (newbuf == NULL) |
1648 return FAIL; /* out of memory */ | 1701 return FAIL; /* out of memory */ |
1649 STRCPY(p, node->rq_buffer); | 1702 mch_memmove(p, node->rq_buffer, node->rq_buflen); |
1650 p += node->rq_buflen; | 1703 p += node->rq_buflen; |
1651 vim_free(node->rq_buffer); | 1704 vim_free(node->rq_buffer); |
1652 node->rq_buffer = newbuf; | 1705 node->rq_buffer = newbuf; |
1653 for (n = node; n != last_node; ) | 1706 for (n = node; n != last_node; ) |
1654 { | 1707 { |
1655 n = n->rq_next; | 1708 n = n->rq_next; |
1656 STRCPY(p, n->rq_buffer); | 1709 mch_memmove(p, n->rq_buffer, n->rq_buflen); |
1657 p += n->rq_buflen; | 1710 p += n->rq_buflen; |
1658 vim_free(n->rq_buffer); | 1711 vim_free(n->rq_buffer); |
1659 } | 1712 } |
1660 node->rq_buflen = (long_u)(p - newbuf); | 1713 node->rq_buflen = (long_u)(p - newbuf); |
1661 | 1714 |
1689 int i; | 1742 int i; |
1690 | 1743 |
1691 node = (readq_T *)alloc(sizeof(readq_T)); | 1744 node = (readq_T *)alloc(sizeof(readq_T)); |
1692 if (node == NULL) | 1745 if (node == NULL) |
1693 return FAIL; /* out of memory */ | 1746 return FAIL; /* out of memory */ |
1747 /* A NUL is added at the end, because netbeans code expects that. | |
1748 * Otherwise a NUL may appear inside the text. */ | |
1694 node->rq_buffer = alloc(len + 1); | 1749 node->rq_buffer = alloc(len + 1); |
1695 if (node->rq_buffer == NULL) | 1750 if (node->rq_buffer == NULL) |
1696 { | 1751 { |
1697 vim_free(node); | 1752 vim_free(node); |
1698 return FAIL; /* out of memory */ | 1753 return FAIL; /* out of memory */ |
2281 cbq_T *cbhead = &channel->ch_part[part].ch_cb_head; | 2336 cbq_T *cbhead = &channel->ch_part[part].ch_cb_head; |
2282 cbq_T *cbitem; | 2337 cbq_T *cbitem; |
2283 char_u *callback = NULL; | 2338 char_u *callback = NULL; |
2284 partial_T *partial = NULL; | 2339 partial_T *partial = NULL; |
2285 buf_T *buffer = NULL; | 2340 buf_T *buffer = NULL; |
2341 char_u *p; | |
2286 | 2342 |
2287 if (channel->ch_nb_close_cb != NULL) | 2343 if (channel->ch_nb_close_cb != NULL) |
2288 /* this channel is handled elsewhere (netbeans) */ | 2344 /* this channel is handled elsewhere (netbeans) */ |
2289 return FALSE; | 2345 return FALSE; |
2290 | 2346 |
2373 | 2429 |
2374 if (ch_mode == MODE_NL) | 2430 if (ch_mode == MODE_NL) |
2375 { | 2431 { |
2376 char_u *nl; | 2432 char_u *nl; |
2377 char_u *buf; | 2433 char_u *buf; |
2434 readq_T *node; | |
2378 | 2435 |
2379 /* See if we have a message ending in NL in the first buffer. If | 2436 /* See if we have a message ending in NL in the first buffer. If |
2380 * not try to concatenate the first and the second buffer. */ | 2437 * not try to concatenate the first and the second buffer. */ |
2381 while (TRUE) | 2438 while (TRUE) |
2382 { | 2439 { |
2383 buf = channel_peek(channel, part); | 2440 node = channel_peek(channel, part); |
2384 nl = vim_strchr(buf, NL); | 2441 nl = channel_first_nl(node); |
2385 if (nl != NULL) | 2442 if (nl != NULL) |
2386 break; | 2443 break; |
2387 if (channel_collapse(channel, part, TRUE) == FAIL) | 2444 if (channel_collapse(channel, part, TRUE) == FAIL) |
2388 return FALSE; /* incomplete message */ | 2445 return FALSE; /* incomplete message */ |
2389 } | 2446 } |
2390 if (nl[1] == NUL) | 2447 buf = node->rq_buffer; |
2448 | |
2449 /* Convert NUL to NL, the internal representation. */ | |
2450 for (p = buf; p < nl && p < buf + node->rq_buflen; ++p) | |
2451 if (*p == NUL) | |
2452 *p = NL; | |
2453 | |
2454 if (nl + 1 == buf + node->rq_buflen) | |
2391 { | 2455 { |
2392 /* get the whole buffer, drop the NL */ | 2456 /* get the whole buffer, drop the NL */ |
2393 msg = channel_get(channel, part); | 2457 msg = channel_get(channel, part); |
2394 *nl = NUL; | 2458 *nl = NUL; |
2395 } | 2459 } |
2396 else | 2460 else |
2397 { | 2461 { |
2398 /* Copy the message into allocated memory and remove it from | 2462 /* Copy the message into allocated memory (excluding the NL) |
2399 * the buffer. */ | 2463 * and remove it from the buffer (including the NL). */ |
2400 msg = vim_strnsave(buf, (int)(nl - buf)); | 2464 msg = vim_strnsave(buf, (int)(nl - buf)); |
2401 mch_memmove(buf, nl + 1, STRLEN(nl + 1) + 1); | 2465 channel_consume(channel, part, (int)(nl - buf) + 1); |
2402 } | 2466 } |
2403 } | 2467 } |
2404 else | 2468 else |
2469 { | |
2405 /* For a raw channel we don't know where the message ends, just | 2470 /* For a raw channel we don't know where the message ends, just |
2406 * get everything we have. */ | 2471 * get everything we have. |
2472 * Convert NUL to NL, the internal representation. */ | |
2407 msg = channel_get_all(channel, part); | 2473 msg = channel_get_all(channel, part); |
2474 } | |
2408 | 2475 |
2409 if (msg == NULL) | 2476 if (msg == NULL) |
2410 return FALSE; /* out of memory (and avoids Coverity warning) */ | 2477 return FALSE; /* out of memory (and avoids Coverity warning) */ |
2411 | 2478 |
2412 argv[1].v_type = VAR_STRING; | 2479 argv[1].v_type = VAR_STRING; |
2663 for (part = PART_SOCK; part <= PART_ERR; ++part) | 2730 for (part = PART_SOCK; part <= PART_ERR; ++part) |
2664 drop_messages(channel, part); | 2731 drop_messages(channel, part); |
2665 } | 2732 } |
2666 | 2733 |
2667 channel->ch_nb_close_cb = NULL; | 2734 channel->ch_nb_close_cb = NULL; |
2668 } | |
2669 | |
2670 /* | |
2671 * Return the first buffer from "channel"/"part" without removing it. | |
2672 * Returns NULL if there is nothing. | |
2673 */ | |
2674 char_u * | |
2675 channel_peek(channel_T *channel, int part) | |
2676 { | |
2677 readq_T *head = &channel->ch_part[part].ch_head; | |
2678 | |
2679 if (head->rq_next == NULL) | |
2680 return NULL; | |
2681 return head->rq_next->rq_buffer; | |
2682 } | 2735 } |
2683 | 2736 |
2684 /* | 2737 /* |
2685 * Clear the read buffer on "channel"/"part". | 2738 * Clear the read buffer on "channel"/"part". |
2686 */ | 2739 */ |
3041 char_u *buf; | 3094 char_u *buf; |
3042 char_u *msg; | 3095 char_u *msg; |
3043 ch_mode_T mode = channel->ch_part[part].ch_mode; | 3096 ch_mode_T mode = channel->ch_part[part].ch_mode; |
3044 sock_T fd = channel->ch_part[part].ch_fd; | 3097 sock_T fd = channel->ch_part[part].ch_fd; |
3045 char_u *nl; | 3098 char_u *nl; |
3099 readq_T *node; | |
3046 | 3100 |
3047 ch_logsn(channel, "Blocking %s read, timeout: %d msec", | 3101 ch_logsn(channel, "Blocking %s read, timeout: %d msec", |
3048 mode == MODE_RAW ? "RAW" : "NL", timeout); | 3102 mode == MODE_RAW ? "RAW" : "NL", timeout); |
3049 | 3103 |
3050 while (TRUE) | 3104 while (TRUE) |
3051 { | 3105 { |
3052 buf = channel_peek(channel, part); | 3106 node = channel_peek(channel, part); |
3053 if (buf != NULL && (mode == MODE_RAW | 3107 if (node != NULL) |
3054 || (mode == MODE_NL && vim_strchr(buf, NL) != NULL))) | 3108 { |
3055 break; | 3109 if (mode == MODE_RAW || (mode == MODE_NL |
3056 if (buf != NULL && channel_collapse(channel, part, mode == MODE_NL) | 3110 && channel_first_nl(node) != NULL)) |
3057 == OK) | 3111 /* got a complete message */ |
3058 continue; | 3112 break; |
3113 if (channel_collapse(channel, part, mode == MODE_NL) == OK) | |
3114 continue; | |
3115 } | |
3059 | 3116 |
3060 /* Wait for up to the channel timeout. */ | 3117 /* Wait for up to the channel timeout. */ |
3061 if (fd == INVALID_FD) | 3118 if (fd == INVALID_FD) |
3062 return NULL; | 3119 return NULL; |
3063 if (channel_wait(channel, fd, timeout) != CW_READY) | 3120 if (channel_wait(channel, fd, timeout) != CW_READY) |
3072 { | 3129 { |
3073 msg = channel_get_all(channel, part); | 3130 msg = channel_get_all(channel, part); |
3074 } | 3131 } |
3075 else | 3132 else |
3076 { | 3133 { |
3077 nl = vim_strchr(buf, NL); | 3134 char_u *p; |
3078 if (nl[1] == NUL) | 3135 |
3136 buf = node->rq_buffer; | |
3137 nl = channel_first_nl(node); | |
3138 | |
3139 /* Convert NUL to NL, the internal representation. */ | |
3140 for (p = buf; p < nl && p < buf + node->rq_buflen; ++p) | |
3141 if (*p == NUL) | |
3142 *p = NL; | |
3143 | |
3144 if (nl + 1 == buf + node->rq_buflen) | |
3079 { | 3145 { |
3080 /* get the whole buffer */ | 3146 /* get the whole buffer */ |
3081 msg = channel_get(channel, part); | 3147 msg = channel_get(channel, part); |
3082 *nl = NUL; | 3148 *nl = NUL; |
3083 } | 3149 } |
3084 else | 3150 else |
3085 { | 3151 { |
3086 /* Copy the message into allocated memory and remove it from the | 3152 /* Copy the message into allocated memory and remove it from the |
3087 * buffer. */ | 3153 * buffer. */ |
3088 msg = vim_strnsave(buf, (int)(nl - buf)); | 3154 msg = vim_strnsave(buf, (int)(nl - buf)); |
3089 mch_memmove(buf, nl + 1, STRLEN(nl + 1) + 1); | 3155 channel_consume(channel, part, (int)(nl - buf) + 1); |
3090 } | 3156 } |
3091 } | 3157 } |
3092 if (log_fd != NULL) | 3158 if (log_fd != NULL) |
3093 ch_logn(channel, "Returning %d bytes", (int)STRLEN(msg)); | 3159 ch_logn(channel, "Returning %d bytes", (int)STRLEN(msg)); |
3094 return msg; | 3160 return msg; |