From 34c480afa89a4efa917f30592d8c095dbaf7612e Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Tue, 1 Nov 2016 15:28:55 -0400 Subject: [PATCH] runtime: resolve type offsets using source module The runtime.typeEquals function is used during typelinksinit to determine the canonical set of *_type values to use throughout the runtime. As such, it is run against non-canonical *_type values, that is, types from modules that are duplicates of a type from another module that was loaded earlier in the program life. These non-canonical *_type values sometimes contain pointers. These pointers are pointing to position-independent data, and so they are set by ld.so using dynamic relocations when the module is loaded. As such, the pointer can point to the equivalent memory from a previous module. This means if typesEqual follows a pointer inside a *_type, it can end up at a piece of memory from another module. If it reads a typeOff or nameOff from that memory and attempts to resolve it against the non-canonical *_type from the later module, it will end up with a reference to junk memory. Instead, resolve against the pointer the offset was read from, so the data is valid. Fixes #17709. Should no longer matter after #17724 is resolved in a later Go. Change-Id: Ie88b151a3407d82ac030a97b5b6a19fc781901cb Reviewed-on: https://go-review.googlesource.com/32513 Run-TryBot: David Crawshaw Reviewed-by: Keith Randall --- src/runtime/type.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/runtime/type.go b/src/runtime/type.go index a3a19b9be0..3ecc54c72c 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -199,11 +199,11 @@ func (t *_type) nameOff(off nameOff) name { return resolveNameOff(unsafe.Pointer(t), off) } -func (t *_type) typeOff(off typeOff) *_type { +func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type { if off == 0 { return nil } - base := uintptr(unsafe.Pointer(t)) + base := uintptr(ptrInModule) var md *moduledata for next := &firstmoduledata; next != nil; next = next.next { if base >= next.types && base < next.etypes { @@ -235,6 +235,10 @@ func (t *_type) typeOff(off typeOff) *_type { return (*_type)(unsafe.Pointer(res)) } +func (t *_type) typeOff(off typeOff) *_type { + return resolveTypeOff(unsafe.Pointer(t), off) +} + func (t *_type) textOff(off textOff) unsafe.Pointer { base := uintptr(unsafe.Pointer(t)) var md *moduledata @@ -596,15 +600,19 @@ func typesEqual(t, v *_type) bool { for i := range it.mhdr { tm := &it.mhdr[i] vm := &iv.mhdr[i] - tname := it.typ.nameOff(tm.name) - vname := iv.typ.nameOff(vm.name) + // Note the mhdr array can be relocated from + // another module. See #17724. + tname := resolveNameOff(unsafe.Pointer(tm), tm.name) + vname := resolveNameOff(unsafe.Pointer(vm), vm.name) if tname.name() != vname.name() { return false } if tname.pkgPath() != vname.pkgPath() { return false } - if !typesEqual(it.typ.typeOff(tm.ityp), iv.typ.typeOff(vm.ityp)) { + tityp := resolveTypeOff(unsafe.Pointer(tm), tm.ityp) + vityp := resolveTypeOff(unsafe.Pointer(vm), vm.ityp) + if !typesEqual(tityp, vityp) { return false } }