lf icon indicating copy to clipboard operation
lf copied to clipboard

Crash on file deletion

Open BachoSeven opened this issue 2 years ago • 4 comments

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

BachoSeven avatar Aug 01 '22 12:08 BachoSeven

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:

  1. Open lf in directory
  2. 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"
  1. Press D in lf, confirm and all files are successfully deleted

Limero avatar Aug 06 '22 12:08 Limero

@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(?)

BachoSeven avatar Aug 11 '22 07:08 BachoSeven

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

BachoSeven avatar Aug 13 '22 18:08 BachoSeven

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.

Yaroslav-95 avatar Aug 20 '22 18:08 Yaroslav-95

Haven't experienced this crashes in more than a year, closing. I assume it has been fixed during various refactors, possibly related to #792

BachoSeven avatar Jan 07 '24 15:01 BachoSeven