blink.cmp icon indicating copy to clipboard operation
blink.cmp copied to clipboard

buffer completion for large CJK document leads to segmentation fault of neovim

Open moetayuko opened this issue 1 year ago • 2 comments

Make sure you have done the following

  • [X] I have updated to the latest version of blink.cmp
  • [X] I have read the README

Bug Description

I'm using LazyVim, which enables the buffer completion source for blink.cmp https://github.com/LazyVim/LazyVim/blob/dc4345a5ee23ffb4aad50c01eca49d5bc47a96c3/lua/lazyvim/plugins/extras/coding/blink.lua#L76

when editing a large CJK document and modifying a long sentence in insert mode, neovim crashes with a segmentation fault right after the modification. I can no longer reproduce the crash once I disable buffer from completion sources, so I suspect there's something wrong with it

this is a random large Chinese document for reproducing the issue https://github.com/ArcturusZhang/Classical-Mechanics-Lecture-Notes/raw/refs/heads/master/chapter/chapter2.tex

here is a cast for the issue asciicast

below is the stack trace

#0  __strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:76
No locals.
#1  0x0000650858389eea in xstrdup (str=0x0) at /usr/src/debug/neovim/neovim/src/nvim/memory.c:469
No locals.
#2  0x0000650858356744 in nlua_luv_thread_common_cfpcall (lstate=0x72535a3e0380, nargs=1, nresult=-1,
    flags=1, is_callback=is_callback@entry=false) at /usr/src/debug/neovim/neovim/src/nvim/lua/executor.c:279
        error = <optimized out>
        retval = <optimized out>
        top = 2
        status = 2
#3  0x0000650858356895 in nlua_luv_thread_cfpcall (lstate=<optimized out>, nargs=<optimized out>,
    nresult=<optimized out>, flags=<optimized out>)
    at /usr/src/debug/neovim/neovim/src/nvim/lua/executor.c:244
No locals.
#4  0x0000725360b2b644 in luv_work_cb (L=0x72535a3e0380) at /usr/src/debug/libluv/luv-1.48.0-2/src/work.c:107
        i = <optimized out>
        req = <optimized out>
        work = 0x6508705fac00
        ctx = <optimized out>
        lctx = 0x72535a3ea4d8
        top = 0
#5  0x0000725360a17f06 in lj_BC_FUNCC () at buildvm_x86.dasc:857
No locals.
#6  0x0000725360a2c0aa in lua_pcall (L=L@entry=0x72535a3e0380, nargs=nargs@entry=1,
    nresults=nresults@entry=0, errfunc=errfunc@entry=0)
    at /usr/src/debug/luajit/LuaJIT-fe71d0fb54ceadfb5b5f3b6baf29e486d97f6059/src/lj_api.c:1122
        g = 0x72535a3e03e0
        oldh = 0 '\000'
        ef = <optimized out>
        status = <optimized out>
#7  0x00006508583566e7 in nlua_luv_thread_common_cfpcall (lstate=lstate@entry=0x72535a3e0380,
    nargs=nargs@entry=1, nresult=nresult@entry=0, flags=flags@entry=1, is_callback=is_callback@entry=false)
    at /usr/src/debug/neovim/neovim/src/nvim/lua/executor.c:263
        retval = <optimized out>
        top = 2
        status = <optimized out>
#8  0x0000650858356895 in nlua_luv_thread_cfpcall (lstate=lstate@entry=0x72535a3e0380, nargs=nargs@entry=1,
    nresult=nresult@entry=0, flags=flags@entry=1) at /usr/src/debug/neovim/neovim/src/nvim/lua/executor.c:244
No locals.
#9  0x00006508583568dd in nlua_luv_thread_cfcpcall (lstate=0x72535a3e0380, func=<optimized out>,
    ud=0x6508705fac00, flags=1) at /usr/src/debug/neovim/neovim/src/nvim/lua/executor.c:252
        retval = <optimized out>
#10 0x0000725360b2b8aa in luv_work_cb_wrapper (req=0x6508705fac00)
    at /usr/src/debug/libluv/luv-1.48.0-2/src/work.c:155
        work = 0x6508705fac00
        L = 0x72535a3e0380
        lctx = <optimized out>
        i = <optimized out>
#11 0x000072536090030a in worker (arg=0x0) at src/threadpool.c:122
        w = 0x6508705fac58
        q = 0x6508705fac70
        is_slow_work = 0

Relevant configuration

vim.env.LAZY_STDPATH = ".repro"
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()

require("lazy.minit").repro({
	spec = {
		{ "LazyVim/LazyVim", import = "lazyvim.plugins" },
		-- uncomment the following block avoids segmentation fault
		-- {
		-- 	"saghen/blink.cmp",
		-- 	opts = {
		-- 		sources = {
		-- 			default = function()
		-- 				return { "lsp", "path", "snippets" }
		-- 			end,
		-- 		},
		-- 	},
		-- },
	},
})

neovim version

v0.10.2

blink.cmp version: branch, tag, or commit

v0.7.6

moetayuko avatar Dec 14 '24 12:12 moetayuko

Do we really need this '+ 1'? It seems that removing this line solves the problem.

https://github.com/Saghen/blink.cmp/blob/217f670d85d8b56f48146636b61019ccd072f9cc/lua/blink/cmp/sources/buffer.lua#L21-L24

It also produces a (seemingly) weird chunk:

Typing ipsum on a text:

Lorem {cursor} dolor sit amet, consectetur adipiscing elit. Gravida mus sociosqu

with start_col = start_col + 1:

{
  _line = "Lorem i  dolor sit amet, consectetur adipiscing elit. Gravida mus sociosqu"
}

without start_col = start_col + 1:

{                                                                                                                           
  _line = "Lorem   dolor sit amet, consectetur adipiscing elit. Gravida mus sociosqu"                                        
}  

Typing bar baz on a text:

foo("{cursor}")

with start_col = start_col + 1:

{                                                                                                                           
  _line = 'foo("b ")'                                                                                                        
}                                                                                                                           
{                                                                                                                           
  _line = 'foo("bar b ")'                                                                                                    
}    

without start_col = start_col + 1:

{                                                                                                                           
  _line = 'foo(" ")'                                                                                                         
}                                                                                                                           
{                                                                                                                           
  _line = 'foo("bar  ")'                                                                                                     
}  

itepechi avatar Dec 14 '24 16:12 itepechi

Do we really need this '+ 1'? It seems that removing this line solves the problem.

confirmed

moetayuko avatar Dec 15 '24 03:12 moetayuko

Thanks for debugging this @itepechi!

saghen avatar Dec 16 '24 18:12 saghen