I'm to create an object (whatever it is) satisfying certain interface dynamically. Current reflect.StructOf
creates structs but without adding methods. So I read the source code and tried to add a function in reflect
package and I got the following error,
unexpected fault address 0xc0000b8120
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x2 addr=0xc0000b8120 pc=0xc0000b8120]
Here is the file I added into the reflect
package,
package reflect
import (
"sort"
"unsafe"
)
type InterfaceMethod struct {
Name string
Func Value
}
func InterfaceOf(funcs []InterfaceMethod) Value {
if len(funcs) == 0 {
return New(TypeOf("Interface {}"))
}
var (
repr = []byte("struct { /* non-invertible */ }")
hash = fnv1(0, []byte("struct { /* non-invertible */ }")...)
size uintptr
typalign uint8
methods []method
)
// add sorted methods here
{
for idx := range funcs {
if funcs[idx].Func.Type().Kind() != Func {
panic("funcs contains non-func")
}
c := funcs[idx].Name[0]
if !('A' <= c && c <= 'Z') {
panic("funcs contains unexported func")
}
}
sort.Slice(funcs, func(i, j int) bool {
return funcs[i].Name < funcs[j].Name
})
for idx := range funcs {
ft := funcs[idx].Func.Type().common()
ft.uncommon()
ifn := funcs[idx].Func
methods = append(methods, method{
name: resolveReflectName(newName(funcs[idx].Name, "", true)),
mtyp: resolveReflectType(ft),
ifn: resolveReflectText(unsafe.Pointer(&ifn)),
tfn: resolveReflectText(unsafe.Pointer(&ifn)),
})
}
}
var typ *structType
var ut *uncommonType
{
// A *rtype representing a struct is followed directly in memory by an
// array of method objects representing the methods attached to the
// struct. To get the same layout for a run time generated type, we
// need an array directly following the uncommonType memory.
// A similar strategy is used for funcTypeFixed4, ...funcTypeFixedN.
tt := New(StructOf([]StructField{
{Name: "S", Type: TypeOf(structType{})},
{Name: "U", Type: TypeOf(uncommonType{})},
{Name: "M", Type: ArrayOf(len(methods), TypeOf(methods[0]))},
}))
typ = (*structType)(tt.Elem().Field(0).Addr().UnsafePointer())
ut = (*uncommonType)(tt.Elem().Field(1).Addr().UnsafePointer())
copy(tt.Elem().Field(2).Slice(0, len(methods)).Interface().([]method), methods)
}
ut.mcount = uint16(len(methods))
ut.xcount = ut.mcount // we only have exported methods
ut.moff = uint32(unsafe.Sizeof(uncommonType{}))
str := string(repr)
// Round the size up to be a multiple of the alignment.
size = align(size, uintptr(typalign))
// Make the struct type.
var istruct any = struct{}{}
prototype := *(**structType)(unsafe.Pointer(&istruct))
*typ = *prototype
typ.str = resolveReflectName(newName(str, "", false))
typ.tflag = 0 // TODO: set tflagRegularMemory
typ.hash = hash
typ.size = size
typ.ptrdata = typeptrdata(typ.common())
typ.align = typalign
typ.fieldAlign = typalign
typ.ptrToThis = 0
typ.tflag |= tflagUncommon
{
typ.kind &^= kindGCProg
bv := new(bitVector)
addTypeBits(bv, 0, typ.common())
if len(bv.data) > 0 {
typ.gcdata = &bv.data[0]
}
}
typ.equal = nil
typ.kind &^= kindDirectIface
return Zero(&typ.rtype)
}
Here is the testing file.
package main
import (
"fmt"
"reflect"
"testing"
)
func TestInterfaceOf(t *testing.T) {
type AliceInterface interface {
BobMethod() (error, string)
}
Alice := reflect.TypeOf((*AliceInterface)(nil)).Elem()
Bob := Alice.Method(0)
Carol := reflect.MakeFunc(Bob.Type, func(args []reflect.Value) []reflect.Value {
fmt.Println("[wow]")
nilError := reflect.Zero(reflect.TypeOf((*error)(nil)).Elem())
return []reflect.Value{nilError, reflect.ValueOf("haha")}
})
Dan := reflect.InterfaceOf([]reflect.InterfaceMethod{
{
Name: "BobMethod",
Func: Carol,
},
})
Dan.Method(0).Call([]reflect.Value{}) // panic
dan := Dan.Interface().(AliceInterface)
dan.BobMethod() // also panic
}