fix: address CodeRabbit findings — []string keepAlive + needsKeepAlive analysis
- Add reflect.Slice to needsKeepAlive check ([]string args need keepAlive) - Keep individual CString allocations in keepAlive (prevent GC during C call) - Fix variadic detection: use loop var v instead of args[i]
- commit
- a02394b1b2afe4553a50f6ed58d590b413491b3a
- author
- brice · · 2026-03-23 09:51 UTC
- parent
- d2ade5c
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +9 -6
M func.go +9 -6
| @@ -224,11 +224,12 @@ func RegisterFunc(fptr any, cfn uintptr) { | |||
| 224 | 224 | // and variadic []any args (unknown types at registration time). | |
| 225 | 225 | needsKeepAlive := false | |
| 226 | 226 | for i := 0; i < ty.NumIn(); i++ { | |
| 227 | - | switch ty.In(i).Kind() { | |
| 228 | - | case reflect.String, reflect.Struct, reflect.Array: | |
| 227 | + | inKind := ty.In(i).Kind() | |
| 228 | + | switch inKind { | |
| 229 | + | case reflect.String, reflect.Struct, reflect.Array, reflect.Slice: | |
| 230 | + | // Slice covers []string (CString allocs) and variadic ...any ([]any) | |
| 229 | 231 | needsKeepAlive = true | |
| 230 | 232 | case reflect.Interface: | |
| 231 | - | // variadic []any — could contain anything | |
| 232 | 233 | needsKeepAlive = true | |
| 233 | 234 | } | |
| 234 | 235 | } | |
| @@ -312,7 +313,7 @@ func RegisterFunc(fptr any, cfn uintptr) { | |||
| 312 | 313 | } | |
| 313 | 314 | } | |
| 314 | 315 | for i, v := range args { | |
| 315 | - | if variadic, ok := xreflect.TypeAssert[[]any](args[i]); ok { | |
| 316 | + | if variadic, ok := xreflect.TypeAssert[[]any](v); ok { | |
| 316 | 317 | if i != len(args)-1 { | |
| 317 | 318 | panic("purego: can only expand last parameter") | |
| 318 | 319 | } | |
| @@ -342,7 +343,7 @@ func RegisterFunc(fptr any, cfn uintptr) { | |||
| 342 | 343 | defer runtime.KeepAlive(args) | |
| 343 | 344 | ||
| 344 | 345 | for i, v := range args { | |
| 345 | - | if variadic, ok := xreflect.TypeAssert[[]any](args[i]); ok { | |
| 346 | + | if variadic, ok := xreflect.TypeAssert[[]any](v); ok { | |
| 346 | 347 | if i != len(args)-1 { | |
| 347 | 348 | panic("purego: can only expand last parameter") | |
| 348 | 349 | } | |
| @@ -516,7 +517,9 @@ func addValue(v reflect.Value, keepAlive []any, addInt func(x uintptr), addFloat | |||
| 516 | 517 | } else { | |
| 517 | 518 | res := make([]*byte, len(ss)+1) | |
| 518 | 519 | for i, s := range ss { | |
| 519 | - | res[i] = strings.CString(s) | |
| 520 | + | ptr := strings.CString(s) | |
| 521 | + | keepAlive = append(keepAlive, ptr) | |
| 522 | + | res[i] = ptr | |
| 520 | 523 | } | |
| 521 | 524 | // NULL-terminated for C | |
| 522 | 525 | res[len(ss)] = nil | |
| @@ -224,11 +224,12 @@ func RegisterFunc(fptr any, cfn uintptr) { | |||||
| 224 | // and variadic []any args (unknown types at registration time). | 224 | // and variadic []any args (unknown types at registration time). | ||
| 225 | needsKeepAlive := false | 225 | needsKeepAlive := false | ||
| 226 | for i := 0; i < ty.NumIn(); i++ { | 226 | for i := 0; i < ty.NumIn(); i++ { | ||
| 227 | - | switch ty.In(i).Kind() { | 227 | + | inKind := ty.In(i).Kind() |
| 228 | - | case reflect.String, reflect.Struct, reflect.Array: | 228 | + | switch inKind { |
| 229 | + | case reflect.String, reflect.Struct, reflect.Array, reflect.Slice: | |||
| 230 | + | // Slice covers []string (CString allocs) and variadic ...any ([]any) | |||
| 229 | needsKeepAlive = true | 231 | needsKeepAlive = true | ||
| 230 | case reflect.Interface: | 232 | case reflect.Interface: | ||
| 231 | - | // variadic []any — could contain anything | |||
| 232 | needsKeepAlive = true | 233 | needsKeepAlive = true | ||
| 233 | } | 234 | } | ||
| 234 | } | 235 | } | ||
| @@ -312,7 +313,7 @@ func RegisterFunc(fptr any, cfn uintptr) { | |||||
| 312 | } | 313 | } | ||
| 313 | } | 314 | } | ||
| 314 | for i, v := range args { | 315 | for i, v := range args { | ||
| 315 | - | if variadic, ok := xreflect.TypeAssert[[]any](args[i]); ok { | 316 | + | if variadic, ok := xreflect.TypeAssert[[]any](v); ok { |
| 316 | if i != len(args)-1 { | 317 | if i != len(args)-1 { | ||
| 317 | panic("purego: can only expand last parameter") | 318 | panic("purego: can only expand last parameter") | ||
| 318 | } | 319 | } | ||
| @@ -342,7 +343,7 @@ func RegisterFunc(fptr any, cfn uintptr) { | |||||
| 342 | defer runtime.KeepAlive(args) | 343 | defer runtime.KeepAlive(args) | ||
| 343 | 344 | ||||
| 344 | for i, v := range args { | 345 | for i, v := range args { | ||
| 345 | - | if variadic, ok := xreflect.TypeAssert[[]any](args[i]); ok { | 346 | + | if variadic, ok := xreflect.TypeAssert[[]any](v); ok { |
| 346 | if i != len(args)-1 { | 347 | if i != len(args)-1 { | ||
| 347 | panic("purego: can only expand last parameter") | 348 | panic("purego: can only expand last parameter") | ||
| 348 | } | 349 | } | ||
| @@ -516,7 +517,9 @@ func addValue(v reflect.Value, keepAlive []any, addInt func(x uintptr), addFloat | |||||
| 516 | } else { | 517 | } else { | ||
| 517 | res := make([]*byte, len(ss)+1) | 518 | res := make([]*byte, len(ss)+1) | ||
| 518 | for i, s := range ss { | 519 | for i, s := range ss { | ||
| 519 | - | res[i] = strings.CString(s) | 520 | + | ptr := strings.CString(s) |
| 521 | + | keepAlive = append(keepAlive, ptr) | |||
| 522 | + | res[i] = ptr | |||
| 520 | } | 523 | } | ||
| 521 | // NULL-terminated for C | 524 | // NULL-terminated for C | ||
| 522 | res[len(ss)] = nil | 525 | res[len(ss)] = nil | ||