[Go] Use unsafe.Slice and unsafe.String in Go fragments

The existing code didn't work correctly for strings longer than 2GB.

This does require using at least Go 1.20, but that should be OK as
the last currently supported version of Go is 1.22.

This restores commit ff5c118aaa which
was rolled back by commit fe3a7af855
because Go was generating C code that uses declarations after
statements. The original commit now works because 1) commit
e0ecea47b1 sets the C standard to use,
and 2) the current minor versions of the relevant Go releases were
fixed to put the declarations first.

Fixes #3125
This commit is contained in:
Ian Lance Taylor 2025-06-25 13:51:06 -07:00
parent 64fcc45920
commit 93d67c9549
7 changed files with 15 additions and 11 deletions

View File

@ -7,6 +7,10 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.4.0 (in progress)
===========================
2025-06-27: ianlancetaylor
Use unsafe for Go strings rather than byte arrays.
Update minimum Go supported version to 1.20.
2025-06-23: jschueller
#3184 #3196 [Python] Support multi-phase module initialization.

View File

@ -73,7 +73,7 @@ code. SWIG fills this gap.
There are (at least) two different Go compilers. The first is the gc compiler
of the <a href="https://golang.org/doc/install">Go distribution</a>, normally
invoked via the <a href="https://golang.org/cmd/go/">go tool</a>.
SWIG supports the gc compiler version 1.2 or later.
SWIG supports the gc compiler version 1.20 or later.
The second Go compiler is the <a href="https://golang.org/doc/install/gccgo">
gccgo compiler</a>, which is a frontend to the GCC compiler suite.
The interface to C/C++ code is completely different for the two Go compilers.

View File

@ -434,7 +434,7 @@ $(GOPATHPARENTDIR)/go.mod:
@mkdir $(GOPATHDIR) 2>/dev/null || true
echo "module swigtests" > $(GOPATHDIR)/go.mod
echo "" >> $(GOPATHDIR)/go.mod
echo "go 1.12" >> $(GOPATHDIR)/go.mod
echo "go 1.20" >> $(GOPATHDIR)/go.mod
mv -f $(GOPATHDIR)/go.mod $(GOPATHPARENTDIR)/go.mod
go: $(SRCDIR_SRCS) $(GOPATHPARENTDIR)/go.mod

View File

@ -46,7 +46,7 @@ struct swigcdata {
$result = nil
} else {
b := make([]byte, p.size)
a := (*[0x7fffffff]byte)(unsafe.Pointer(p.data))[:p.size]
a := unsafe.Slice((*byte)(unsafe.Pointer(p.data)), p.size)
copy(b, a)
Swig_free(p.data)
Swig_free(uintptr(unsafe.Pointer(p)))

View File

@ -485,10 +485,10 @@ rvrdeleter.reset($1); %}
%{
{
p := Swig_malloc(len($input) + 1)
s := (*[1<<30]byte)(unsafe.Pointer(p))[:len($input) + 1]
s := unsafe.Slice((*byte)(unsafe.Pointer(p)), len($input) + 1)
copy(s, $input)
s[len($input)] = 0
$result = *(*string)(unsafe.Pointer(&s))
$result = unsafe.String((*byte)(unsafe.Pointer(p)), len($input) + 1)
}
%}

View File

@ -22,7 +22,7 @@ static _gostring_ Swig_AllocateString(const char *p, size_t l) {
type swig_gostring struct { p uintptr; n int }
func swigCopyString(s string) string {
p := *(*swig_gostring)(unsafe.Pointer(&s))
r := string((*[0x7fffffff]byte)(unsafe.Pointer(p.p))[:p.n])
r := string(unsafe.Slice((*byte)(unsafe.Pointer(p.p)), p.n))
Swig_free(p.p)
return r
}

View File

@ -28,9 +28,9 @@ class string;
%{
{
p := Swig_malloc(len($input))
s := (*[1<<30]byte)(unsafe.Pointer(p))[:len($input)]
s := unsafe.Slice((*byte)(unsafe.Pointer(p)), len($input))
copy(s, $input)
$result = *(*string)(unsafe.Pointer(&s))
$result = unsafe.String((*byte)(unsafe.Pointer(p)), len($input))
}
%}
@ -65,9 +65,9 @@ class string;
%{
{
p := Swig_malloc(len($input))
s := (*[1<<30]byte)(unsafe.Pointer(p))[:len($input)]
s := unsafe.Slice((*byte)(unsafe.Pointer(p)), len($input))
copy(s, $input)
$result = *(*string)(unsafe.Pointer(&s))
$result = unsafe.String((*byte)(unsafe.Pointer(p)), len($input))
}
%}
@ -110,7 +110,7 @@ class string;
%{
if $input != nil {
p := Swig_malloc(len(*$input))
s := (*[1<<30]byte)(unsafe.Pointer(p))[:len(*$input)]
s := unsafe.Slice((*byte)(unsafe.Pointer(p)), len(*$input))
copy(s, *$input)
$result = (*string)(unsafe.Pointer(&s))
} else {