purego: fix bool field placement at non-zero offsets (#351)
Bool fields were incorrectly placed at bit 0 regardless of their offset within the struct. This caused incorrect marshalling when bool fields appeared after other fields. The fix properly shifts the bool value by the current bit offset, ensuring it's placed at the correct position in the packed struct data. Adds regression test with FloatAndBool struct to verify the fix. Closes #350
- commit
- 4956991301fb70ba13d96683f8eb140a66286b97
- author
- Travis Cline · · 2025-10-27 03:33 UTC
- committer
- GitHub · · 2025-10-27 03:33 UTC
- parent
- 4ad96f6
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
5 files · +26 -3
M struct_amd64.go +1 -1
| @@ -165,7 +165,7 @@ func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintp | |||
| 165 | 165 | place(f) | |
| 166 | 166 | case reflect.Bool: | |
| 167 | 167 | if f.Bool() { | |
| 168 | - | val |= 1 | |
| 168 | + | val |= 1 << shift | |
| 169 | 169 | } | |
| 170 | 170 | shift += 8 | |
| 171 | 171 | class |= _INTEGER | |
| @@ -165,7 +165,7 @@ func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintp | |||||
| 165 | place(f) | 165 | place(f) | ||
| 166 | case reflect.Bool: | 166 | case reflect.Bool: | ||
| 167 | if f.Bool() { | 167 | if f.Bool() { | ||
| 168 | - | val |= 1 | 168 | + | val |= 1 << shift |
| 169 | } | 169 | } | ||
| 170 | shift += 8 | 170 | shift += 8 | ||
| 171 | class |= _INTEGER | 171 | class |= _INTEGER | ||
M struct_arm64.go +1 -1
| @@ -123,7 +123,7 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr | |||
| 123 | 123 | place(f) | |
| 124 | 124 | case reflect.Bool: | |
| 125 | 125 | if f.Bool() { | |
| 126 | - | val |= 1 | |
| 126 | + | val |= 1 << shift | |
| 127 | 127 | } | |
| 128 | 128 | shift += 8 | |
| 129 | 129 | class |= _INT | |
| @@ -123,7 +123,7 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr | |||||
| 123 | place(f) | 123 | place(f) | ||
| 124 | case reflect.Bool: | 124 | case reflect.Bool: | ||
| 125 | if f.Bool() { | 125 | if f.Bool() { | ||
| 126 | - | val |= 1 | 126 | + | val |= 1 << shift |
| 127 | } | 127 | } | ||
| 128 | shift += 8 | 128 | shift += 8 | ||
| 129 | class |= _INT | 129 | class |= _INT | ||
M struct_loong64.go +1 -1
| @@ -104,7 +104,7 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr | |||
| 104 | 104 | place(f) | |
| 105 | 105 | case reflect.Bool: | |
| 106 | 106 | if f.Bool() { | |
| 107 | - | val |= 1 | |
| 107 | + | val |= 1 << shift | |
| 108 | 108 | } | |
| 109 | 109 | shift += 8 | |
| 110 | 110 | class |= _INT | |
| @@ -104,7 +104,7 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr | |||||
| 104 | place(f) | 104 | place(f) | ||
| 105 | case reflect.Bool: | 105 | case reflect.Bool: | ||
| 106 | if f.Bool() { | 106 | if f.Bool() { | ||
| 107 | - | val |= 1 | 107 | + | val |= 1 << shift |
| 108 | } | 108 | } | ||
| 109 | shift += 8 | 109 | shift += 8 | ||
| 110 | class |= _INT | 110 | class |= _INT | ||
M struct_test.go +14 -0
| @@ -472,6 +472,20 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 472 | 472 | t.Fatalf("TakeGoUintAndReturn returned %+v wanted %+v", ret, expected) | |
| 473 | 473 | } | |
| 474 | 474 | } | |
| 475 | + | { | |
| 476 | + | type FloatAndBool struct { | |
| 477 | + | x float32 | |
| 478 | + | y bool | |
| 479 | + | } | |
| 480 | + | var FloatAndBoolFn func(FloatAndBool) int32 | |
| 481 | + | purego.RegisterLibFunc(&FloatAndBoolFn, lib, "FloatAndBool") | |
| 482 | + | if ret := FloatAndBoolFn(FloatAndBool{x: 12345.0, y: true}); ret != 1 { | |
| 483 | + | t.Fatalf("FloatAndBool(y: true) = %d, want 1", ret) | |
| 484 | + | } | |
| 485 | + | if ret := FloatAndBoolFn(FloatAndBool{x: 12345.0, y: false}); ret != 0 { | |
| 486 | + | t.Fatalf("FloatAndBool(y: false) = %d, want 0", ret) | |
| 487 | + | } | |
| 488 | + | } | |
| 475 | 489 | } | |
| 476 | 490 | ||
| 477 | 491 | func TestRegisterFunc_structReturns(t *testing.T) { | |
| @@ -472,6 +472,20 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||||
| 472 | t.Fatalf("TakeGoUintAndReturn returned %+v wanted %+v", ret, expected) | 472 | t.Fatalf("TakeGoUintAndReturn returned %+v wanted %+v", ret, expected) | ||
| 473 | } | 473 | } | ||
| 474 | } | 474 | } | ||
| 475 | + | { | |||
| 476 | + | type FloatAndBool struct { | |||
| 477 | + | x float32 | |||
| 478 | + | y bool | |||
| 479 | + | } | |||
| 480 | + | var FloatAndBoolFn func(FloatAndBool) int32 | |||
| 481 | + | purego.RegisterLibFunc(&FloatAndBoolFn, lib, "FloatAndBool") | |||
| 482 | + | if ret := FloatAndBoolFn(FloatAndBool{x: 12345.0, y: true}); ret != 1 { | |||
| 483 | + | t.Fatalf("FloatAndBool(y: true) = %d, want 1", ret) | |||
| 484 | + | } | |||
| 485 | + | if ret := FloatAndBoolFn(FloatAndBool{x: 12345.0, y: false}); ret != 0 { | |||
| 486 | + | t.Fatalf("FloatAndBool(y: false) = %d, want 0", ret) | |||
| 487 | + | } | |||
| 488 | + | } | |||
| 475 | } | 489 | } | ||
| 476 | 490 | ||||
| 477 | func TestRegisterFunc_structReturns(t *testing.T) { | 491 | func TestRegisterFunc_structReturns(t *testing.T) { | ||
M testdata/structtest/struct_test.c +9 -0
| @@ -352,3 +352,12 @@ GoUint GoUint4(struct GoUint4 g) { | |||
| 352 | 352 | GoUint TakeGoUintAndReturn(GoUint a) { | |
| 353 | 353 | return a; | |
| 354 | 354 | } | |
| 355 | + | ||
| 356 | + | struct FloatAndBool { | |
| 357 | + | float value; | |
| 358 | + | _Bool has_value; | |
| 359 | + | }; | |
| 360 | + | ||
| 361 | + | int FloatAndBool(struct FloatAndBool f) { | |
| 362 | + | return f.has_value; | |
| 363 | + | } | |
| @@ -352,3 +352,12 @@ GoUint GoUint4(struct GoUint4 g) { | |||||
| 352 | GoUint TakeGoUintAndReturn(GoUint a) { | 352 | GoUint TakeGoUintAndReturn(GoUint a) { | ||
| 353 | return a; | 353 | return a; | ||
| 354 | } | 354 | } | ||
| 355 | + | ||||
| 356 | + | struct FloatAndBool { | |||
| 357 | + | float value; | |||
| 358 | + | _Bool has_value; | |||
| 359 | + | }; | |||
| 360 | + | ||||
| 361 | + | int FloatAndBool(struct FloatAndBool f) { | |||
| 362 | + | return f.has_value; | |||
| 363 | + | } | |||