FAQ
Hello,

I've been working on some reflect additions such as FuncOf(). I've been
issue to deadcode() in ld which is blowing away typelinks to interface
method types not directly referenced by the code.
Heres a quick example to show why this is problematic:

type I int
func (I) X(in int) int {
     return in
}

func main() {
     intT := TypeOf(0)
     ft := FuncOf([]Type{intT}, []Type{intT}, false))
}

Here I've constructed a function type using FuncOf(). The 'func(int) int'
type of X was never referenced by the code and hence deleted by the
deadcode detector.
However, the type lives on in the main.I.X method type. When FuncOf fails
to find it in the typelinks it creates a new type that is not equal to
main.I.X, causing havoc in the runtime.

By commenting out a few lines, I was able to keep my typelinks, though I am
now a bit over my head. I would like to ask someone in the know what the
implications of my reckless commenting are.
     // keep each beginning with 'typelink.' if the symbol it points at is
being kept.
     for(s = ctxt->allsym; s != S; s = s->allsym) {
         //if(strncmp(s->name, "go.typelink.", 12) == 0)
             //s->reachable = s->nr==1 && s->r[0].sym->reachable;
         s->reachable = 1;
     }

In particular, what is s->nr? I'm guessing r[0].sym->reachable is the
typelink for main.I, which is the unused type that gets deleted? Is this
roughly correct?

Playing around,

     for(s = ctxt->allsym; s != S; s = s->allsym) {
         if(strncmp(s->name, "go.typelink.", 12) == 0)
             s->reachable = 1;
     }

results in unreachable symbol errors, e.g.
type.[]*go/ast.InterfaceType: unreachable sym in relocation:
type.[]*go/ast.InterfaceType type..gc.[]*go/ast.InterfaceType

Thank you.




--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Ian Lance Taylor at Mar 9, 2014 at 4:55 pm

    On Sun, Mar 9, 2014 at 8:02 AM, wrote:
    I've been working on some reflect additions such as FuncOf(). I've been
    issue to deadcode() in ld which is blowing away typelinks to interface
    method types not directly referenced by the code.
    Heres a quick example to show why this is problematic:

    type I int
    func (I) X(in int) int {
    return in
    }

    func main() {
    intT := TypeOf(0)
    ft := FuncOf([]Type{intT}, []Type{intT}, false))
    }

    Here I've constructed a function type using FuncOf(). The 'func(int) int'
    type of X was never referenced by the code and hence deleted by the
    deadcode detector.
    However, the type lives on in the main.I.X method type. When FuncOf fails to
    find it in the typelinks it creates a new type that is not equal to
    main.I.X, causing havoc in the runtime.
    If I'm following your description correctly, it sounds like the bug is
    that the main.I.X method type is not being marked as reachable. That
    is, there should be another case in deadcode that marks the relevant
    typelink symbols as reachable.
    In particular, what is s->nr?
    s->nr is the number of relocations applied to the symbol, which in
    this case is the typelink information. The test is there is to ensure
    that s->r[0] is valid, which it would not be if s->nr == 0.
    I'm guessing r[0].sym->reachable is the typelink for main.I, which
    is the unused type that gets deleted?
    I wouldn't describe it that way. s is the typelink symbol. s->r[0]
    is the symbol to which the typelink refers. If that symbol is
    reachable, then the typelink is reachable. In this case I guess
    main.I is not reachable, and so the typelink for main.I is being
    deleted.

    You seem to be concerned about the type of I.X. But now I'm puzzled:
    why is that typelink being retained? How can it be accessed in the
    program?

    Can you show us a program that results in havoc with your definition
    of reflect.FuncOf?

    Ian

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Carl at Mar 9, 2014 at 10:44 pm

    On Mon, Mar 10, 2014 at 1:55 AM, Ian Lance Taylor wrote:
    On Sun, Mar 9, 2014 at 8:02 AM, wrote:

    I've been working on some reflect additions such as FuncOf(). I've been
    issue to deadcode() in ld which is blowing away typelinks to interface
    method types not directly referenced by the code.
    Heres a quick example to show why this is problematic:

    type I int
    func (I) X(in int) int {
    return in
    }

    func main() {
    intT := TypeOf(0)
    ft := FuncOf([]Type{intT}, []Type{intT}, false))
    }

    Here I've constructed a function type using FuncOf(). The 'func(int) int'
    type of X was never referenced by the code and hence deleted by the
    deadcode detector.
    However, the type lives on in the main.I.X method type. When FuncOf fails to
    find it in the typelinks it creates a new type that is not equal to
    main.I.X, causing havoc in the runtime.
    If I'm following your description correctly, it sounds like the bug is
    that the main.I.X method type is not being marked as reachable. That
    is, there should be another case in deadcode that marks the relevant
    typelink symbols as reachable.
    In particular, what is s->nr?
    s->nr is the number of relocations applied to the symbol, which in
    this case is the typelink information. The test is there is to ensure
    that s->r[0] is valid, which it would not be if s->nr == 0.
    I'm guessing r[0].sym->reachable is the typelink for main.I, which
    is the unused type that gets deleted?
    I wouldn't describe it that way. s is the typelink symbol. s->r[0]
    is the symbol to which the typelink refers. If that symbol is
    reachable, then the typelink is reachable. In this case I guess
    main.I is not reachable, and so the typelink for main.I is being
    deleted.
    Ok, that makes sense.
    You seem to be concerned about the type of I.X. But now I'm puzzled:
    why is that typelink being retained? How can it be accessed in the
    program?

    Can you show us a program that results in havoc with your definition
    of reflect.FuncOf?
    The particular issue I encountered was that when assigning to a
    created interface, reflect.implements() checks
    each method type of the interface is satisfied by a method of the dynamic type.
         intT := TypeOf(0)
         iface := InterfaceOf([]Method{
             {Name: "X", Type: FuncOf([]Type{intT}, []Type{intT}, false)},
         })
         i := New(iface).Elem()
         i.Set(ValueOf(I(0)))

    panic: reflect.Set: value of type main.I is not assignable to type
    interface { X(int) int }

    The constructed interface method func type has the correct
    representation (func(int) int), but is duplicated because it is not
    found in the typelinks.
    Perhaps havoc is an exaggeration, but the reflect package at least did
    access the type of main.I.X.
    Ian
    --
    Carl

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Ian Lance Taylor at Mar 10, 2014 at 4:51 pm

    On Sun, Mar 9, 2014 at 3:44 PM, Carl wrote:
    On Mon, Mar 10, 2014 at 1:55 AM, Ian Lance Taylor wrote:

    Can you show us a program that results in havoc with your definition
    of reflect.FuncOf?
    The particular issue I encountered was that when assigning to a
    created interface, reflect.implements() checks
    each method type of the interface is satisfied by a method of the dynamic type.
    intT := TypeOf(0)
    iface := InterfaceOf([]Method{
    {Name: "X", Type: FuncOf([]Type{intT}, []Type{intT}, false)},
    })
    i := New(iface).Elem()
    i.Set(ValueOf(I(0)))

    panic: reflect.Set: value of type main.I is not assignable to type
    interface { X(int) int }

    The constructed interface method func type has the correct
    representation (func(int) int), but is duplicated because it is not
    found in the typelinks.
    Perhaps havoc is an exaggeration, but the reflect package at least did
    access the type of main.I.X.
    I'm sorry, I'm having a hard time figuring out exactly what is going
    on here. You are referring to the type I here, so I don't understand
    why the typelink for I would be being collected. Can you show a
    complete program? Also this seems to refer to InterfaceOf, not
    FuncOf; I guess they are similar but InterfaceOf is also new, right?

    Ian

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Carl at Mar 11, 2014 at 5:54 am

    On Tue, Mar 11, 2014 at 1:51 AM, Ian Lance Taylor wrote:
    I'm sorry, I'm having a hard time figuring out exactly what is going
    on here. You are referring to the type I here, so I don't understand
    why the typelink for I would be being collected. Can you show a
    complete program? Also this seems to refer to InterfaceOf, not
    FuncOf; I guess they are similar but InterfaceOf is also new, right?
    Sorry, the second example was meant to be a continuation of the first,
    which I didn't make obvious.
    The full program is at http://play.golang.org/p/mgzxZB2aw4

    package main

    import . "reflect"

    type I int
    func (I) X(in int) int {
         return in
    }

    func main() {
         intT := TypeOf(0)
         iface := InterfaceOf([]Method{
             {Name: "X", Type: FuncOf([]Type{intT}, []Type{intT}, false)},
         })
         i := New(iface).Elem();
         i.Set(ValueOf(I(0)))
    }

    Type 'I' should implement the constructed interface iface;
    InterfaceOf() is something I've implemented.
    At the call to Value.Set(v), reflect first checks that v is assignable
    to the Value, and because
    FuncOf([IntT], [IntT]) != TypeOf(I.X) the check fails.

    panic: reflect.Set: value of type main.I is not assignable to type
    interface { X(int) int }

    The root cause is the check

             if tm.typ != vm.mtyp {
                 continue
             }

    circa line type.go:1225 of implements().

    Does that make sense?

    Thank you.
    --
    Carl

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Ian Lance Taylor at Mar 11, 2014 at 4:54 pm

    On Mon, Mar 10, 2014 at 10:54 PM, Carl wrote:
    At the call to Value.Set(v), reflect first checks that v is assignable
    to the Value, and because
    FuncOf([IntT], [IntT]) != TypeOf(I.X) the check fails.

    panic: reflect.Set: value of type main.I is not assignable to type
    interface { X(int) int }

    The root cause is the check

    if tm.typ != vm.mtyp {
    continue
    }

    circa line type.go:1225 of implements().

    Does that make sense?
    Thanks, yes.

    So now I see that the type is there in the program, but it's not in
    the typelinks. I guess first I would check that you've modified
    dtypsym in gc/reflect.c to put function types into the typelinks.

    After that, then, yes, it does seem that the linker may be removing
    the typelink incorrectly. It should be easy to instrument the loop in
    deadcode in ld/go.c to print out function types that are being removed
    from typelinks, and print out the associated symbol. Look for the
    type you want, and see what the associated symbol is.

    It's quite possible that something will need to explicitly mark
    interface method types typelinks as reachable if the interface is
    reachable.

    Ian

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Carl at Mar 11, 2014 at 5:51 pm
    Thanks for that bit of info.

    I am currently marking all typelinks in my fork before the flood, my
    reasoning being that if the reflect package is able to create any type,
    then all types created by the compiler must be visible to the reflect
    package.

    Having just written that I've realised I ought to go back and check how
    pointers are being handled. If it's possible for a pointer type to exist
    without it's elem type in the typelinks there will be problems.

    Carl
    2014/03/12 3:54 "Ian Lance Taylor" <iant@golang.org>:
    On Mon, Mar 10, 2014 at 10:54 PM, Carl wrote:

    At the call to Value.Set(v), reflect first checks that v is assignable
    to the Value, and because
    FuncOf([IntT], [IntT]) != TypeOf(I.X) the check fails.

    panic: reflect.Set: value of type main.I is not assignable to type
    interface { X(int) int }

    The root cause is the check

    if tm.typ != vm.mtyp {
    continue
    }

    circa line type.go:1225 of implements().

    Does that make sense?
    Thanks, yes.

    So now I see that the type is there in the program, but it's not in
    the typelinks. I guess first I would check that you've modified
    dtypsym in gc/reflect.c to put function types into the typelinks.

    After that, then, yes, it does seem that the linker may be removing
    the typelink incorrectly. It should be easy to instrument the loop in
    deadcode in ld/go.c to print out function types that are being removed
    from typelinks, and print out the associated symbol. Look for the
    type you want, and see what the associated symbol is.

    It's quite possible that something will need to explicitly mark
    interface method types typelinks as reachable if the interface is
    reachable.

    Ian
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Ian Lance Taylor at Mar 11, 2014 at 6:36 pm

    On Tue, Mar 11, 2014 at 10:51 AM, Carl wrote:
    I am currently marking all typelinks in my fork before the flood, my
    reasoning being that if the reflect package is able to create any type, then
    all types created by the compiler must be visible to the reflect package.
    No, that's only necessary if the type remains in the program for some
    reason. If the type is completely eliminated from the program, then
    it's appropriate to eliminate the typelink as well.

    Ian

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Carl at Mar 11, 2014 at 6:37 pm
    That makes sense.

    Carl
    2014/03/12 5:36 "Ian Lance Taylor" <iant@golang.org>:
    On Tue, Mar 11, 2014 at 10:51 AM, Carl wrote:

    I am currently marking all typelinks in my fork before the flood, my
    reasoning being that if the reflect package is able to create any type, then
    all types created by the compiler must be visible to the reflect package.
    No, that's only necessary if the type remains in the program for some
    reason. If the type is completely eliminated from the program, then
    it's appropriate to eliminate the typelink as well.

    Ian
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedMar 9, '14 at 3:02p
activeMar 11, '14 at 6:37p
posts9
users2
websitegolang.org

2 users in discussion

Carl: 5 posts Ian Lance Taylor: 4 posts

People

Translate

site design / logo © 2022 Grokbase