pkujhd / goloader

load and run golang code at runtime.
Apache License 2.0
507 stars 59 forks source link

`typelinksRegister` may bind wrong address when some types have same name at packages which also have same name #85

Closed fumeboy closed 1 year ago

fumeboy commented 1 year ago
// register.go
func typelinksRegister(symPtr map[string]uintptr) {
    md := firstmoduledata
    for _, tl := range md.typelinks {
        t := (*_type)(adduintptr(md.types, int(tl)))
        if md.typemap != nil {
            t = (*_type)(adduintptr(md.typemap[typeOff(tl)], 0))
        }
        registerType(t, symPtr)
    }

typelinksRegister write elem to symPtr with key, the key is made by _type.String(), and which is lost the pkgpath and just cotains package name, so if two packages have same name, typelinksRegister may write symPtr twice at same key.

let user do registerType manually may be more safe, like this:

func init() {
    registerType(
        new(int64),
        new(int32),
        new(int16),
        new(int8),
        new(int),
        new(bool),
        new(string),
        new(byte),
        new(float64),
        new(uintptr),
        new(unsafe.Pointer),
        new(time.Time),
    )
    registerType(
        new(builtin.Context),
    )
    registerType(
        fmt.Sprintf,
        new(fmt.Stringer),
        strconv.Itoa,
        strconv.FormatInt,
        time.Sleep,
        json.Marshal,
        new(json.Marshaler),
        json.Unmarshal,
        new(json.Unmarshaler),
        new(sync.Mutex),
        new(sync.Mutex).Lock,
        new(sync.Mutex).Unlock,
        new(sync.WaitGroup),
        new(sync.WaitGroup).Wait,
        new(sync.WaitGroup).Add,
        new(sync.WaitGroup).Done,
    )
}
fumeboy commented 1 year ago

and share an discovery of type system here

i found the relocation R_MethodOff is used to put value as typeOff of method.mtyp, and the runtime (reflect indeed) always use the function resolveTypeOff the get *_type from moduledata.typemap by using the typeOff value as key

type method struct {
    name nameOff
    mtyp typeOff
    ifn  textOff
    tfn  textOff
}

so we could build custom moduledata.typemap with custom typeOff value for plugins, such as using math.MaxUint32 - 123 to visit json.Marshaler.Marshal, and the json.Marshaler.Marshal is provided by loader.

if a type is too far to visit by plugin (farther than 32bit), we can use this operation.

eh-steve commented 1 year ago

My implementation is different and produces fully qualified symbol names (no collisions), and I'd already implemented a similar idea to your second suggestion in this commit a few weeks ago. I need to fix a final few CGo bugs in that branch before I merge though

pkujhd commented 1 year ago

if a type is named, the resolved type path will be add with this code