lf
lf copied to clipboard
Crash on file deletion
I was deleting some pictures with the following workflow:
I opened a folder from lf in my image viewer Sxiv, marked through Sxiv a bunch of pictures (>100), and on exit Sxiv sends to stdout the list of marked images, which I pipe to the following script which selects them in the lf
interface:
while read -r file; do
[ -z "$file" ] && continue
lf -remote "send select \"$file\""
lf -remote "send toggle"
done
So I did this, and then pressed D
in lf
to delete them, confirmed, and the following crash error happened. However, the images were indeed deleted, so no error as in functionality.
(list of images)...
delete?[y/N]y
fatal error: concurrent map iteration and map write
goroutine 13 [running]:
runtime.throw({0x55f98590b22b?, 0x9?})
runtime/panic.go:992 +0x71 fp=0xc000383990 sp=0xc000383960 pc=0x55f985797011
runtime.mapiternext(0xc000383ae8?)
runtime/map.go:871 +0x4eb fp=0xc000383a00 sp=0xc000383990 pc=0x55f98577268b
main.(*nav).currSelections(0xc000111520)
github.com/gokcehan/lf/nav.go:1694 +0x12a fp=0xc000383b58 sp=0xc000383a00 pc=0x55f9858eb9aa
main.(*nav).exportFiles(0xc000111520)
github.com/gokcehan/lf/nav.go:597 +0x4e fp=0xc000383bb0 sp=0xc000383b58
pc=0x55f9858e380e
main.(*nav).preview(0xc000111520, {0xc0004ef100, 0x1e}, 0xc0000192c0)
github.com/gokcehan/lf/nav.go:654 +0x165 fp=0xc000383f18 sp=0xc000383bb0 pc=0x55f9858e3dc5
main.(*nav).previewLoop(0xc000111520, 0xc0001de9a0)
github.com/gokcehan/lf/nav.go:626 +0x1d9 fp=0xc000383fc0 sp=0xc000383f18 pc=0x55f9858e3a59
main.(*app).loop.func2()
github.com/gokcehan/lf/app.go:239 +0x2a fp=0xc000383fe0 sp=0xc000383fc0
pc=0x55f9858c516a
runtime.goexit()
runtime/asm_amd64.s:1571 +0x1 fp=0xc000383fe8 sp=0xc000383fe0 pc=0x55f9857c7081
created by main.(*app).loop
github.com/gokcehan/lf/app.go:239 +0xaa
goroutine 1 [runnable]:
syscall.Syscall6(0x106, 0xffffffffffffff9c, 0xc0004ee020, 0xc0000cfe48, 0x100, 0x0, 0x0)
syscall/asm_linux_amd64.s:43 +0x5
syscall.fstatat(0xffffffffffffffff?, {0xc0004ee480?, 0x4e4b09b3da?}, 0xc0000cfe48?, 0xffffffffffffffff?)
syscall/zsyscall_linux_amd64.go:1450 +0x10f
syscall.Lstat(...)
syscall/syscall_linux_amd64.go:68
os.lstatNolog.func1(...)
os/stat_unix.go:45
os.ignoringEINTR(...)
os/file_posix.go:245
os.lstatNolog({0xc0004ee480, 0x1e})
os/stat_unix.go:44 +0x5b
os.Lstat({0xc0004ee480, 0x1e})
os/stat.go:22 +0x34
main.(*nav).renew(0xc000111520)
github.com/gokcehan/lf/nav.go:546 +0xd1
main.(*app).runShell(0xc000162380, {0xc0000261e0, 0x93}, {0x0, 0x0, 0x0}, {0xc000358368, 0x1})
github.com/gokcehan/lf/app.go:575 +0x766
main.(*execExpr).eval(0xc00032e560, 0xc00007dcb0?, {0x0, 0x0, 0x0})
github.com/gokcehan/lf/eval.go:2079 +0x150
main.(*callExpr).eval(0xc000318750, 0xc000162380, {0xc000296b00?, 0x0?, 0x0?})
github.com/gokcehan/lf/eval.go:1118 +0x3877
main.(*app).loop(0xc000162380)
github.com/gokcehan/lf/app.go:434 +0xa8f
main.run()
github.com/gokcehan/lf/client.go:62 +0x757
main.main()
github.com/gokcehan/lf/main.go:319 +0x7b9
goroutine 8 [syscall, 4 minutes]:
os/signal.signal_recv()
runtime/sigqueue.go:151 +0x2f
os/signal.loop()
os/signal/signal_unix.go:23 +0x19
created by os/signal.Notify.func1.1
os/signal/signal.go:151 +0x2a
goroutine 11 [select]:
github.com/gdamore/tcell/v2.(*tScreen).PollEvent(0x0?)
github.com/gdamore/tcell/[email protected]/tscreen.go:928 +0x6a
main.(*ui).pollEvents(0xc0001de9a0)
github.com/gokcehan/lf/ui.go:562 +0x50
created by main.newUI
github.com/gokcehan/lf/ui.go:554 +0x34a
goroutine 12 [chan receive, 4 minutes]:
main.newApp.func1()
github.com/gokcehan/lf/app.go:48 +0x35
created by main.newApp
github.com/gokcehan/lf/app.go:47 +0x1cd
goroutine 14 [IO wait]:
internal/poll.runtime_pollWait(0x7fcbeca7bf88, 0x72)
runtime/netpoll.go:302 +0x89
internal/poll.(*pollDesc).wait(0xc00029a080?, 0xc0003c82ef?, 0x0)
internal/poll/fd_poll_runtime.go:83 +0x32
internal/poll.(*pollDesc).waitRead(...)
internal/poll/fd_poll_runtime.go:88
internal/poll.(*FD).Read(0xc00029a080, {0xc0003c82ef, 0xd11, 0xd11})
internal/poll/fd_unix.go:167 +0x25a
net.(*netFD).Read(0xc00029a080, {0xc0003c82ef?, 0xc00053a540?, 0xc000381df0?})
net/fd_posix.go:55 +0x29
net.(*conn).Read(0xc00029e000, {0xc0003c82ef?, 0xc000381e80?, 0x55f98576853d?})
net/net.go:183 +0x45
bufio.(*Scanner).Scan(0xc000381f50)
bufio/scan.go:215 +0x865
main.readExpr.func1()
github.com/gokcehan/lf/client.go:86 +0x210
created by main.readExpr
github.com/gokcehan/lf/client.go:70 +0x6a
goroutine 15 [select]:
main.(*ui).pollEvent(0xc0001de9a0)
github.com/gokcehan/lf/ui.go:974 +0xab
main.(*ui).readExpr.func1()
github.com/gokcehan/lf/ui.go:1171 +0x25
created by main.(*ui).readExpr
github.com/gokcehan/lf/ui.go:1169 +0x56
goroutine 68 [runnable]:
syscall.Syscall(0xd9, 0x3, 0xc000576000, 0x2000)
syscall/asm_linux_amd64.s:20 +0x5
syscall.Getdents(0xc000387af0?, {0xc000576000?, 0xc000387ac0?, 0x3?})
syscall/zsyscall_linux_amd64.go:439 +0x4d
syscall.ReadDirent(...)
syscall/syscall_linux.go:870
internal/poll.ignoringEINTRIO(...)
internal/poll/fd_unix.go:794
internal/poll.(*FD).ReadDirent(0x55f985ad5500?, {0xc000576000, 0x2000, 0x2000})
internal/poll/fd_unix.go:646 +0x1ca
os.(*File).readdir(0xc0003b2000, 0xffffffffffffffff?, 0x0)
os/dir_unix.go:70 +0x1f0
os.(*File).Readdirnames(0xc000017218?, 0x17?)
os/dir.go:70 +0x25
main.readdir({0xc000017218, 0x17})
github.com/gokcehan/lf/nav.go:56 +0x5e
main.newDir({0xc000017218, 0x17})
github.com/gokcehan/lf/nav.go:158 +0x5f
main.(*nav).checkDir.func1()
github.com/gokcehan/lf/nav.go:447 +0x37
created by main.(*nav).checkDir
github.com/gokcehan/lf/nav.go:446 +0x2d3
Are you able to replicate the issue? I tried but wasn't able to.
As you are only using Sxiv to select, I expect manually selecting many files would work the same. lf -remote "send toggle"
should also not be necessary, as just selecting the files would be enough for the delete.
What I tested:
- Open lf in directory
- Run script in separate terminal window
#!/bin/sh
i=0
while (( i++ < 1000 )); do
cp ../photo.png "photo-$i.png"
done
lf -remote "send glob-select *.png"
- Press D in lf, confirm and all files are successfully deleted
@Limero i suspect it might have been some kind of race condition thus difficult to replicate so perhaps @gokcehan can check if there is any possibility for something like that in the selection code(?)
It happened again, while deleting something normally but quickly (first few lines of output is the aforementioned custom interactive delete
cmd I use):
/home/fra/.steam
/home/fra/.pulse-cookie
/home/fra/.steampath
/home/fra/.steampid
delete?[y/N]y
fatal error: concurrent map iteration and map write
goroutine 13 [running]:
runtime.throw({0x557995c8422b?, 0x0?})
runtime/panic.go:992 +0x71 fp=0xc000103990 sp=0xc000103960 pc=0x557995b10011
runtime.mapiternext(0xc000103ae8?)
runtime/map.go:871 +0x4eb fp=0xc000103a00 sp=0xc000103990 pc=0x557995aeb68b
main.(*nav).currSelections(0xc000119860)
github.com/gokcehan/lf/nav.go:1694 +0x12a fp=0xc000103b58 sp=0xc000103a00 pc=0x557995c649aa
main.(*nav).exportFiles(0xc000119860)
github.com/gokcehan/lf/nav.go:597 +0x4e fp=0xc000103bb0 sp=0xc000103b58 pc=0x557995c5c80e
main.(*nav).preview(0xc000119860, {0xc0003900c0, 0x13}, 0xc000018ba0)
github.com/gokcehan/lf/nav.go:654 +0x165 fp=0xc000103f18 sp=0xc000103bb0 pc=0x557995c5cdc5
main.(*nav).previewLoop(0xc000119860, 0xc0001e69a0)
github.com/gokcehan/lf/nav.go:626 +0x1d9 fp=0xc000103fc0 sp=0xc000103f18 pc=0x557995c5ca59
main.(*app).loop.func2()
github.com/gokcehan/lf/app.go:239 +0x2a fp=0xc000103fe0 sp=0xc000103fc0 pc=0x557995c3e16a
runtime.goexit()
runtime/asm_amd64.s:1571 +0x1 fp=0xc000103fe8 sp=0xc000103fe0 pc=0x557995b40081
created by main.(*app).loop
github.com/gokcehan/lf/app.go:239 +0xaa
goroutine 1 [runnable]:
syscall.SetNonblock(0x3?, 0x1)
syscall/exec_unix.go:106 +0x87
os.newFile(0x3, {0x557995c7acfe, 0x8}, 0x1)
os/file_unix.go:181 +0x13e
os.openFileNolog({0x557995c7acfe, 0x8}, 0x2, 0x0)
os/file_unix.go:240 +0x170
os.OpenFile({0x557995c7acfe, 0x8}, 0x2, 0x18c37c40?)
os/file.go:338 +0x45
github.com/gdamore/tcell/v2.(*devTty).Start(0xc0000702d0)
github.com/gdamore/tcell/[email protected]/tty_unix.go:70 +0xac
github.com/gdamore/tcell/v2.(*tScreen).engage(0xc0001b8480)
github.com/gdamore/tcell/[email protected]/tscreen.go:1618 +0x105
github.com/gdamore/tcell/v2.(*tScreen).Resume(0x0?)
github.com/gdamore/tcell/[email protected]/tscreen.go:1597 +0x19
main.(*ui).resume(0xc0001e69a0)
github.com/gokcehan/lf/ui.go:1181 +0x30
main.(*app).runShell.func1()
github.com/gokcehan/lf/app.go:489 +0x25
main.(*app).runShell(0xc000142400, {0xc0000261e0, 0x93}, {0x0, 0x0, 0x0}, {0xc0002ec288, 0x1})
github.com/gokcehan/lf/app.go:575 +0x783
main.(*execExpr).eval(0xc0002c04c0, 0xc00007dcb0?, {0x0, 0x0, 0x0})
github.com/gokcehan/lf/eval.go:2079 +0x150
main.(*callExpr).eval(0xc0002aa750, 0xc000142400, {0xc000492400?, 0x0?, 0x0?})
github.com/gokcehan/lf/eval.go:1118 +0x3877
main.(*app).loop(0xc000142400)
github.com/gokcehan/lf/app.go:434 +0xa8f
main.run()
github.com/gokcehan/lf/client.go:62 +0x757
main.main()
github.com/gokcehan/lf/main.go:319 +0x7b9
goroutine 8 [syscall]:
os/signal.signal_recv()
runtime/sigqueue.go:151 +0x2f
os/signal.loop()
os/signal/signal_unix.go:23 +0x19
created by os/signal.Notify.func1.1
os/signal/signal.go:151 +0x2a
goroutine 11 [select]:
github.com/gdamore/tcell/v2.(*tScreen).PollEvent(0x0?)
github.com/gdamore/tcell/[email protected]/tscreen.go:928 +0x6a
main.(*ui).pollEvents(0xc0001e69a0)
github.com/gokcehan/lf/ui.go:562 +0x50
created by main.newUI
github.com/gokcehan/lf/ui.go:554 +0x34a
goroutine 12 [chan receive]:
main.newApp.func1()
github.com/gokcehan/lf/app.go:48 +0x35
created by main.newApp
github.com/gokcehan/lf/app.go:47 +0x1cd
goroutine 14 [IO wait]:
internal/poll.runtime_pollWait(0x7f0018c8ef88, 0x72)
runtime/netpoll.go:302 +0x89
internal/poll.(*pollDesc).wait(0xc0000a4080?, 0xc0003ce03a?, 0x0)
internal/poll/fd_poll_runtime.go:83 +0x32
internal/poll.(*pollDesc).waitRead(...)
internal/poll/fd_poll_runtime.go:88
internal/poll.(*FD).Read(0xc0000a4080, {0xc0003ce03a, 0xfc6, 0xfc6})
internal/poll/fd_unix.go:167 +0x25a
net.(*netFD).Read(0xc0000a4080, {0xc0003ce03a?, 0xc0003800c0?, 0xc000101df0?})
net/fd_posix.go:55 +0x29
net.(*conn).Read(0xc0000a8000, {0xc0003ce03a?, 0xc000101e80?, 0x557995ae153d?})
net/net.go:183 +0x45
bufio.(*Scanner).Scan(0xc000101f50)
bufio/scan.go:215 +0x865
main.readExpr.func1()
github.com/gokcehan/lf/client.go:86 +0x210
created by main.readExpr
github.com/gokcehan/lf/client.go:70 +0x6a
goroutine 15 [select]:
main.(*ui).pollEvent(0xc0001e69a0)
github.com/gokcehan/lf/ui.go:974 +0xab
main.(*ui).readExpr.func1()
github.com/gokcehan/lf/ui.go:1171 +0x25
created by main.(*ui).readExpr
github.com/gokcehan/lf/ui.go:1169 +0x56
goroutine 68 [runnable]:
syscall.Syscall6(0x101, 0xffffffffffffff9c, 0xc000364d10, 0x80000, 0x0, 0x0, 0x0)
syscall/asm_linux_amd64.s:43 +0x5
syscall.openat(0x0?, {0xc00001a1f4?, 0x0?}, 0x0?, 0x0?)
syscall/zsyscall_linux_amd64.go:68 +0x105
syscall.Open(...)
syscall/syscall_linux.go:155
os.openFileNolog({0xc00001a1f4, 0x9}, 0x0, 0x0)
os/file_unix.go:216 +0x9b
os.OpenFile({0xc00001a1f4, 0x9}, 0x0, 0x0?)
os/file.go:338 +0x45
os.Open(...)
os/file.go:318
main.readdir({0xc00001a1f4, 0x9})
github.com/gokcehan/lf/nav.go:52 +0x45
main.newDir({0xc00001a1f4, 0x9})
github.com/gokcehan/lf/nav.go:158 +0x5f
main.(*nav).checkDir.func1()
github.com/gokcehan/lf/nav.go:447 +0x37
created by main.(*nav).checkDir
github.com/gokcehan/lf/nav.go:446 +0x2d3
I also have this issue. In fact, my backtrace looks essentially the same as BachoSeven's, i.e. lf crashes at nav.go:1694 because of a concurrent map write and iteration. I also have a delete script in my lfrc that deletes the selected files. It doesn't always crash lf, but it does so randomly with multiple selected files.
Haven't experienced this crashes in more than a year, closing. I assume it has been fixed during various refactors, possibly related to #792