diff --git a/.github/workflows/push-check-go116.yml b/.github/workflows/push-check-go116.yml index c35f082..a962f08 100644 --- a/.github/workflows/push-check-go116.yml +++ b/.github/workflows/push-check-go116.yml @@ -21,4 +21,4 @@ jobs: ${{ runner.os }}-go- - name: Unit Test - run: GOMAXPROCS=4 go test -v -race -gcflags=-d=checkptr=0 -covermode=atomic -coverprofile=coverage.out ./... + run: GOMAXPROCS=4 go test -v -gcflags=-d=checkptr=0 -race -covermode=atomic -coverprofile=coverage.out ./... diff --git a/internal/loader/funcdata.go b/internal/loader/funcdata.go index 047a0da..3e916f6 100644 --- a/internal/loader/funcdata.go +++ b/internal/loader/funcdata.go @@ -53,6 +53,8 @@ var ( modList []*_ModuleData ) +var emptyByte byte + func encodeVariant(v int) []byte { var u int var r []byte diff --git a/internal/loader/funcdata_go115.go b/internal/loader/funcdata_go115.go index bd334de..3673da8 100644 --- a/internal/loader/funcdata_go115.go +++ b/internal/loader/funcdata_go115.go @@ -155,6 +155,8 @@ func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args in minpc : minpc, maxpc : maxpc, modulename : name, + gcdata: uintptr(unsafe.Pointer(&emptyByte)), + gcbss: uintptr(unsafe.Pointer(&emptyByte)), } /* verify and register the new module */ diff --git a/internal/loader/funcdata_go116.go b/internal/loader/funcdata_go116.go index 1316b64..20d7df1 100644 --- a/internal/loader/funcdata_go116.go +++ b/internal/loader/funcdata_go116.go @@ -159,6 +159,8 @@ func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args in minpc : minpc, maxpc : maxpc, modulename : name, + gcdata: uintptr(unsafe.Pointer(&emptyByte)), + gcbss: uintptr(unsafe.Pointer(&emptyByte)), } /* verify and register the new module */ diff --git a/internal/loader/funcdata_go118.go b/internal/loader/funcdata_go118.go index 07312fa..433a6ba 100644 --- a/internal/loader/funcdata_go118.go +++ b/internal/loader/funcdata_go118.go @@ -28,7 +28,6 @@ import ( // This list must match the list in cmd/internal/objabi/funcid.go. type funcFlag uint8 - type _Func struct { entryOff uint32 // start pc nameoff int32 // function name @@ -186,6 +185,8 @@ func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args in minpc : minpc, maxpc : maxpc, modulename : name, + gcdata: uintptr(unsafe.Pointer(&emptyByte)), + gcbss: uintptr(unsafe.Pointer(&emptyByte)), gofunc: base, } diff --git a/issue_test/plugin/main.go b/issue_test/plugin/main.go new file mode 100644 index 0000000..b64f761 --- /dev/null +++ b/issue_test/plugin/main.go @@ -0,0 +1,23 @@ +package main + +import ( + `fmt` + + `github.com/bytedance/sonic` +) + +var V int + +var Obj map[string]string + +func init() { + if err := sonic.UnmarshalString(`{"a":"b"}`, &Obj); err != nil { + panic(err) + } +} + +func F() { fmt.Printf("Hello, number %d\n", V) } + +func Unmarshal(json string, val interface{}) error { + return sonic.UnmarshalString(json, val) +} diff --git a/issue_test/plugin_test.go b/issue_test/plugin_test.go new file mode 100644 index 0000000..89d41cc --- /dev/null +++ b/issue_test/plugin_test.go @@ -0,0 +1,96 @@ +// +build !race + +/* + * Copyright 2021 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package issue_test + +import ( + `bytes` + `fmt` + `os/exec` + `plugin` + `runtime` + `testing` + `reflect` + + _ `github.com/bytedance/sonic` +) + +func buildPlugin() { + out := bytes.NewBuffer(nil) + bin0, err := exec.LookPath("rm") + if err != nil { + panic(err) + } + cmd0 := exec.Cmd{ + Path: bin0, + Args: []string{"rm", "-f", "plugin/plugin."+runtime.Version()+".so"}, + Stdout: out, + Stderr: out, + } + if err := cmd0.Run(); err != nil { + panic(string(out.Bytes())) + } + out.Reset() + bin, err := exec.LookPath("go") + if err != nil { + panic(err) + } + cmd := exec.Cmd{ + Path: bin, + Args: []string{"go", "build", "-buildmode", "plugin", "-o", "plugin/plugin."+runtime.Version()+".so", "plugin/main.go"}, + Stdout: out, + Stderr: out, + } + if err := cmd.Run(); err != nil { + panic(string(out.Bytes())) + } +} + + +func TestPlugin(t *testing.T) { + buildPlugin() + p, err := plugin.Open("plugin/plugin."+runtime.Version()+".so") + if err != nil { + t.Fatal(err) + } + v, err := p.Lookup("V") + if err != nil { + t.Fatal(err) + } + f, err := p.Lookup("F") + if err != nil { + t.Fatal(err) + } + *v.(*int) = 7 + f.(func())() // prints "Hello, number 7" + obj, err := p.Lookup("Obj") + m := *(obj.(*map[string]string)) + fmt.Printf("%#v\n", m) + d, err := p.Lookup("Unmarshal") + if err != nil { + t.Fatal(err) + } + dec := d.(func(json string, val interface{}) error) + var exp map[string]string + if err := dec(`{"a":"b"}`, &exp); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(m, exp) { + t.Fatal(m, exp) + } +}