fix(raw): keep Go pointers alive across fixed-arity calls
Pointer parameters of generated Funcs methods are now unsafe.Pointer and converted to uintptr inside the Syscall call expression, so go:uintptrescapes pins them. RuleNames fields are unsafe.Pointer. The generator whitelists uintptr/uint32/int32/unsafe.Pointer and rejects floats, bools and varargs.
- commit
- c0b0a8ff2d7af7b8bb826d9e28a1620225264c3e
- author
- brice · · 2026-10-01 18:50 UTC
- parent
- e01c311
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
3 files · +72 -32
M internal/gen/gen.go +24 -9
| @@ -57,23 +57,30 @@ func constants(h string) string { | |||
| 57 | 57 | // Pointers are uintptr to avoid GC passing Go pointers to native code unexpectedly. | |
| 58 | 58 | var Functions = []struct{ Name, Signature string }{ | |
| 59 | 59 | {"xkb_context_new", "func(uint32) uintptr"}, {"xkb_context_ref", "func(uintptr) uintptr"}, {"xkb_context_unref", "func(uintptr)"}, | |
| 60 | - | {"xkb_keymap_new_from_names", "func(uintptr, uintptr, uint32) uintptr"}, {"xkb_keymap_new_from_string", "func(uintptr, uintptr, uint32, uint32) uintptr"}, {"xkb_keymap_new_from_buffer", "func(uintptr, uintptr, uintptr, uint32, uint32) uintptr"}, | |
| 60 | + | {"xkb_keymap_new_from_names", "func(uintptr, unsafe.Pointer, uint32) uintptr"}, {"xkb_keymap_new_from_string", "func(uintptr, unsafe.Pointer, uint32, uint32) uintptr"}, {"xkb_keymap_new_from_buffer", "func(uintptr, unsafe.Pointer, uintptr, uint32, uint32) uintptr"}, | |
| 61 | 61 | {"xkb_keymap_ref", "func(uintptr) uintptr"}, {"xkb_keymap_unref", "func(uintptr)"}, {"xkb_keymap_get_as_string", "func(uintptr,uint32) uintptr"}, | |
| 62 | - | {"xkb_keymap_mod_get_index", "func(uintptr,uintptr) uint32"}, {"xkb_keymap_key_repeats", "func(uintptr,uint32) int32"}, {"xkb_keymap_num_layouts", "func(uintptr) uint32"}, | |
| 62 | + | {"xkb_keymap_mod_get_index", "func(uintptr,unsafe.Pointer) uint32"}, {"xkb_keymap_key_repeats", "func(uintptr,uint32) int32"}, {"xkb_keymap_num_layouts", "func(uintptr) uint32"}, | |
| 63 | 63 | {"xkb_state_new", "func(uintptr) uintptr"}, {"xkb_state_ref", "func(uintptr) uintptr"}, {"xkb_state_unref", "func(uintptr)"}, | |
| 64 | 64 | {"xkb_state_update_mask", "func(uintptr,uint32,uint32,uint32,uint32,uint32,uint32) uint32"}, | |
| 65 | 65 | {"xkb_state_serialize_layout", "func(uintptr,uint32) uint32"}, {"xkb_state_serialize_mods", "func(uintptr,uint32) uint32"}, | |
| 66 | - | {"xkb_state_mod_name_is_active", "func(uintptr,uintptr,uint32) int32"}, {"xkb_state_mod_index_is_active", "func(uintptr,uint32,uint32) int32"}, | |
| 67 | - | {"xkb_state_key_get_one_sym", "func(uintptr,uint32) uint32"}, {"xkb_state_key_get_utf8", "func(uintptr,uint32,uintptr,uintptr) int32"}, | |
| 68 | - | {"xkb_keysym_get_name", "func(uint32,uintptr,uintptr) int32"}, {"xkb_keysym_from_name", "func(uintptr,uint32) uint32"}, | |
| 69 | - | {"xkb_compose_table_new_from_locale", "func(uintptr,uintptr,uint32) uintptr"}, {"xkb_compose_table_ref", "func(uintptr) uintptr"}, {"xkb_compose_table_unref", "func(uintptr)"}, | |
| 66 | + | {"xkb_state_mod_name_is_active", "func(uintptr,unsafe.Pointer,uint32) int32"}, {"xkb_state_mod_index_is_active", "func(uintptr,uint32,uint32) int32"}, | |
| 67 | + | {"xkb_state_key_get_one_sym", "func(uintptr,uint32) uint32"}, {"xkb_state_key_get_utf8", "func(uintptr,uint32,unsafe.Pointer,uintptr) int32"}, | |
| 68 | + | {"xkb_keysym_get_name", "func(uint32,unsafe.Pointer,uintptr) int32"}, {"xkb_keysym_from_name", "func(unsafe.Pointer,uint32) uint32"}, | |
| 69 | + | {"xkb_compose_table_new_from_locale", "func(uintptr,unsafe.Pointer,uint32) uintptr"}, {"xkb_compose_table_ref", "func(uintptr) uintptr"}, {"xkb_compose_table_unref", "func(uintptr)"}, | |
| 70 | 70 | {"xkb_compose_state_new", "func(uintptr,uint32) uintptr"}, {"xkb_compose_state_ref", "func(uintptr) uintptr"}, {"xkb_compose_state_unref", "func(uintptr)"}, | |
| 71 | 71 | {"xkb_compose_state_feed", "func(uintptr,uint32) uint32"}, {"xkb_compose_state_get_status", "func(uintptr) uint32"}, | |
| 72 | - | {"xkb_compose_state_reset", "func(uintptr)"}, {"xkb_compose_state_get_utf8", "func(uintptr,uintptr,uintptr) int32"}, {"xkb_compose_state_get_one_sym", "func(uintptr) uint32"}, | |
| 72 | + | {"xkb_compose_state_reset", "func(uintptr)"}, {"xkb_compose_state_get_utf8", "func(uintptr,unsafe.Pointer,uintptr) int32"}, {"xkb_compose_state_get_one_sym", "func(uintptr) uint32"}, | |
| 73 | 73 | } | |
| 74 | 74 | ||
| 75 | 75 | func field(name string) string { return strings.ToUpper(name[:1]) + name[1:] } | |
| 76 | 76 | ||
| 77 | + | // Only fixed-width integer-class values reach Syscall6/Syscall15: floats, bools, | |
| 78 | + | // varargs and structs would be silently mis-passed, so the generator rejects them. | |
| 79 | + | // unsafe.Pointer is accepted for parameters only (Go memory handed to C); | |
| 80 | + | // uintptr is for C-owned handles and sizes. | |
| 81 | + | var allowedParams = map[string]bool{"uintptr": true, "uint32": true, "int32": true, "unsafe.Pointer": true} | |
| 82 | + | var allowedReturns = map[string]bool{"": true, "uintptr": true, "uint32": true, "int32": true} | |
| 83 | + | ||
| 77 | 84 | // method renders an exported, allocation-free wrapper calling the resolved | |
| 78 | 85 | // address through purego.Syscall6 (up to 6 arguments) or Syscall15. | |
| 79 | 86 | func method(name, sig string) (string, error) { | |
| @@ -92,9 +99,17 @@ func method(name, sig string) (string, error) { | |||
| 92 | 99 | if len(types) > 15 { | |
| 93 | 100 | return "", fmt.Errorf("%s: more than 15 arguments", name) | |
| 94 | 101 | } | |
| 102 | + | if !allowedReturns[ret] { | |
| 103 | + | return "", fmt.Errorf("%s: unsupported return type %q", name, ret) | |
| 104 | + | } | |
| 95 | 105 | var decl, args []string | |
| 96 | 106 | for i, t := range types { | |
| 107 | + | if !allowedParams[t] { | |
| 108 | + | return "", fmt.Errorf("%s: unsupported parameter type %q", name, t) | |
| 109 | + | } | |
| 97 | 110 | decl = append(decl, fmt.Sprintf("a%d %s", i+1, t)) | |
| 111 | + | // The uintptr conversion must stay inside the Syscall call expression so | |
| 112 | + | // //go:uintptrescapes keeps unsafe.Pointer arguments alive and unmoved. | |
| 98 | 113 | if t == "uintptr" { | |
| 99 | 114 | args = append(args, fmt.Sprintf("a%d", i+1)) | |
| 100 | 115 | } else { | |
| @@ -132,9 +147,9 @@ func Generate(root string) error { | |||
| 132 | 147 | } | |
| 133 | 148 | hdr := string(h1) + "\n" + string(h2) | |
| 134 | 149 | var b strings.Builder | |
| 135 | - | b.WriteString("// Code generated by go generate; DO NOT EDIT.\npackage raw\n\nimport \"github.com/bnema/purego\"\n\n") | |
| 150 | + | b.WriteString("// Code generated by go generate; DO NOT EDIT.\npackage raw\n\nimport (\n\"unsafe\"\n\n\"github.com/bnema/purego\"\n)\n\n") | |
| 136 | 151 | b.WriteString("// Opaque C handles and scalar typedefs.\ntype Context uintptr\ntype Keymap uintptr\ntype State uintptr\ntype ComposeTable uintptr\ntype ComposeState uintptr\ntype Keycode uint32\ntype Keysym uint32\ntype LayoutIndex uint32\ntype ModIndex uint32\ntype ModMask uint32\ntype LayoutMask uint32\n") | |
| 137 | - | b.WriteString("// RuleNames matches struct xkb_rule_names (five const char pointers).\ntype RuleNames struct { Rules, Model, Layout, Variant, Options uintptr }\n") | |
| 152 | + | b.WriteString("// RuleNames matches struct xkb_rule_names (five const char pointers). The\n// fields are unsafe.Pointer so the GC sees the NUL-terminated strings they reference.\ntype RuleNames struct { Rules, Model, Layout, Variant, Options unsafe.Pointer }\n") | |
| 138 | 153 | b.WriteString("const (\n" + constants(hdr)) | |
| 139 | 154 | for _, f := range []string{"xkbcommon-keysyms.h", "xkbcommon-names.h"} { | |
| 140 | 155 | data, e := os.ReadFile(root + "/upstream/" + f) | |
| @@ -57,23 +57,30 @@ func constants(h string) string { | |||||
| 57 | // Pointers are uintptr to avoid GC passing Go pointers to native code unexpectedly. | 57 | // Pointers are uintptr to avoid GC passing Go pointers to native code unexpectedly. | ||
| 58 | var Functions = []struct{ Name, Signature string }{ | 58 | var Functions = []struct{ Name, Signature string }{ | ||
| 59 | {"xkb_context_new", "func(uint32) uintptr"}, {"xkb_context_ref", "func(uintptr) uintptr"}, {"xkb_context_unref", "func(uintptr)"}, | 59 | {"xkb_context_new", "func(uint32) uintptr"}, {"xkb_context_ref", "func(uintptr) uintptr"}, {"xkb_context_unref", "func(uintptr)"}, | ||
| 60 | - | {"xkb_keymap_new_from_names", "func(uintptr, uintptr, uint32) uintptr"}, {"xkb_keymap_new_from_string", "func(uintptr, uintptr, uint32, uint32) uintptr"}, {"xkb_keymap_new_from_buffer", "func(uintptr, uintptr, uintptr, uint32, uint32) uintptr"}, | 60 | + | {"xkb_keymap_new_from_names", "func(uintptr, unsafe.Pointer, uint32) uintptr"}, {"xkb_keymap_new_from_string", "func(uintptr, unsafe.Pointer, uint32, uint32) uintptr"}, {"xkb_keymap_new_from_buffer", "func(uintptr, unsafe.Pointer, uintptr, uint32, uint32) uintptr"}, |
| 61 | {"xkb_keymap_ref", "func(uintptr) uintptr"}, {"xkb_keymap_unref", "func(uintptr)"}, {"xkb_keymap_get_as_string", "func(uintptr,uint32) uintptr"}, | 61 | {"xkb_keymap_ref", "func(uintptr) uintptr"}, {"xkb_keymap_unref", "func(uintptr)"}, {"xkb_keymap_get_as_string", "func(uintptr,uint32) uintptr"}, | ||
| 62 | - | {"xkb_keymap_mod_get_index", "func(uintptr,uintptr) uint32"}, {"xkb_keymap_key_repeats", "func(uintptr,uint32) int32"}, {"xkb_keymap_num_layouts", "func(uintptr) uint32"}, | 62 | + | {"xkb_keymap_mod_get_index", "func(uintptr,unsafe.Pointer) uint32"}, {"xkb_keymap_key_repeats", "func(uintptr,uint32) int32"}, {"xkb_keymap_num_layouts", "func(uintptr) uint32"}, |
| 63 | {"xkb_state_new", "func(uintptr) uintptr"}, {"xkb_state_ref", "func(uintptr) uintptr"}, {"xkb_state_unref", "func(uintptr)"}, | 63 | {"xkb_state_new", "func(uintptr) uintptr"}, {"xkb_state_ref", "func(uintptr) uintptr"}, {"xkb_state_unref", "func(uintptr)"}, | ||
| 64 | {"xkb_state_update_mask", "func(uintptr,uint32,uint32,uint32,uint32,uint32,uint32) uint32"}, | 64 | {"xkb_state_update_mask", "func(uintptr,uint32,uint32,uint32,uint32,uint32,uint32) uint32"}, | ||
| 65 | {"xkb_state_serialize_layout", "func(uintptr,uint32) uint32"}, {"xkb_state_serialize_mods", "func(uintptr,uint32) uint32"}, | 65 | {"xkb_state_serialize_layout", "func(uintptr,uint32) uint32"}, {"xkb_state_serialize_mods", "func(uintptr,uint32) uint32"}, | ||
| 66 | - | {"xkb_state_mod_name_is_active", "func(uintptr,uintptr,uint32) int32"}, {"xkb_state_mod_index_is_active", "func(uintptr,uint32,uint32) int32"}, | 66 | + | {"xkb_state_mod_name_is_active", "func(uintptr,unsafe.Pointer,uint32) int32"}, {"xkb_state_mod_index_is_active", "func(uintptr,uint32,uint32) int32"}, |
| 67 | - | {"xkb_state_key_get_one_sym", "func(uintptr,uint32) uint32"}, {"xkb_state_key_get_utf8", "func(uintptr,uint32,uintptr,uintptr) int32"}, | 67 | + | {"xkb_state_key_get_one_sym", "func(uintptr,uint32) uint32"}, {"xkb_state_key_get_utf8", "func(uintptr,uint32,unsafe.Pointer,uintptr) int32"}, |
| 68 | - | {"xkb_keysym_get_name", "func(uint32,uintptr,uintptr) int32"}, {"xkb_keysym_from_name", "func(uintptr,uint32) uint32"}, | 68 | + | {"xkb_keysym_get_name", "func(uint32,unsafe.Pointer,uintptr) int32"}, {"xkb_keysym_from_name", "func(unsafe.Pointer,uint32) uint32"}, |
| 69 | - | {"xkb_compose_table_new_from_locale", "func(uintptr,uintptr,uint32) uintptr"}, {"xkb_compose_table_ref", "func(uintptr) uintptr"}, {"xkb_compose_table_unref", "func(uintptr)"}, | 69 | + | {"xkb_compose_table_new_from_locale", "func(uintptr,unsafe.Pointer,uint32) uintptr"}, {"xkb_compose_table_ref", "func(uintptr) uintptr"}, {"xkb_compose_table_unref", "func(uintptr)"}, |
| 70 | {"xkb_compose_state_new", "func(uintptr,uint32) uintptr"}, {"xkb_compose_state_ref", "func(uintptr) uintptr"}, {"xkb_compose_state_unref", "func(uintptr)"}, | 70 | {"xkb_compose_state_new", "func(uintptr,uint32) uintptr"}, {"xkb_compose_state_ref", "func(uintptr) uintptr"}, {"xkb_compose_state_unref", "func(uintptr)"}, | ||
| 71 | {"xkb_compose_state_feed", "func(uintptr,uint32) uint32"}, {"xkb_compose_state_get_status", "func(uintptr) uint32"}, | 71 | {"xkb_compose_state_feed", "func(uintptr,uint32) uint32"}, {"xkb_compose_state_get_status", "func(uintptr) uint32"}, | ||
| 72 | - | {"xkb_compose_state_reset", "func(uintptr)"}, {"xkb_compose_state_get_utf8", "func(uintptr,uintptr,uintptr) int32"}, {"xkb_compose_state_get_one_sym", "func(uintptr) uint32"}, | 72 | + | {"xkb_compose_state_reset", "func(uintptr)"}, {"xkb_compose_state_get_utf8", "func(uintptr,unsafe.Pointer,uintptr) int32"}, {"xkb_compose_state_get_one_sym", "func(uintptr) uint32"}, |
| 73 | } | 73 | } | ||
| 74 | 74 | ||||
| 75 | func field(name string) string { return strings.ToUpper(name[:1]) + name[1:] } | 75 | func field(name string) string { return strings.ToUpper(name[:1]) + name[1:] } | ||
| 76 | 76 | ||||
| 77 | + | // Only fixed-width integer-class values reach Syscall6/Syscall15: floats, bools, | |||
| 78 | + | // varargs and structs would be silently mis-passed, so the generator rejects them. | |||
| 79 | + | // unsafe.Pointer is accepted for parameters only (Go memory handed to C); | |||
| 80 | + | // uintptr is for C-owned handles and sizes. | |||
| 81 | + | var allowedParams = map[string]bool{"uintptr": true, "uint32": true, "int32": true, "unsafe.Pointer": true} | |||
| 82 | + | var allowedReturns = map[string]bool{"": true, "uintptr": true, "uint32": true, "int32": true} | |||
| 83 | + | ||||
| 77 | // method renders an exported, allocation-free wrapper calling the resolved | 84 | // method renders an exported, allocation-free wrapper calling the resolved | ||
| 78 | // address through purego.Syscall6 (up to 6 arguments) or Syscall15. | 85 | // address through purego.Syscall6 (up to 6 arguments) or Syscall15. | ||
| 79 | func method(name, sig string) (string, error) { | 86 | func method(name, sig string) (string, error) { | ||
| @@ -92,9 +99,17 @@ func method(name, sig string) (string, error) { | |||||
| 92 | if len(types) > 15 { | 99 | if len(types) > 15 { | ||
| 93 | return "", fmt.Errorf("%s: more than 15 arguments", name) | 100 | return "", fmt.Errorf("%s: more than 15 arguments", name) | ||
| 94 | } | 101 | } | ||
| 102 | + | if !allowedReturns[ret] { | |||
| 103 | + | return "", fmt.Errorf("%s: unsupported return type %q", name, ret) | |||
| 104 | + | } | |||
| 95 | var decl, args []string | 105 | var decl, args []string | ||
| 96 | for i, t := range types { | 106 | for i, t := range types { | ||
| 107 | + | if !allowedParams[t] { | |||
| 108 | + | return "", fmt.Errorf("%s: unsupported parameter type %q", name, t) | |||
| 109 | + | } | |||
| 97 | decl = append(decl, fmt.Sprintf("a%d %s", i+1, t)) | 110 | decl = append(decl, fmt.Sprintf("a%d %s", i+1, t)) | ||
| 111 | + | // The uintptr conversion must stay inside the Syscall call expression so | |||
| 112 | + | // //go:uintptrescapes keeps unsafe.Pointer arguments alive and unmoved. | |||
| 98 | if t == "uintptr" { | 113 | if t == "uintptr" { | ||
| 99 | args = append(args, fmt.Sprintf("a%d", i+1)) | 114 | args = append(args, fmt.Sprintf("a%d", i+1)) | ||
| 100 | } else { | 115 | } else { | ||
| @@ -132,9 +147,9 @@ func Generate(root string) error { | |||||
| 132 | } | 147 | } | ||
| 133 | hdr := string(h1) + "\n" + string(h2) | 148 | hdr := string(h1) + "\n" + string(h2) | ||
| 134 | var b strings.Builder | 149 | var b strings.Builder | ||
| 135 | - | b.WriteString("// Code generated by go generate; DO NOT EDIT.\npackage raw\n\nimport \"github.com/bnema/purego\"\n\n") | 150 | + | b.WriteString("// Code generated by go generate; DO NOT EDIT.\npackage raw\n\nimport (\n\"unsafe\"\n\n\"github.com/bnema/purego\"\n)\n\n") |
| 136 | b.WriteString("// Opaque C handles and scalar typedefs.\ntype Context uintptr\ntype Keymap uintptr\ntype State uintptr\ntype ComposeTable uintptr\ntype ComposeState uintptr\ntype Keycode uint32\ntype Keysym uint32\ntype LayoutIndex uint32\ntype ModIndex uint32\ntype ModMask uint32\ntype LayoutMask uint32\n") | 151 | b.WriteString("// Opaque C handles and scalar typedefs.\ntype Context uintptr\ntype Keymap uintptr\ntype State uintptr\ntype ComposeTable uintptr\ntype ComposeState uintptr\ntype Keycode uint32\ntype Keysym uint32\ntype LayoutIndex uint32\ntype ModIndex uint32\ntype ModMask uint32\ntype LayoutMask uint32\n") | ||
| 137 | - | b.WriteString("// RuleNames matches struct xkb_rule_names (five const char pointers).\ntype RuleNames struct { Rules, Model, Layout, Variant, Options uintptr }\n") | 152 | + | b.WriteString("// RuleNames matches struct xkb_rule_names (five const char pointers). The\n// fields are unsafe.Pointer so the GC sees the NUL-terminated strings they reference.\ntype RuleNames struct { Rules, Model, Layout, Variant, Options unsafe.Pointer }\n") |
| 138 | b.WriteString("const (\n" + constants(hdr)) | 153 | b.WriteString("const (\n" + constants(hdr)) | ||
| 139 | for _, f := range []string{"xkbcommon-keysyms.h", "xkbcommon-names.h"} { | 154 | for _, f := range []string{"xkbcommon-keysyms.h", "xkbcommon-names.h"} { | ||
| 140 | data, e := os.ReadFile(root + "/upstream/" + f) | 155 | data, e := os.ReadFile(root + "/upstream/" + f) | ||
M internal/gen/gen_test.go +20 -0
| @@ -23,3 +23,23 @@ func TestConstants(t *testing.T) { | |||
| 23 | 23 | } | |
| 24 | 24 | } | |
| 25 | 25 | } | |
| 26 | + | ||
| 27 | + | func TestMethodWhitelist(t *testing.T) { | |
| 28 | + | for _, sig := range []string{"func(float64) uint32", "func(bool)", "func(uintptr, ...uintptr) uint32", "func(uint32) float32", "func(uint32) unsafe.Pointer", "func(*int)", "func(uint32) bool"} { | |
| 29 | + | if _, err := method("xkb_bad", sig); err == nil { | |
| 30 | + | t.Fatalf("accepted %s", sig) | |
| 31 | + | } | |
| 32 | + | } | |
| 33 | + | got, err := method("xkb_ok", "func(uintptr, unsafe.Pointer, int32) uint32") | |
| 34 | + | if err != nil { | |
| 35 | + | t.Fatal(err) | |
| 36 | + | } | |
| 37 | + | for _, want := range []string{"purego.Syscall6(f.xkb_ok, a1, uintptr(a2), uintptr(a3), 0, 0, 0)", "return uint32(r)", "a2 unsafe.Pointer"} { | |
| 38 | + | if !strings.Contains(got, want) { | |
| 39 | + | t.Fatalf("missing %q in %s", want, got) | |
| 40 | + | } | |
| 41 | + | } | |
| 42 | + | if got, _ = method("xkb_seven", "func(uintptr,uint32,uint32,uint32,uint32,uint32,uint32)"); !strings.Contains(got, "purego.Syscall15(") { | |
| 43 | + | t.Fatal("seven args must use Syscall15") | |
| 44 | + | } | |
| 45 | + | } | |
| @@ -23,3 +23,23 @@ func TestConstants(t *testing.T) { | |||||
| 23 | } | 23 | } | ||
| 24 | } | 24 | } | ||
| 25 | } | 25 | } | ||
| 26 | + | ||||
| 27 | + | func TestMethodWhitelist(t *testing.T) { | |||
| 28 | + | for _, sig := range []string{"func(float64) uint32", "func(bool)", "func(uintptr, ...uintptr) uint32", "func(uint32) float32", "func(uint32) unsafe.Pointer", "func(*int)", "func(uint32) bool"} { | |||
| 29 | + | if _, err := method("xkb_bad", sig); err == nil { | |||
| 30 | + | t.Fatalf("accepted %s", sig) | |||
| 31 | + | } | |||
| 32 | + | } | |||
| 33 | + | got, err := method("xkb_ok", "func(uintptr, unsafe.Pointer, int32) uint32") | |||
| 34 | + | if err != nil { | |||
| 35 | + | t.Fatal(err) | |||
| 36 | + | } | |||
| 37 | + | for _, want := range []string{"purego.Syscall6(f.xkb_ok, a1, uintptr(a2), uintptr(a3), 0, 0, 0)", "return uint32(r)", "a2 unsafe.Pointer"} { | |||
| 38 | + | if !strings.Contains(got, want) { | |||
| 39 | + | t.Fatalf("missing %q in %s", want, got) | |||
| 40 | + | } | |||
| 41 | + | } | |||
| 42 | + | if got, _ = method("xkb_seven", "func(uintptr,uint32,uint32,uint32,uint32,uint32,uint32)"); !strings.Contains(got, "purego.Syscall15(") { | |||
| 43 | + | t.Fatal("seven args must use Syscall15") | |||
| 44 | + | } | |||
| 45 | + | } | |||
M raw/generated.go +28 -23
| @@ -1,7 +1,11 @@ | |||
| 1 | 1 | // Code generated by go generate; DO NOT EDIT. | |
| 2 | 2 | package raw | |
| 3 | 3 | ||
| 4 | - | import "github.com/bnema/purego" | |
| 4 | + | import ( | |
| 5 | + | "unsafe" | |
| 6 | + | ||
| 7 | + | "github.com/bnema/purego" | |
| 8 | + | ) | |
| 5 | 9 | ||
| 6 | 10 | // Opaque C handles and scalar typedefs. | |
| 7 | 11 | type Context uintptr | |
| @@ -16,8 +20,9 @@ type ModIndex uint32 | |||
| 16 | 20 | type ModMask uint32 | |
| 17 | 21 | type LayoutMask uint32 | |
| 18 | 22 | ||
| 19 | - | // RuleNames matches struct xkb_rule_names (five const char pointers). | |
| 20 | - | type RuleNames struct{ Rules, Model, Layout, Variant, Options uintptr } | |
| 23 | + | // RuleNames matches struct xkb_rule_names (five const char pointers). The | |
| 24 | + | // fields are unsafe.Pointer so the GC sees the NUL-terminated strings they reference. | |
| 25 | + | type RuleNames struct{ Rules, Model, Layout, Variant, Options unsafe.Pointer } | |
| 21 | 26 | ||
| 22 | 27 | const ( | |
| 23 | 28 | XKB_RMLVO_BUILDER_NO_FLAGS = 0 | |
| @@ -2863,20 +2868,20 @@ func (f *Funcs) Xkb_context_unref(a1 uintptr) { | |||
| 2863 | 2868 | } | |
| 2864 | 2869 | ||
| 2865 | 2870 | // Xkb_keymap_new_from_names calls xkb_keymap_new_from_names without allocating. | |
| 2866 | - | func (f *Funcs) Xkb_keymap_new_from_names(a1 uintptr, a2 uintptr, a3 uint32) uintptr { | |
| 2867 | - | r, _, _ := purego.Syscall6(f.xkb_keymap_new_from_names, a1, a2, uintptr(a3), 0, 0, 0) | |
| 2871 | + | func (f *Funcs) Xkb_keymap_new_from_names(a1 uintptr, a2 unsafe.Pointer, a3 uint32) uintptr { | |
| 2872 | + | r, _, _ := purego.Syscall6(f.xkb_keymap_new_from_names, a1, uintptr(a2), uintptr(a3), 0, 0, 0) | |
| 2868 | 2873 | return r | |
| 2869 | 2874 | } | |
| 2870 | 2875 | ||
| 2871 | 2876 | // Xkb_keymap_new_from_string calls xkb_keymap_new_from_string without allocating. | |
| 2872 | - | func (f *Funcs) Xkb_keymap_new_from_string(a1 uintptr, a2 uintptr, a3 uint32, a4 uint32) uintptr { | |
| 2873 | - | r, _, _ := purego.Syscall6(f.xkb_keymap_new_from_string, a1, a2, uintptr(a3), uintptr(a4), 0, 0) | |
| 2877 | + | func (f *Funcs) Xkb_keymap_new_from_string(a1 uintptr, a2 unsafe.Pointer, a3 uint32, a4 uint32) uintptr { | |
| 2878 | + | r, _, _ := purego.Syscall6(f.xkb_keymap_new_from_string, a1, uintptr(a2), uintptr(a3), uintptr(a4), 0, 0) | |
| 2874 | 2879 | return r | |
| 2875 | 2880 | } | |
| 2876 | 2881 | ||
| 2877 | 2882 | // Xkb_keymap_new_from_buffer calls xkb_keymap_new_from_buffer without allocating. | |
| 2878 | - | func (f *Funcs) Xkb_keymap_new_from_buffer(a1 uintptr, a2 uintptr, a3 uintptr, a4 uint32, a5 uint32) uintptr { | |
| 2879 | - | r, _, _ := purego.Syscall6(f.xkb_keymap_new_from_buffer, a1, a2, a3, uintptr(a4), uintptr(a5), 0) | |
| 2883 | + | func (f *Funcs) Xkb_keymap_new_from_buffer(a1 uintptr, a2 unsafe.Pointer, a3 uintptr, a4 uint32, a5 uint32) uintptr { | |
| 2884 | + | r, _, _ := purego.Syscall6(f.xkb_keymap_new_from_buffer, a1, uintptr(a2), a3, uintptr(a4), uintptr(a5), 0) | |
| 2880 | 2885 | return r | |
| 2881 | 2886 | } | |
| 2882 | 2887 | ||
| @@ -2898,8 +2903,8 @@ func (f *Funcs) Xkb_keymap_get_as_string(a1 uintptr, a2 uint32) uintptr { | |||
| 2898 | 2903 | } | |
| 2899 | 2904 | ||
| 2900 | 2905 | // Xkb_keymap_mod_get_index calls xkb_keymap_mod_get_index without allocating. | |
| 2901 | - | func (f *Funcs) Xkb_keymap_mod_get_index(a1 uintptr, a2 uintptr) uint32 { | |
| 2902 | - | r, _, _ := purego.Syscall6(f.xkb_keymap_mod_get_index, a1, a2, 0, 0, 0, 0) | |
| 2906 | + | func (f *Funcs) Xkb_keymap_mod_get_index(a1 uintptr, a2 unsafe.Pointer) uint32 { | |
| 2907 | + | r, _, _ := purego.Syscall6(f.xkb_keymap_mod_get_index, a1, uintptr(a2), 0, 0, 0, 0) | |
| 2903 | 2908 | return uint32(r) | |
| 2904 | 2909 | } | |
| 2905 | 2910 | ||
| @@ -2951,8 +2956,8 @@ func (f *Funcs) Xkb_state_serialize_mods(a1 uintptr, a2 uint32) uint32 { | |||
| 2951 | 2956 | } | |
| 2952 | 2957 | ||
| 2953 | 2958 | // Xkb_state_mod_name_is_active calls xkb_state_mod_name_is_active without allocating. | |
| 2954 | - | func (f *Funcs) Xkb_state_mod_name_is_active(a1 uintptr, a2 uintptr, a3 uint32) int32 { | |
| 2955 | - | r, _, _ := purego.Syscall6(f.xkb_state_mod_name_is_active, a1, a2, uintptr(a3), 0, 0, 0) | |
| 2959 | + | func (f *Funcs) Xkb_state_mod_name_is_active(a1 uintptr, a2 unsafe.Pointer, a3 uint32) int32 { | |
| 2960 | + | r, _, _ := purego.Syscall6(f.xkb_state_mod_name_is_active, a1, uintptr(a2), uintptr(a3), 0, 0, 0) | |
| 2956 | 2961 | return int32(r) | |
| 2957 | 2962 | } | |
| 2958 | 2963 | ||
| @@ -2969,26 +2974,26 @@ func (f *Funcs) Xkb_state_key_get_one_sym(a1 uintptr, a2 uint32) uint32 { | |||
| 2969 | 2974 | } | |
| 2970 | 2975 | ||
| 2971 | 2976 | // Xkb_state_key_get_utf8 calls xkb_state_key_get_utf8 without allocating. | |
| 2972 | - | func (f *Funcs) Xkb_state_key_get_utf8(a1 uintptr, a2 uint32, a3 uintptr, a4 uintptr) int32 { | |
| 2973 | - | r, _, _ := purego.Syscall6(f.xkb_state_key_get_utf8, a1, uintptr(a2), a3, a4, 0, 0) | |
| 2977 | + | func (f *Funcs) Xkb_state_key_get_utf8(a1 uintptr, a2 uint32, a3 unsafe.Pointer, a4 uintptr) int32 { | |
| 2978 | + | r, _, _ := purego.Syscall6(f.xkb_state_key_get_utf8, a1, uintptr(a2), uintptr(a3), a4, 0, 0) | |
| 2974 | 2979 | return int32(r) | |
| 2975 | 2980 | } | |
| 2976 | 2981 | ||
| 2977 | 2982 | // Xkb_keysym_get_name calls xkb_keysym_get_name without allocating. | |
| 2978 | - | func (f *Funcs) Xkb_keysym_get_name(a1 uint32, a2 uintptr, a3 uintptr) int32 { | |
| 2979 | - | r, _, _ := purego.Syscall6(f.xkb_keysym_get_name, uintptr(a1), a2, a3, 0, 0, 0) | |
| 2983 | + | func (f *Funcs) Xkb_keysym_get_name(a1 uint32, a2 unsafe.Pointer, a3 uintptr) int32 { | |
| 2984 | + | r, _, _ := purego.Syscall6(f.xkb_keysym_get_name, uintptr(a1), uintptr(a2), a3, 0, 0, 0) | |
| 2980 | 2985 | return int32(r) | |
| 2981 | 2986 | } | |
| 2982 | 2987 | ||
| 2983 | 2988 | // Xkb_keysym_from_name calls xkb_keysym_from_name without allocating. | |
| 2984 | - | func (f *Funcs) Xkb_keysym_from_name(a1 uintptr, a2 uint32) uint32 { | |
| 2985 | - | r, _, _ := purego.Syscall6(f.xkb_keysym_from_name, a1, uintptr(a2), 0, 0, 0, 0) | |
| 2989 | + | func (f *Funcs) Xkb_keysym_from_name(a1 unsafe.Pointer, a2 uint32) uint32 { | |
| 2990 | + | r, _, _ := purego.Syscall6(f.xkb_keysym_from_name, uintptr(a1), uintptr(a2), 0, 0, 0, 0) | |
| 2986 | 2991 | return uint32(r) | |
| 2987 | 2992 | } | |
| 2988 | 2993 | ||
| 2989 | 2994 | // Xkb_compose_table_new_from_locale calls xkb_compose_table_new_from_locale without allocating. | |
| 2990 | - | func (f *Funcs) Xkb_compose_table_new_from_locale(a1 uintptr, a2 uintptr, a3 uint32) uintptr { | |
| 2991 | - | r, _, _ := purego.Syscall6(f.xkb_compose_table_new_from_locale, a1, a2, uintptr(a3), 0, 0, 0) | |
| 2995 | + | func (f *Funcs) Xkb_compose_table_new_from_locale(a1 uintptr, a2 unsafe.Pointer, a3 uint32) uintptr { | |
| 2996 | + | r, _, _ := purego.Syscall6(f.xkb_compose_table_new_from_locale, a1, uintptr(a2), uintptr(a3), 0, 0, 0) | |
| 2992 | 2997 | return r | |
| 2993 | 2998 | } | |
| 2994 | 2999 | ||
| @@ -3038,8 +3043,8 @@ func (f *Funcs) Xkb_compose_state_reset(a1 uintptr) { | |||
| 3038 | 3043 | } | |
| 3039 | 3044 | ||
| 3040 | 3045 | // Xkb_compose_state_get_utf8 calls xkb_compose_state_get_utf8 without allocating. | |
| 3041 | - | func (f *Funcs) Xkb_compose_state_get_utf8(a1 uintptr, a2 uintptr, a3 uintptr) int32 { | |
| 3042 | - | r, _, _ := purego.Syscall6(f.xkb_compose_state_get_utf8, a1, a2, a3, 0, 0, 0) | |
| 3046 | + | func (f *Funcs) Xkb_compose_state_get_utf8(a1 uintptr, a2 unsafe.Pointer, a3 uintptr) int32 { | |
| 3047 | + | r, _, _ := purego.Syscall6(f.xkb_compose_state_get_utf8, a1, uintptr(a2), a3, 0, 0, 0) | |
| 3043 | 3048 | return int32(r) | |
| 3044 | 3049 | } | |
| 3045 | 3050 | ||
| @@ -1,7 +1,11 @@ | |||||
| 1 | // Code generated by go generate; DO NOT EDIT. | 1 | // Code generated by go generate; DO NOT EDIT. | ||
| 2 | package raw | 2 | package raw | ||
| 3 | 3 | ||||
| 4 | - | import "github.com/bnema/purego" | 4 | + | import ( |
| 5 | + | "unsafe" | |||
| 6 | + | ||||
| 7 | + | "github.com/bnema/purego" | |||
| 8 | + | ) | |||
| 5 | 9 | ||||
| 6 | // Opaque C handles and scalar typedefs. | 10 | // Opaque C handles and scalar typedefs. | ||
| 7 | type Context uintptr | 11 | type Context uintptr | ||
| @@ -16,8 +20,9 @@ type ModIndex uint32 | |||||
| 16 | type ModMask uint32 | 20 | type ModMask uint32 | ||
| 17 | type LayoutMask uint32 | 21 | type LayoutMask uint32 | ||
| 18 | 22 | ||||
| 19 | - | // RuleNames matches struct xkb_rule_names (five const char pointers). | 23 | + | // RuleNames matches struct xkb_rule_names (five const char pointers). The |
| 20 | - | type RuleNames struct{ Rules, Model, Layout, Variant, Options uintptr } | 24 | + | // fields are unsafe.Pointer so the GC sees the NUL-terminated strings they reference. |
| 25 | + | type RuleNames struct{ Rules, Model, Layout, Variant, Options unsafe.Pointer } | |||
| 21 | 26 | ||||
| 22 | const ( | 27 | const ( | ||
| 23 | XKB_RMLVO_BUILDER_NO_FLAGS = 0 | 28 | XKB_RMLVO_BUILDER_NO_FLAGS = 0 | ||
| @@ -2863,20 +2868,20 @@ func (f *Funcs) Xkb_context_unref(a1 uintptr) { | |||||
| 2863 | } | 2868 | } | ||
| 2864 | 2869 | ||||
| 2865 | // Xkb_keymap_new_from_names calls xkb_keymap_new_from_names without allocating. | 2870 | // Xkb_keymap_new_from_names calls xkb_keymap_new_from_names without allocating. | ||
| 2866 | - | func (f *Funcs) Xkb_keymap_new_from_names(a1 uintptr, a2 uintptr, a3 uint32) uintptr { | 2871 | + | func (f *Funcs) Xkb_keymap_new_from_names(a1 uintptr, a2 unsafe.Pointer, a3 uint32) uintptr { |
| 2867 | - | r, _, _ := purego.Syscall6(f.xkb_keymap_new_from_names, a1, a2, uintptr(a3), 0, 0, 0) | 2872 | + | r, _, _ := purego.Syscall6(f.xkb_keymap_new_from_names, a1, uintptr(a2), uintptr(a3), 0, 0, 0) |
| 2868 | return r | 2873 | return r | ||
| 2869 | } | 2874 | } | ||
| 2870 | 2875 | ||||
| 2871 | // Xkb_keymap_new_from_string calls xkb_keymap_new_from_string without allocating. | 2876 | // Xkb_keymap_new_from_string calls xkb_keymap_new_from_string without allocating. | ||
| 2872 | - | func (f *Funcs) Xkb_keymap_new_from_string(a1 uintptr, a2 uintptr, a3 uint32, a4 uint32) uintptr { | 2877 | + | func (f *Funcs) Xkb_keymap_new_from_string(a1 uintptr, a2 unsafe.Pointer, a3 uint32, a4 uint32) uintptr { |
| 2873 | - | r, _, _ := purego.Syscall6(f.xkb_keymap_new_from_string, a1, a2, uintptr(a3), uintptr(a4), 0, 0) | 2878 | + | r, _, _ := purego.Syscall6(f.xkb_keymap_new_from_string, a1, uintptr(a2), uintptr(a3), uintptr(a4), 0, 0) |
| 2874 | return r | 2879 | return r | ||
| 2875 | } | 2880 | } | ||
| 2876 | 2881 | ||||
| 2877 | // Xkb_keymap_new_from_buffer calls xkb_keymap_new_from_buffer without allocating. | 2882 | // Xkb_keymap_new_from_buffer calls xkb_keymap_new_from_buffer without allocating. | ||
| 2878 | - | func (f *Funcs) Xkb_keymap_new_from_buffer(a1 uintptr, a2 uintptr, a3 uintptr, a4 uint32, a5 uint32) uintptr { | 2883 | + | func (f *Funcs) Xkb_keymap_new_from_buffer(a1 uintptr, a2 unsafe.Pointer, a3 uintptr, a4 uint32, a5 uint32) uintptr { |
| 2879 | - | r, _, _ := purego.Syscall6(f.xkb_keymap_new_from_buffer, a1, a2, a3, uintptr(a4), uintptr(a5), 0) | 2884 | + | r, _, _ := purego.Syscall6(f.xkb_keymap_new_from_buffer, a1, uintptr(a2), a3, uintptr(a4), uintptr(a5), 0) |
| 2880 | return r | 2885 | return r | ||
| 2881 | } | 2886 | } | ||
| 2882 | 2887 | ||||
| @@ -2898,8 +2903,8 @@ func (f *Funcs) Xkb_keymap_get_as_string(a1 uintptr, a2 uint32) uintptr { | |||||
| 2898 | } | 2903 | } | ||
| 2899 | 2904 | ||||
| 2900 | // Xkb_keymap_mod_get_index calls xkb_keymap_mod_get_index without allocating. | 2905 | // Xkb_keymap_mod_get_index calls xkb_keymap_mod_get_index without allocating. | ||
| 2901 | - | func (f *Funcs) Xkb_keymap_mod_get_index(a1 uintptr, a2 uintptr) uint32 { | 2906 | + | func (f *Funcs) Xkb_keymap_mod_get_index(a1 uintptr, a2 unsafe.Pointer) uint32 { |
| 2902 | - | r, _, _ := purego.Syscall6(f.xkb_keymap_mod_get_index, a1, a2, 0, 0, 0, 0) | 2907 | + | r, _, _ := purego.Syscall6(f.xkb_keymap_mod_get_index, a1, uintptr(a2), 0, 0, 0, 0) |
| 2903 | return uint32(r) | 2908 | return uint32(r) | ||
| 2904 | } | 2909 | } | ||
| 2905 | 2910 | ||||
| @@ -2951,8 +2956,8 @@ func (f *Funcs) Xkb_state_serialize_mods(a1 uintptr, a2 uint32) uint32 { | |||||
| 2951 | } | 2956 | } | ||
| 2952 | 2957 | ||||
| 2953 | // Xkb_state_mod_name_is_active calls xkb_state_mod_name_is_active without allocating. | 2958 | // Xkb_state_mod_name_is_active calls xkb_state_mod_name_is_active without allocating. | ||
| 2954 | - | func (f *Funcs) Xkb_state_mod_name_is_active(a1 uintptr, a2 uintptr, a3 uint32) int32 { | 2959 | + | func (f *Funcs) Xkb_state_mod_name_is_active(a1 uintptr, a2 unsafe.Pointer, a3 uint32) int32 { |
| 2955 | - | r, _, _ := purego.Syscall6(f.xkb_state_mod_name_is_active, a1, a2, uintptr(a3), 0, 0, 0) | 2960 | + | r, _, _ := purego.Syscall6(f.xkb_state_mod_name_is_active, a1, uintptr(a2), uintptr(a3), 0, 0, 0) |
| 2956 | return int32(r) | 2961 | return int32(r) | ||
| 2957 | } | 2962 | } | ||
| 2958 | 2963 | ||||
| @@ -2969,26 +2974,26 @@ func (f *Funcs) Xkb_state_key_get_one_sym(a1 uintptr, a2 uint32) uint32 { | |||||
| 2969 | } | 2974 | } | ||
| 2970 | 2975 | ||||
| 2971 | // Xkb_state_key_get_utf8 calls xkb_state_key_get_utf8 without allocating. | 2976 | // Xkb_state_key_get_utf8 calls xkb_state_key_get_utf8 without allocating. | ||
| 2972 | - | func (f *Funcs) Xkb_state_key_get_utf8(a1 uintptr, a2 uint32, a3 uintptr, a4 uintptr) int32 { | 2977 | + | func (f *Funcs) Xkb_state_key_get_utf8(a1 uintptr, a2 uint32, a3 unsafe.Pointer, a4 uintptr) int32 { |
| 2973 | - | r, _, _ := purego.Syscall6(f.xkb_state_key_get_utf8, a1, uintptr(a2), a3, a4, 0, 0) | 2978 | + | r, _, _ := purego.Syscall6(f.xkb_state_key_get_utf8, a1, uintptr(a2), uintptr(a3), a4, 0, 0) |
| 2974 | return int32(r) | 2979 | return int32(r) | ||
| 2975 | } | 2980 | } | ||
| 2976 | 2981 | ||||
| 2977 | // Xkb_keysym_get_name calls xkb_keysym_get_name without allocating. | 2982 | // Xkb_keysym_get_name calls xkb_keysym_get_name without allocating. | ||
| 2978 | - | func (f *Funcs) Xkb_keysym_get_name(a1 uint32, a2 uintptr, a3 uintptr) int32 { | 2983 | + | func (f *Funcs) Xkb_keysym_get_name(a1 uint32, a2 unsafe.Pointer, a3 uintptr) int32 { |
| 2979 | - | r, _, _ := purego.Syscall6(f.xkb_keysym_get_name, uintptr(a1), a2, a3, 0, 0, 0) | 2984 | + | r, _, _ := purego.Syscall6(f.xkb_keysym_get_name, uintptr(a1), uintptr(a2), a3, 0, 0, 0) |
| 2980 | return int32(r) | 2985 | return int32(r) | ||
| 2981 | } | 2986 | } | ||
| 2982 | 2987 | ||||
| 2983 | // Xkb_keysym_from_name calls xkb_keysym_from_name without allocating. | 2988 | // Xkb_keysym_from_name calls xkb_keysym_from_name without allocating. | ||
| 2984 | - | func (f *Funcs) Xkb_keysym_from_name(a1 uintptr, a2 uint32) uint32 { | 2989 | + | func (f *Funcs) Xkb_keysym_from_name(a1 unsafe.Pointer, a2 uint32) uint32 { |
| 2985 | - | r, _, _ := purego.Syscall6(f.xkb_keysym_from_name, a1, uintptr(a2), 0, 0, 0, 0) | 2990 | + | r, _, _ := purego.Syscall6(f.xkb_keysym_from_name, uintptr(a1), uintptr(a2), 0, 0, 0, 0) |
| 2986 | return uint32(r) | 2991 | return uint32(r) | ||
| 2987 | } | 2992 | } | ||
| 2988 | 2993 | ||||
| 2989 | // Xkb_compose_table_new_from_locale calls xkb_compose_table_new_from_locale without allocating. | 2994 | // Xkb_compose_table_new_from_locale calls xkb_compose_table_new_from_locale without allocating. | ||
| 2990 | - | func (f *Funcs) Xkb_compose_table_new_from_locale(a1 uintptr, a2 uintptr, a3 uint32) uintptr { | 2995 | + | func (f *Funcs) Xkb_compose_table_new_from_locale(a1 uintptr, a2 unsafe.Pointer, a3 uint32) uintptr { |
| 2991 | - | r, _, _ := purego.Syscall6(f.xkb_compose_table_new_from_locale, a1, a2, uintptr(a3), 0, 0, 0) | 2996 | + | r, _, _ := purego.Syscall6(f.xkb_compose_table_new_from_locale, a1, uintptr(a2), uintptr(a3), 0, 0, 0) |
| 2992 | return r | 2997 | return r | ||
| 2993 | } | 2998 | } | ||
| 2994 | 2999 | ||||
| @@ -3038,8 +3043,8 @@ func (f *Funcs) Xkb_compose_state_reset(a1 uintptr) { | |||||
| 3038 | } | 3043 | } | ||
| 3039 | 3044 | ||||
| 3040 | // Xkb_compose_state_get_utf8 calls xkb_compose_state_get_utf8 without allocating. | 3045 | // Xkb_compose_state_get_utf8 calls xkb_compose_state_get_utf8 without allocating. | ||
| 3041 | - | func (f *Funcs) Xkb_compose_state_get_utf8(a1 uintptr, a2 uintptr, a3 uintptr) int32 { | 3046 | + | func (f *Funcs) Xkb_compose_state_get_utf8(a1 uintptr, a2 unsafe.Pointer, a3 uintptr) int32 { |
| 3042 | - | r, _, _ := purego.Syscall6(f.xkb_compose_state_get_utf8, a1, a2, a3, 0, 0, 0) | 3047 | + | r, _, _ := purego.Syscall6(f.xkb_compose_state_get_utf8, a1, uintptr(a2), a3, 0, 0, 0) |
| 3043 | return int32(r) | 3048 | return int32(r) | ||
| 3044 | } | 3049 | } | ||
| 3045 | 3050 | ||||