Skip to content

Commit fdcfb35

Browse files
committed
fix: allow dlopen on statically-linked musl binaries
The isDynamicBinary() check prevents loadLibrary from attempting dlopen on statically-linked Linux binaries. This is correct for glibc, where dlopen from static binaries is undefined behavior and can crash, but overly conservative for musl libc, which has a fully functional dlopen implementation even in static binaries. Add an isMusl() check so that static binaries on musl-based systems (like Alpine Linux) can still load native libwebp via dlopen. On glibc systems the existing guard is preserved. This enables native libwebp loading in Alpine/Docker environments where Go+CGO+musl produces static binaries by default.
1 parent 3a7e672 commit fdcfb35

1 file changed

Lines changed: 27 additions & 1 deletion

File tree

‎purego_unix.go‎

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"os"
99
"runtime"
10+
"strings"
1011

1112
"github.com/ebitengine/purego"
1213
)
@@ -17,7 +18,7 @@ const (
1718
)
1819

1920
func loadLibrary(name string) (uintptr, error) {
20-
if runtime.GOOS == "linux" && !isDynamicBinary() {
21+
if runtime.GOOS == "linux" && !isDynamicBinary() && !isMusl() {
2122
return 0, fmt.Errorf("not a dynamic binary")
2223
}
2324

@@ -49,3 +50,28 @@ func isDynamicBinary() bool {
4950

5051
return false
5152
}
53+
54+
// isMusl returns true if the current process is linked against musl libc.
55+
// Musl supports dlopen from statically-linked binaries, unlike glibc.
56+
func isMusl() bool {
57+
maps, err := os.ReadFile("/proc/self/maps")
58+
if err == nil && strings.Contains(string(maps), "musl") {
59+
return true
60+
}
61+
62+
// For static binaries /proc/self/maps won't show musl.
63+
// Check if the musl dynamic linker exists on the system.
64+
for _, path := range []string{
65+
"/lib/ld-musl-aarch64.so.1",
66+
"/lib/ld-musl-x86_64.so.1",
67+
"/lib/ld-musl-armhf.so.1",
68+
"/lib/ld-musl-i386.so.1",
69+
"/lib/ld-musl-riscv64.so.1",
70+
} {
71+
if _, err := os.Stat(path); err == nil {
72+
return true
73+
}
74+
}
75+
76+
return false
77+
}

0 commit comments

Comments
 (0)