Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reflect.Type.NumMethod() returns 0 for interface types, impacting CBOR unmarshalling #4260

Open
frenkel26 opened this issue May 12, 2024 · 0 comments

Comments

@frenkel26
Copy link

Description

It appears that reflect.Type.NumMethod() returns 0 when called on interface types. This behavior is particularly problematic for functionalities like CBOR unmarshalling that rely on NumMethod() for type resolution.

Potential Source of Issue

This issue may stem from changes made in the following commit: acba074
The relevant code is:

var numMethods int
if hasMethodSet {
  for i := 0; i < ms.Len(); i++ {
    if ms.At(i).Obj().Exported() {
      numMethods++
    }
  }
}

Here, numMethods is incremented only under the hasMethodSet condition, which is set to false if the type is an interface. This might not be the intended functionality.

Example of Affected Code

package main

import (
	"fmt"

	"github.com/fxamacker/cbor/v2"
)

type Marshallable interface {
	MarshalBinary() ([]byte, error)
	UnmarshalBinary(data []byte) error
}

type A struct {
	Data []byte
}

func (a *A) MarshalBinary() ([]byte, error) {
	return a.Data, nil
}

func (a *A) UnmarshalBinary(data []byte) error {
	a.Data = data
	return nil
}

type Message struct {
	SomeMarshallable Marshallable
}

func runMarshalUnmarshal() error {
	messageToMarshal := Message{
		SomeMarshallable: &A{Data: []byte("hello")},
	}

	// Marshal
	msgBytes, err := cbor.Marshal(messageToMarshal)
	if err != nil {
		return err
	}

	// Initiate with concrete type
	messageFromUnmarshal := Message{
		SomeMarshallable: &A{},
	}

	// Unmarshal
	err = cbor.Unmarshal(msgBytes, &messageFromUnmarshal)
	if err != nil {
		return err
	}

	// Print type of Marshallable
	fmt.Printf("%T\n", messageFromUnmarshal.SomeMarshallable)
	return nil
}

func main() {
	err := runMarshalUnmarshal()
	if err != nil {
		panic(err)
	}
}

Expected Behavior

The code above is expected to print the type *main.A but instead it prints []uint8. Removing the if hasMethodSet condition from the code reference above results with the desired behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant