detached c0b0a8f

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 VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · 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 {
5757 // Pointers are uintptr to avoid GC passing Go pointers to native code unexpectedly.
5858 var Functions = []struct{ Name, Signature string }{
5959 {"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"},
6161 {"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"},
6363 {"xkb_state_new", "func(uintptr) uintptr"}, {"xkb_state_ref", "func(uintptr) uintptr"}, {"xkb_state_unref", "func(uintptr)"},
6464 {"xkb_state_update_mask", "func(uintptr,uint32,uint32,uint32,uint32,uint32,uint32) uint32"},
6565 {"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)"},
7070 {"xkb_compose_state_new", "func(uintptr,uint32) uintptr"}, {"xkb_compose_state_ref", "func(uintptr) uintptr"}, {"xkb_compose_state_unref", "func(uintptr)"},
7171 {"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"},
7373 }
7474
7575 func field(name string) string { return strings.ToUpper(name[:1]) + name[1:] }
7676
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+
7784 // method renders an exported, allocation-free wrapper calling the resolved
7885 // address through purego.Syscall6 (up to 6 arguments) or Syscall15.
7986 func method(name, sig string) (string, error) {
@@ -92,9 +99,17 @@ func method(name, sig string) (string, error) {
9299 if len(types) > 15 {
93100 return "", fmt.Errorf("%s: more than 15 arguments", name)
94101 }
102+ if !allowedReturns[ret] {
103+ return "", fmt.Errorf("%s: unsupported return type %q", name, ret)
104+ }
95105 var decl, args []string
96106 for i, t := range types {
107+ if !allowedParams[t] {
108+ return "", fmt.Errorf("%s: unsupported parameter type %q", name, t)
109+ }
97110 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.
98113 if t == "uintptr" {
99114 args = append(args, fmt.Sprintf("a%d", i+1))
100115 } else {
@@ -132,9 +147,9 @@ func Generate(root string) error {
132147 }
133148 hdr := string(h1) + "\n" + string(h2)
134149 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")
136151 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")
138153 b.WriteString("const (\n" + constants(hdr))
139154 for _, f := range []string{"xkbcommon-keysyms.h", "xkbcommon-names.h"} {
140155 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 resolved84 // 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 []string105 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.Builder149 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) {
2323 }
2424 }
2525 }
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 @@
11 // Code generated by go generate; DO NOT EDIT.
22 package raw
33
4-import "github.com/bnema/purego"
4+import (
5+ "unsafe"
6+
7+ "github.com/bnema/purego"
8+)
59
610 // Opaque C handles and scalar typedefs.
711 type Context uintptr
@@ -16,8 +20,9 @@ type ModIndex uint32
1620 type ModMask uint32
1721 type LayoutMask uint32
1822
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 }
2126
2227 const (
2328 XKB_RMLVO_BUILDER_NO_FLAGS = 0
@@ -2863,20 +2868,20 @@ func (f *Funcs) Xkb_context_unref(a1 uintptr) {
28632868 }
28642869
28652870 // 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)
28682873 return r
28692874 }
28702875
28712876 // 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)
28742879 return r
28752880 }
28762881
28772882 // 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)
28802885 return r
28812886 }
28822887
@@ -2898,8 +2903,8 @@ func (f *Funcs) Xkb_keymap_get_as_string(a1 uintptr, a2 uint32) uintptr {
28982903 }
28992904
29002905 // 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)
29032908 return uint32(r)
29042909 }
29052910
@@ -2951,8 +2956,8 @@ func (f *Funcs) Xkb_state_serialize_mods(a1 uintptr, a2 uint32) uint32 {
29512956 }
29522957
29532958 // 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)
29562961 return int32(r)
29572962 }
29582963
@@ -2969,26 +2974,26 @@ func (f *Funcs) Xkb_state_key_get_one_sym(a1 uintptr, a2 uint32) uint32 {
29692974 }
29702975
29712976 // 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)
29742979 return int32(r)
29752980 }
29762981
29772982 // 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)
29802985 return int32(r)
29812986 }
29822987
29832988 // 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)
29862991 return uint32(r)
29872992 }
29882993
29892994 // 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)
29922997 return r
29932998 }
29942999
@@ -3038,8 +3043,8 @@ func (f *Funcs) Xkb_compose_state_reset(a1 uintptr) {
30383043 }
30393044
30403045 // 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)
30433048 return int32(r)
30443049 }
30453050
@@ -1,7 +1,11 @@
1 // Code generated by go generate; DO NOT EDIT.1 // Code generated by go generate; DO NOT EDIT.
2 package raw2 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 uintptr11 type Context uintptr
@@ -16,8 +20,9 @@ type ModIndex uint32
16 type ModMask uint3220 type ModMask uint32
17 type LayoutMask uint3221 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 = 028 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 r2873 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 r2879 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 r2885 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 r2997 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

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 2

↑↓ moveenter openesc close