Skip to content

Commit 1c0d793

Browse files
committed
before unload module, unregister itab from itabList, otherwise, there will be panic when the itabList grow
1 parent 882355b commit 1c0d793

10 files changed

+146
-61
lines changed

Diff for: dymcode.go

+3
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,9 @@ func Load(code *CodeReloc, symPtr map[string]uintptr) (*CodeModule, error) {
535535
}
536536

537537
func (cm *CodeModule) Unload() {
538+
for i := 0; i < len(cm.itabs); i++ {
539+
eraseiface(cm.itabs[i].inter, cm.itabs[i]._type)
540+
}
538541
runtime.GC()
539542
modulesLock.Lock()
540543
removeModule(cm.Module)

Diff for: iface.1.10.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// +build go1.10
2+
// +build !go1.15
3+
4+
package goloader
5+
6+
import (
7+
"unsafe"
8+
)
9+
10+
// layout of Itab known to compilers
11+
// allocated in non-garbage-collected memory
12+
// Needs to be in sync with
13+
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptabs.
14+
type itab struct {
15+
inter *interfacetype
16+
_type *_type
17+
hash uint32 // copy of _type.hash. Used for type switches.
18+
_ [4]byte
19+
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
20+
}
21+
22+
const itabInitSize = 512
23+
24+
// Note: change the formula in the mallocgc call in itabAdd if you change these fields.
25+
type itabTableType struct {
26+
size uintptr // length of entries array. Always a power of 2.
27+
count uintptr // current number of filled entries.
28+
entries [itabInitSize]*itab // really [size] large
29+
}
30+
31+
//go:linkname itabTable runtime.itabTable
32+
var itabTable *itabTableType // pointer to current table
33+
34+
//go:linkname itabLock runtime.itabLock
35+
var itabLock mutex
36+
37+
//go:linkname itabHashFunc runtime.itabHashFunc
38+
func itabHashFunc(inter *interfacetype, typ *_type) uintptr
39+
40+
func eraseiface(inter *interfacetype, typ *_type) bool {
41+
lock(&itabLock)
42+
defer unlock(&itabLock)
43+
mask := itabTable.size - 1
44+
h := itabHashFunc(inter, typ) & mask
45+
for i := uintptr(1); ; i++ {
46+
p := (**itab)(add(unsafe.Pointer(&itabTable.entries), h*PtrSize))
47+
// Use atomic read here so if we see m != nil, we also see
48+
// the initializations of the fields of m.
49+
// m := *p
50+
m := (*itab)(Loadp(unsafe.Pointer(p)))
51+
if m == nil {
52+
return false
53+
}
54+
if m.inter == inter && m._type == typ {
55+
atomicstorep(unsafe.Pointer(p), unsafe.Pointer(nil))
56+
itabTable.count = itabTable.count - 1
57+
return true
58+
}
59+
h += i
60+
h &= mask
61+
}
62+
}

Diff for: iface.1.8.go

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// +build go1.8
2+
// +build !go1.10,!go1.11,!go1.12,!go1.13,!go1.14,!go1.15
3+
4+
package goloader
5+
6+
import (
7+
"unsafe"
8+
)
9+
10+
// layout of Itab known to compilers
11+
// allocated in non-garbage-collected memory
12+
// Needs to be in sync with
13+
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs.
14+
type itab struct {
15+
inter *interfacetype
16+
_type *_type
17+
link *itab
18+
bad int32
19+
inhash int32 // has this itab been added to hash?
20+
fun [1]uintptr // variable sized
21+
}
22+
23+
// See: src/runtime/iface.go
24+
const hashSize = 1009
25+
26+
//go:linkname hash runtime.hash
27+
var hash [hashSize]*itab
28+
29+
//go:linkname ifaceLock runtime.ifaceLock
30+
var ifaceLock mutex
31+
32+
//go:linkname itabhash runtime.itabhash
33+
func itabhash(inter *interfacetype, typ *_type) uint32
34+
35+
func eraseiface(inter *interfacetype, typ *_type) bool {
36+
lock(&ifaceLock)
37+
defer unlock(&ifaceLock)
38+
h := itabhash(inter, typ)
39+
var m, last *itab = nil, nil
40+
for m = (*itab)(Loadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link {
41+
if m.inter == inter && m._type == typ {
42+
if last == nil {
43+
atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(nil))
44+
} else {
45+
last.link = m.link
46+
}
47+
return true
48+
}
49+
last = m
50+
}
51+
return false
52+
}

Diff for: iface.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package goloader
2+
3+
import "unsafe"
4+
5+
// Mutual exclusion locks. In the uncontended case,
6+
// as fast as spin locks (just a few user-level instructions),
7+
// but on the contention path they sleep in the kernel.
8+
// A zeroed Mutex is unlocked (no need to initialize each lock).
9+
type mutex struct {
10+
// Futex-based impl treats it as uint32 key,
11+
// while sema-based impl as M* waitm.
12+
// Used to be a union, but unions break precise GC.
13+
key uintptr
14+
}
15+
16+
//go:linkname lock runtime.lock
17+
func lock(l *mutex)
18+
19+
//go:linkname unlock runtime.unlock
20+
func unlock(l *mutex)
21+
22+
//go:linkname atomicstorep runtime.atomicstorep
23+
func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer)

Diff for: module.1.10.go

-12
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,6 @@ package goloader
55

66
import "cmd/objfile/goobj"
77

8-
// layout of Itab known to compilers
9-
// allocated in non-garbage-collected memory
10-
// Needs to be in sync with
11-
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs.
12-
type itab struct {
13-
inter *interfacetype
14-
_type *_type
15-
hash uint32 // copy of _type.hash. Used for type switches.
16-
_ [4]byte
17-
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
18-
}
19-
208
// PCDATA and FUNCDATA table indexes.
219
//
2210
// See funcdata.h and ../cmd/internal/obj/funcdata.go.

Diff for: module.1.12.go

-12
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,6 @@ import (
99
"strings"
1010
)
1111

12-
// layout of Itab known to compilers
13-
// allocated in non-garbage-collected memory
14-
// Needs to be in sync with
15-
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs.
16-
type itab struct {
17-
inter *interfacetype
18-
_type *_type
19-
hash uint32 // copy of _type.hash. Used for type switches.
20-
_ [4]byte
21-
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
22-
}
23-
2412
// PCDATA and FUNCDATA table indexes.
2513
//
2614
// See funcdata.h and ../cmd/internal/objabi/funcdata.go.

Diff for: module.1.13.go

-12
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,6 @@ import (
99
"strings"
1010
)
1111

12-
// layout of Itab known to compilers
13-
// allocated in non-garbage-collected memory
14-
// Needs to be in sync with
15-
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs.
16-
type itab struct {
17-
inter *interfacetype
18-
_type *_type
19-
hash uint32 // copy of _type.hash. Used for type switches.
20-
_ [4]byte
21-
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
22-
}
23-
2412
// PCDATA and FUNCDATA table indexes.
2513
//
2614
// See funcdata.h and ../cmd/internal/objabi/funcdata.go.

Diff for: module.1.14.go

-12
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,6 @@ import (
99
"strings"
1010
)
1111

12-
// layout of Itab known to compilers
13-
// allocated in non-garbage-collected memory
14-
// Needs to be in sync with
15-
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptabs.
16-
type itab struct {
17-
inter *interfacetype
18-
_type *_type
19-
hash uint32 // copy of _type.hash. Used for type switches.
20-
_ [4]byte
21-
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
22-
}
23-
2412
// PCDATA and FUNCDATA table indexes.
2513
//
2614
// See funcdata.h and ../cmd/internal/objabi/funcdata.go.

Diff for: module.1.8.go

-13
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,6 @@ import (
77
"cmd/objfile/goobj"
88
)
99

10-
// layout of Itab known to compilers
11-
// allocated in non-garbage-collected memory
12-
// Needs to be in sync with
13-
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs.
14-
type itab struct {
15-
inter *interfacetype
16-
_type *_type
17-
link *itab
18-
bad int32
19-
inhash int32 // has this itab been added to hash?
20-
fun [1]uintptr // variable sized
21-
}
22-
2310
// PCDATA and FUNCDATA table indexes.
2411
//
2512
// See funcdata.h and ../cmd/internal/obj/funcdata.go.

Diff for: utils.go

+6
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,9 @@ func copy2Slice(dst []byte, src unsafe.Pointer, size int) {
4040
}
4141
copy(dst, *(*[]byte)(unsafe.Pointer(&s)))
4242
}
43+
44+
//go:nosplit
45+
//go:noinline
46+
func Loadp(ptr unsafe.Pointer) unsafe.Pointer {
47+
return *(*unsafe.Pointer)(ptr)
48+
}

0 commit comments

Comments
 (0)