mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 18:55:14 -07:00
fix(extmarks): fix heap buffer overflow caused by inline virtual text (#23851)
also fixes an edge case where the extends character would not be drawn if the real text exactly fits the grid.
This commit is contained in:
parent
fa0a25dcb3
commit
31a51acdc3
@ -134,6 +134,7 @@ typedef struct {
|
|||||||
|
|
||||||
int skip_cells; // nr of cells to skip for virtual text
|
int skip_cells; // nr of cells to skip for virtual text
|
||||||
int skipped_cells; // nr of skipped virtual text cells
|
int skipped_cells; // nr of skipped virtual text cells
|
||||||
|
bool more_virt_inline_chunks; // indicates if there is more inline virtual text after n_extra
|
||||||
} winlinevars_T;
|
} winlinevars_T;
|
||||||
|
|
||||||
/// for line_putchar. Contains the state that needs to be remembered from
|
/// for line_putchar. Contains the state that needs to be remembered from
|
||||||
@ -870,6 +871,25 @@ static void apply_cursorline_highlight(win_T *wp, winlinevars_T *wlv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks if there is more inline virtual text that need to be drawn
|
||||||
|
// and sets has_more_virt_inline_chunks to reflect that.
|
||||||
|
static bool has_more_inline_virt(winlinevars_T *wlv, ptrdiff_t v)
|
||||||
|
{
|
||||||
|
DecorState *state = &decor_state;
|
||||||
|
for (size_t i = 0; i < kv_size(state->active); i++) {
|
||||||
|
DecorRange *item = &kv_A(state->active, i);
|
||||||
|
if (item->start_row != state->row
|
||||||
|
|| !kv_size(item->decor.virt_text)
|
||||||
|
|| item->decor.virt_text_pos != kVTInline) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (item->draw_col >= -1 && item->start_col >= v) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t v)
|
static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t v)
|
||||||
{
|
{
|
||||||
while (wlv->n_extra == 0) {
|
while (wlv->n_extra == 0) {
|
||||||
@ -892,6 +912,7 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
wlv->more_virt_inline_chunks = has_more_inline_virt(wlv, v);
|
||||||
if (!kv_size(wlv->virt_inline)) {
|
if (!kv_size(wlv->virt_inline)) {
|
||||||
// no more inline virtual text here
|
// no more inline virtual text here
|
||||||
break;
|
break;
|
||||||
@ -909,6 +930,11 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t
|
|||||||
wlv->c_final = NUL;
|
wlv->c_final = NUL;
|
||||||
wlv->extra_attr = vtc.hl_id ? syn_id2attr(vtc.hl_id) : 0;
|
wlv->extra_attr = vtc.hl_id ? syn_id2attr(vtc.hl_id) : 0;
|
||||||
wlv->n_attr = mb_charlen(vtc.text);
|
wlv->n_attr = mb_charlen(vtc.text);
|
||||||
|
|
||||||
|
// Checks if there is more inline virtual text chunks that need to be drawn.
|
||||||
|
wlv->more_virt_inline_chunks = has_more_inline_virt(wlv, v)
|
||||||
|
|| wlv->virt_inline_i < kv_size(wlv->virt_inline);
|
||||||
|
|
||||||
// If the text didn't reach until the first window
|
// If the text didn't reach until the first window
|
||||||
// column we need to skip cells.
|
// column we need to skip cells.
|
||||||
if (wlv->skip_cells > 0) {
|
if (wlv->skip_cells > 0) {
|
||||||
@ -2874,7 +2900,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|
|||||||
&& !has_fold
|
&& !has_fold
|
||||||
&& (*ptr != NUL
|
&& (*ptr != NUL
|
||||||
|| lcs_eol_one > 0
|
|| lcs_eol_one > 0
|
||||||
|| (wlv.n_extra > 0 && (wlv.c_extra != NUL || *wlv.p_extra != NUL)))) {
|
|| (wlv.n_extra > 0 && (wlv.c_extra != NUL || *wlv.p_extra != NUL))
|
||||||
|
|| wlv.more_virt_inline_chunks)) {
|
||||||
c = wp->w_p_lcs_chars.ext;
|
c = wp->w_p_lcs_chars.ext;
|
||||||
wlv.char_attr = win_hl_attr(wp, HLF_AT);
|
wlv.char_attr = win_hl_attr(wp, HLF_AT);
|
||||||
mb_c = c;
|
mb_c = c;
|
||||||
@ -3064,7 +3091,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|
|||||||
|| (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL
|
|| (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL
|
||||||
&& wlv.p_extra != at_end_str)
|
&& wlv.p_extra != at_end_str)
|
||||||
|| (wlv.n_extra != 0
|
|| (wlv.n_extra != 0
|
||||||
&& (wlv.c_extra != NUL || *wlv.p_extra != NUL)))) {
|
&& (wlv.c_extra != NUL || *wlv.p_extra != NUL)) || wlv.more_virt_inline_chunks)) {
|
||||||
bool wrap = wp->w_p_wrap // Wrapping enabled.
|
bool wrap = wp->w_p_wrap // Wrapping enabled.
|
||||||
&& wlv.filler_todo <= 0 // Not drawing diff filler lines.
|
&& wlv.filler_todo <= 0 // Not drawing diff filler lines.
|
||||||
&& lcs_eol_one != -1 // Haven't printed the lcs_eol character.
|
&& lcs_eol_one != -1 // Haven't printed the lcs_eol character.
|
||||||
|
@ -2506,6 +2506,28 @@ bbbbbbb]])
|
|||||||
|
|
|
|
||||||
]]}
|
]]}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('list "extends" is drawn with only inline virtual text offscreen', function()
|
||||||
|
command('set nowrap')
|
||||||
|
command('set list')
|
||||||
|
command('set listchars+=extends:c')
|
||||||
|
meths.buf_set_extmark(0, ns, 0, 0,
|
||||||
|
{ virt_text = { { 'test', 'Special' } }, virt_text_pos = 'inline' })
|
||||||
|
insert(string.rep('a', 50))
|
||||||
|
feed('gg0')
|
||||||
|
screen:expect { grid = [[
|
||||||
|
^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:c}|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('decorations: virtual lines', function()
|
describe('decorations: virtual lines', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user