detached a7a7574

purego: support string arguments in Go callbacks from C

commit
a7a757496003828984098b524cea737794202c53
author
brice · · 2026-04-15 03:32 UTC
parent
3078bf4
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +27 -1
M syscall_unix.go +27 -1
@@ -11,6 +11,8 @@ import (
1111 "runtime"
1212 "sync"
1313 "unsafe"
14+
15+ "github.com/bnema/purego/internal/strings"
1416 )
1517
1618 var syscall15XABI0 uintptr
@@ -82,7 +84,7 @@ func compileCallback(fn any) uintptr {
8284 continue
8385 case reflect.Interface, reflect.Func, reflect.Slice,
8486 reflect.Chan, reflect.Complex64, reflect.Complex128,
85- reflect.String, reflect.Map, reflect.Invalid:
87+ reflect.Map, reflect.Invalid:
8688 panic("purego: unsupported argument type: " + in.Kind().String())
8789 }
8890 }
@@ -211,6 +213,30 @@ func callbackWrap(a *callbackArgs) {
211213 }
212214 }
213215 floatsN += slots
216+ case reflect.String:
217+ slots = 1
218+ var ptr uintptr
219+ if intsN+slots > numOfIntegerRegisters() {
220+ if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
221+ ptr = uintptr(callbackArgFromStack(a.args, stackSlot, &stackByteOffset, reflect.TypeOf(uintptr(0))).Uint())
222+ } else if stackFrame != nil {
223+ if runtime.GOARCH == "s390x" {
224+ ptr = uintptr(callbackArgFromSlotBigEndian(unsafe.Pointer(&stackFrame[stackSlot]), reflect.TypeOf(uintptr(0))).Uint())
225+ } else {
226+ ptr = *(*uintptr)(unsafe.Pointer(&stackFrame[stackSlot]))
227+ }
228+ stackSlot += slots
229+ } else {
230+ ptr = frame[stackSlot]
231+ stackSlot += slots
232+ }
233+ } else {
234+ pos := intsN + numOfFloatRegisters()
235+ ptr = frame[pos]
236+ }
237+ intsN += slots
238+ args[i] = reflect.ValueOf(strings.GoString(ptr))
239+ continue
214240 case reflect.Struct:
215241 if i == 0 && inType.AssignableTo(reflect.TypeOf(CDecl{})) {
216242 args[i] = reflect.Zero(inType)
@@ -11,6 +11,8 @@ import (
11 "runtime"11 "runtime"
12 "sync"12 "sync"
13 "unsafe"13 "unsafe"
14+
15+ "github.com/bnema/purego/internal/strings"
14 )16 )
15 17
16 var syscall15XABI0 uintptr18 var syscall15XABI0 uintptr
@@ -82,7 +84,7 @@ func compileCallback(fn any) uintptr {
82 continue84 continue
83 case reflect.Interface, reflect.Func, reflect.Slice,85 case reflect.Interface, reflect.Func, reflect.Slice,
84 reflect.Chan, reflect.Complex64, reflect.Complex128,86 reflect.Chan, reflect.Complex64, reflect.Complex128,
85- reflect.String, reflect.Map, reflect.Invalid:87+ reflect.Map, reflect.Invalid:
86 panic("purego: unsupported argument type: " + in.Kind().String())88 panic("purego: unsupported argument type: " + in.Kind().String())
87 }89 }
88 }90 }
@@ -211,6 +213,30 @@ func callbackWrap(a *callbackArgs) {
211 }213 }
212 }214 }
213 floatsN += slots215 floatsN += slots
216+ case reflect.String:
217+ slots = 1
218+ var ptr uintptr
219+ if intsN+slots > numOfIntegerRegisters() {
220+ if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
221+ ptr = uintptr(callbackArgFromStack(a.args, stackSlot, &stackByteOffset, reflect.TypeOf(uintptr(0))).Uint())
222+ } else if stackFrame != nil {
223+ if runtime.GOARCH == "s390x" {
224+ ptr = uintptr(callbackArgFromSlotBigEndian(unsafe.Pointer(&stackFrame[stackSlot]), reflect.TypeOf(uintptr(0))).Uint())
225+ } else {
226+ ptr = *(*uintptr)(unsafe.Pointer(&stackFrame[stackSlot]))
227+ }
228+ stackSlot += slots
229+ } else {
230+ ptr = frame[stackSlot]
231+ stackSlot += slots
232+ }
233+ } else {
234+ pos := intsN + numOfFloatRegisters()
235+ ptr = frame[pos]
236+ }
237+ intsN += slots
238+ args[i] = reflect.ValueOf(strings.GoString(ptr))
239+ continue
214 case reflect.Struct:240 case reflect.Struct:
215 if i == 0 && inType.AssignableTo(reflect.TypeOf(CDecl{})) {241 if i == 0 && inType.AssignableTo(reflect.TypeOf(CDecl{})) {
216 args[i] = reflect.Zero(inType)242 args[i] = reflect.Zero(inType)

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 102

↑↓ moveenter openesc close