fix(core): recover from purego panics during function registration
PuregoSafeRegister now recovers from panics thrown by purego.RegisterFunc (e.g. 'too many stack arguments' for functions with >15 params like g_spawn_async_with_pipes_and_fds). The function pointer stays nil and will panic only if actually called, rather than crashing at init time.
- commit
- 07c3f738f24e08e5622c8db24ffe129792386a85
- author
- brice · · 2026-03-19 18:26 UTC
- committer
- brice · · 2026-03-19 18:28 UTC
- parent
- 53c483e
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +10 -2
M internal/core/core.go +10 -2
| @@ -20,13 +20,21 @@ func PuregoSafeRegister(fptr interface{}, libs []uintptr, name string) { | |||
| 20 | 20 | for _, lib := range libs { | |
| 21 | 21 | sym, err := purego.Dlsym(lib, name) | |
| 22 | 22 | if err == nil { | |
| 23 | - | purego.RegisterFunc(fptr, sym) | |
| 24 | - | ||
| 23 | + | registerFuncSafe(fptr, sym) | |
| 25 | 24 | return | |
| 26 | 25 | } | |
| 27 | 26 | } | |
| 28 | 27 | } | |
| 29 | 28 | ||
| 29 | + | // registerFuncSafe wraps purego.RegisterFunc with panic recovery for | |
| 30 | + | // functions whose signatures exceed upstream purego limits (e.g. "too | |
| 31 | + | // many stack arguments"). The function pointer stays nil and will | |
| 32 | + | // panic only if actually called. | |
| 33 | + | func registerFuncSafe(fptr interface{}, sym uintptr) { | |
| 34 | + | defer func() { recover() }() | |
| 35 | + | purego.RegisterFunc(fptr, sym) | |
| 36 | + | } | |
| 37 | + | ||
| 30 | 38 | // paths to where the shared object files should be located | |
| 31 | 39 | // this is unique per architecture | |
| 32 | 40 | // Debian/Ubuntu has it split into specific arch folder, Fedora is just /usr/lib64 | |
| @@ -20,13 +20,21 @@ func PuregoSafeRegister(fptr interface{}, libs []uintptr, name string) { | |||||
| 20 | for _, lib := range libs { | 20 | for _, lib := range libs { | ||
| 21 | sym, err := purego.Dlsym(lib, name) | 21 | sym, err := purego.Dlsym(lib, name) | ||
| 22 | if err == nil { | 22 | if err == nil { | ||
| 23 | - | purego.RegisterFunc(fptr, sym) | 23 | + | registerFuncSafe(fptr, sym) |
| 24 | - | ||||
| 25 | return | 24 | return | ||
| 26 | } | 25 | } | ||
| 27 | } | 26 | } | ||
| 28 | } | 27 | } | ||
| 29 | 28 | ||||
| 29 | + | // registerFuncSafe wraps purego.RegisterFunc with panic recovery for | |||
| 30 | + | // functions whose signatures exceed upstream purego limits (e.g. "too | |||
| 31 | + | // many stack arguments"). The function pointer stays nil and will | |||
| 32 | + | // panic only if actually called. | |||
| 33 | + | func registerFuncSafe(fptr interface{}, sym uintptr) { | |||
| 34 | + | defer func() { recover() }() | |||
| 35 | + | purego.RegisterFunc(fptr, sym) | |||
| 36 | + | } | |||
| 37 | + | ||||
| 30 | // paths to where the shared object files should be located | 38 | // paths to where the shared object files should be located | ||
| 31 | // this is unique per architecture | 39 | // this is unique per architecture | ||
| 32 | // Debian/Ubuntu has it split into specific arch folder, Fedora is just /usr/lib64 | 40 | // Debian/Ubuntu has it split into specific arch folder, Fedora is just /usr/lib64 | ||