fix: handle WASM runtime panics in gotaglib openFile function.

see #4977

Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Deluan
2026-02-03 22:56:47 -05:00
parent 0c8f2a559c
commit 4e720ee931
+16 -3
View File
@@ -13,12 +13,15 @@ package gotaglib
import ( import (
"errors" "errors"
"fmt"
"io" "io"
"io/fs" "io/fs"
"runtime/debug"
"strings" "strings"
"time" "time"
"github.com/navidrome/navidrome/core/storage/local" "github.com/navidrome/navidrome/core/storage/local"
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model/metadata" "github.com/navidrome/navidrome/model/metadata"
"go.senan.xyz/taglib" "go.senan.xyz/taglib"
) )
@@ -94,7 +97,17 @@ func (e extractor) extractMetadata(filePath string) (*metadata.Info, error) {
// openFile opens the file at filePath using the extractor's filesystem. // openFile opens the file at filePath using the extractor's filesystem.
// It returns a TagLib File handle and a cleanup function to close resources. // It returns a TagLib File handle and a cleanup function to close resources.
func (e extractor) openFile(filePath string) (*taglib.File, func(), error) { func (e extractor) openFile(filePath string) (f *taglib.File, closeFunc func(), err error) {
// Recover from panics in the WASM runtime (e.g., wazero failing to mmap executable memory
// on hardened systems like NixOS with MemoryDenyWriteExecute=true)
debug.SetPanicOnFault(true)
defer func() {
if r := recover(); r != nil {
log.Error("WASM runtime panic: This may be caused by a hardened system that blocks executable memory mapping.", "file", filePath, "panic", r)
err = fmt.Errorf("WASM runtime panic (hardened system?): %v", r)
}
}()
// Open the file from the filesystem // Open the file from the filesystem
file, err := e.fs.Open(filePath) file, err := e.fs.Open(filePath)
if err != nil { if err != nil {
@@ -105,12 +118,12 @@ func (e extractor) openFile(filePath string) (*taglib.File, func(), error) {
file.Close() file.Close()
return nil, nil, errors.New("file is not seekable") return nil, nil, errors.New("file is not seekable")
} }
f, err := taglib.OpenStream(rs, taglib.WithReadStyle(taglib.ReadStyleFast)) f, err = taglib.OpenStream(rs, taglib.WithReadStyle(taglib.ReadStyleFast))
if err != nil { if err != nil {
file.Close() file.Close()
return nil, nil, err return nil, nil, err
} }
closeFunc := func() { closeFunc = func() {
f.Close() f.Close()
file.Close() file.Close()
} }