purego: fix darwin int string mixing (#357)
Add test case that verifies multiple string arguments passed on the stack each receive their correct distinct values, rather than all receiving the same duplicated value. This test catches the bug fixed in the previous commit where v.String() was incorrectly used instead of val.String(). Closes #356
- commit
- 1bb446066e99572ba46bf3db0a3cfe2bb3cda976
- author
- Travis Cline · · 2025-10-29 14:44 UTC
- committer
- GitHub · · 2025-10-29 14:44 UTC
- parent
- 4956991
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
3 files · +17 -1
M func.go +1 -1
| @@ -287,7 +287,7 @@ func RegisterFunc(fptr any, cfn uintptr) { | |||
| 287 | 287 | ||
| 288 | 288 | for j, val := range args[i:] { | |
| 289 | 289 | if val.Kind() == reflect.String { | |
| 290 | - | ptr := strings.CString(v.String()) | |
| 290 | + | ptr := strings.CString(val.String()) | |
| 291 | 291 | keepAlive = append(keepAlive, ptr) | |
| 292 | 292 | val = reflect.ValueOf(ptr) | |
| 293 | 293 | args[i+j] = val | |
| @@ -287,7 +287,7 @@ func RegisterFunc(fptr any, cfn uintptr) { | |||||
| 287 | 287 | ||||
| 288 | for j, val := range args[i:] { | 288 | for j, val := range args[i:] { | ||
| 289 | if val.Kind() == reflect.String { | 289 | if val.Kind() == reflect.String { | ||
| 290 | - | ptr := strings.CString(v.String()) | 290 | + | ptr := strings.CString(val.String()) |
| 291 | keepAlive = append(keepAlive, ptr) | 291 | keepAlive = append(keepAlive, ptr) | ||
| 292 | val = reflect.ValueOf(ptr) | 292 | val = reflect.ValueOf(ptr) | ||
| 293 | args[i+j] = val | 293 | args[i+j] = val | ||
M func_test.go +12 -0
| @@ -185,6 +185,18 @@ func TestABI(t *testing.T) { | |||
| 185 | 185 | t.Fatalf("%s: got %d, want %d", cName, res, expect) | |
| 186 | 186 | } | |
| 187 | 187 | } | |
| 188 | + | { | |
| 189 | + | const cName = "stack_8i32_3strings" | |
| 190 | + | var fn func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, string, string, string) | |
| 191 | + | purego.RegisterLibFunc(&fn, lib, cName) | |
| 192 | + | buf := make([]byte, 256) | |
| 193 | + | fn(&buf[0], uintptr(len(buf)), 1, 2, 3, 4, 5, 6, 7, 8, "foo", "bar", "baz") | |
| 194 | + | res := string(buf[:strings.IndexByte(string(buf), 0)]) | |
| 195 | + | const want = "1:2:3:4:5:6:7:8:foo:bar:baz" | |
| 196 | + | if res != want { | |
| 197 | + | t.Fatalf("%s: got %q, want %q", cName, res, want) | |
| 198 | + | } | |
| 199 | + | } | |
| 188 | 200 | } | |
| 189 | 201 | ||
| 190 | 202 | func buildSharedLib(compilerEnv, libFile string, sources ...string) error { | |
| @@ -185,6 +185,18 @@ func TestABI(t *testing.T) { | |||||
| 185 | t.Fatalf("%s: got %d, want %d", cName, res, expect) | 185 | t.Fatalf("%s: got %d, want %d", cName, res, expect) | ||
| 186 | } | 186 | } | ||
| 187 | } | 187 | } | ||
| 188 | + | { | |||
| 189 | + | const cName = "stack_8i32_3strings" | |||
| 190 | + | var fn func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, string, string, string) | |||
| 191 | + | purego.RegisterLibFunc(&fn, lib, cName) | |||
| 192 | + | buf := make([]byte, 256) | |||
| 193 | + | fn(&buf[0], uintptr(len(buf)), 1, 2, 3, 4, 5, 6, 7, 8, "foo", "bar", "baz") | |||
| 194 | + | res := string(buf[:strings.IndexByte(string(buf), 0)]) | |||
| 195 | + | const want = "1:2:3:4:5:6:7:8:foo:bar:baz" | |||
| 196 | + | if res != want { | |||
| 197 | + | t.Fatalf("%s: got %q, want %q", cName, res, want) | |||
| 198 | + | } | |||
| 199 | + | } | |||
| 188 | } | 200 | } | ||
| 189 | 201 | ||||
| 190 | func buildSharedLib(compilerEnv, libFile string, sources ...string) error { | 202 | func buildSharedLib(compilerEnv, libFile string, sources ...string) error { | ||
M testdata/abitest/abi_test.c +4 -0
| @@ -25,3 +25,7 @@ uint32_t stack_string(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e | |||
| 25 | 25 | assert(strcmp(i, "test") == 0); | |
| 26 | 26 | return a | b | c | d | e | f | g | h; | |
| 27 | 27 | } | |
| 28 | + | ||
| 29 | + | void stack_8i32_3strings(char* result, size_t size, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, const char* s1, const char* s2, const char* s3) { | |
| 30 | + | snprintf(result, size, "%d:%d:%d:%d:%d:%d:%d:%d:%s:%s:%s", a1, a2, a3, a4, a5, a6, a7, a8, s1, s2, s3); | |
| 31 | + | } | |
| @@ -25,3 +25,7 @@ uint32_t stack_string(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e | |||||
| 25 | assert(strcmp(i, "test") == 0); | 25 | assert(strcmp(i, "test") == 0); | ||
| 26 | return a | b | c | d | e | f | g | h; | 26 | return a | b | c | d | e | f | g | h; | ||
| 27 | } | 27 | } | ||
| 28 | + | ||||
| 29 | + | void stack_8i32_3strings(char* result, size_t size, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, const char* s1, const char* s2, const char* s3) { | |||
| 30 | + | snprintf(result, size, "%d:%d:%d:%d:%d:%d:%d:%d:%s:%s:%s", a1, a2, a3, a4, a5, a6, a7, a8, s1, s2, s3); | |||
| 31 | + | } | |||