dubbo-go icon indicating copy to clipboard operation
dubbo-go copied to clipboard

invoking EchoInt8 based on dubbo protocol failed

Open DMwangnima opened this issue 1 year ago • 6 comments

Environment

  • Server: Dubbo-go, v3.1.0
  • Client: Dubbo-go, v3.1.0
  • Protocol: Dubbo

Issue description

Provided Api EchoInt8:

type UserProvider struct {
	EchoInt8  func(ctx context.Context, req int8) (int8, error)
}

func (u *UserProvider) EchoInt8(ctx context.Context, req int8) (int8, error) {
	return req, nil
}

After invoking, srv-side returns error "reflect: Call using int32 as type int8"

Logs

Click me to check logs
cli-side
2023-08-19 09:07:32     INFO    logger/logging.go:42    The following profiles are active: [default]
2023-08-19 09:07:32     INFO    config/root_config.go:137       [Config Center] Config center doesn't start
2023-08-19 09:07:32     INFO    config/reference_config.go:136  URL specified explicitly dubbo://127.0.0.1:20000
2023-08-19 09:07:32     INFO    dubbo/dubbo_protocol.go:99      [DUBBO Protocol] Refer service: dubbo://127.0.0.1:20000/org.apache.dubbo.UserProvider?app.version=&application=dubbo.io&async=false&bean.name=UserProvider&cluster=failover&config.tracing=&environment=&generic=&group=&interface=org.apache.dubbo.UserProvider&loadbalance=&metadata-type=local&module=sample&name=dubbo.io&organization=dubbo-go&owner=dubbo-go&peer=true&provided-by=&reference.filter=cshutdown&registry.role=0&release=dubbo-golang-3.0.4&remote.timestamp=&retries=&serialization=&side=consumer&sticky=false&timestamp=1692407252&version=
2023-08-19 09:07:32     WARN    proxy/proxy.go:209      [CallProxy] invoke service throw exception: reflect: Call using int32 as type int8 , stackTraceElements: []

src-side
2023-08-19 09:07:32     ERROR   proxy_factory/default.go:146    Invoke function error: reflect: Call using int32 as type int8
dubbo.apache.org/dubbo-go/v3/proxy/proxy_factory.callLocalMethod.func1.1
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/proxy/proxy_factory/utils.go:42
runtime.gopanic
        /usr/local/go/src/runtime/panic.go:884
reflect.Value.call
        /usr/local/go/src/reflect/value.go:442
reflect.Value.Call
        /usr/local/go/src/reflect/value.go:370
dubbo.apache.org/dubbo-go/v3/proxy/proxy_factory.callLocalMethod.func1
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/proxy/proxy_factory/utils.go:49
dubbo.apache.org/dubbo-go/v3/proxy/proxy_factory.callLocalMethod
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/proxy/proxy_factory/utils.go:50
dubbo.apache.org/dubbo-go/v3/proxy/proxy_factory.(*ProxyInvoker).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/proxy/proxy_factory/default.go:143
dubbo.apache.org/dubbo-go/v3/filter/graceful_shutdown.(*providerGracefulShutdownFilter).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/filter/graceful_shutdown/provider_filter.go:80
dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper.(*FilterInvoker).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/protocol/protocolwrapper/protocol_filter_wrapper.go:127
dubbo.apache.org/dubbo-go/v3/filter/exec_limit.(*executeLimitFilter).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/filter/exec_limit/filter.go:119
dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper.(*FilterInvoker).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/protocol/protocolwrapper/protocol_filter_wrapper.go:127
dubbo.apache.org/dubbo-go/v3/filter/generic.(*genericServiceFilter).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/filter/generic/service_filter.go:64
dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper.(*FilterInvoker).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/protocol/protocolwrapper/protocol_filter_wrapper.go:127
dubbo.apache.org/dubbo-go/v3/filter/tps.(*tpsLimitFilter).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/filter/tps/filter.go:96
dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper.(*FilterInvoker).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/protocol/protocolwrapper/protocol_filter_wrapper.go:127
dubbo.apache.org/dubbo-go/v3/filter/accesslog.(*Filter).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/filter/accesslog/filter.go:113
dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper.(*FilterInvoker).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/protocol/protocolwrapper/protocol_filter_wrapper.go:127
dubbo.apache.org/dubbo-go/v3/filter/token.(*tokenFilter).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/filter/token/filter.go:94
dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper.(*FilterInvoker).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/protocol/protocolwrapper/protocol_filter_wrapper.go:127
dubbo.apache.org/dubbo-go/v3/filter/metrics.(*Filter).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/filter/metrics/filter.go:55
dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper.(*FilterInvoker).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/protocol/protocolwrapper/protocol_filter_wrapper.go:127
dubbo.apache.org/dubbo-go/v3/filter/echo.(*echoFilter).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/filter/echo/filter.go:64
dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper.(*FilterInvoker).Invoke
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/protocol/protocolwrapper/protocol_filter_wrapper.go:127
dubbo.apache.org/dubbo-go/v3/protocol/dubbo.doHandleRequest
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/protocol/dubbo/dubbo_protocol.go:161
dubbo.apache.org/dubbo-go/v3/protocol/dubbo.(*DubboProtocol).openServer.func1
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/protocol/dubbo/dubbo_protocol.go:128
dubbo.apache.org/dubbo-go/v3/remoting/getty.(*RpcServerHandler).OnMessage
        /Users/wangyuxuan/go/pkg/mod/dubbo.apache.org/dubbo-go/[email protected]/remoting/getty/listener.go:275
github.com/apache/dubbo-getty.(*session).addTask.func1
        /Users/wangyuxuan/go/pkg/mod/github.com/apache/[email protected]/session.go:565
github.com/dubbogo/gost/sync.(*taskPoolSimple).worker
        /Users/wangyuxuan/go/pkg/mod/github.com/dubbogo/[email protected]/sync/task_pool.go:305
runtime.goexit
        /usr/local/go/src/runtime/asm_arm64.s:1172, service: &common.URL{noCopy:common.noCopy{}, baseURL:common.baseURL{Protocol:"dubbo", Location:":20000", Ip:"", Port:"20000", PrimitiveURL:""}, paramsLock:sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:0}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}, params:url.Values{"accesslog":[]string{""}, "app.version":[]string{""}, "application":[]string{"dubbo.io"}, "auth":[]string{""}, "bean.name":[]string{"UserProvider"}, "cluster":[]string{"failover"}, "config.tracing":[]string{""}, "environment":[]string{""}, "execute.limit":[]string{""}, "execute.limit.rejected.handler":[]string{""}, "export":[]string{"true"}, "interface":[]string{"org.apache.dubbo.UserProvider"}, "loadbalance":[]string{"random"}, "max-server-recv-msg-size":[]string{"4mib"}, "max-server-send-msg-size":[]string{""}, "metadata-type":[]string{"local"}, "module":[]string{"sample"}, "name":[]string{"dubbo.io"}, "organization":[]string{"dubbo-go"}, "owner":[]string{"dubbo-go"}, "param.sign":[]string{""}, "pid":[]string{"17878"}, "registry.role":[]string{"3"}, "release":[]string{"dubbo-golang-3.0.4"}, "retries":[]string{""}, "serialization":[]string{""}, "service.filter":[]string{"echo,metrics,token,accesslog,tps,generic_service,execute,pshutdown"}, "side":[]string{"provider"}, "timestamp":[]string{"1692407033"}, "tps.limit.interval":[]string{""}, "tps.limit.rate":[]string{""}, "tps.limit.rejected.handler":[]string{""}, "tps.limit.strategy":[]string{""}, "tps.limiter":[]string{""}, "warmup":[]string{""}}, Path:"/org.apache.dubbo.UserProvider", Username:"", Password:"", Methods:[]string{"EchoInt", "EchoInt8", "GetUser"}, SubURL:(*common.URL)(nil)}

DMwangnima avatar Aug 19 '23 01:08 DMwangnima

Analyzing

For cli-side, dubbo-go make use of Hessian2 to encode int8. After encoding, int8 becomes int32. Refer https://github.com/apache/dubbo-go-hessian2/blob/f0fbe40e207cc5ba0cb76b1dcc0c8db2aee877bf/encode.go#L112

case int8:
    e.buffer = encInt32(e.buffer, int32(val))

For srv-side, dubbo-go uses Hessian2 to decode and get int32. It does not do any compatibility and truncation processing, just pass int32 to user business logic. As a result, it panics.

DMwangnima avatar Aug 19 '23 01:08 DMwangnima

Hi, @tiltwind. This is a hessian-releated issue. Could you take a look at this? Thanks!

justxuewei avatar Aug 23 '23 07:08 justxuewei

@justxuewei In hessian2 protocol, int type (32bit) is the minimal number type, so hessian2 will encode int8 to int32. Then the other side of dubbo rpc will decode and get the int32 value, and use the value as argument to call the function. But the type of the value does not match the type of the parameter,so it panics.

I think the solution is checking whether or not the type of the argument matches the type of the parameter before calling the function, if not matching, try to convert the argument value to a matching one.

And another solution, is changing the definition of the function, using int32 as the type of the parameter.

tiltwind avatar Aug 24 '23 14:08 tiltwind

@justxuewei there is another option.

Change the calling of function from decoder.Decode() to decoder.decToDest(dest)

arg, err = decoder.Decode() 

// change to the following
argDest:= reflect.new(argType)
err = decoder.decToDest(argDest)  // the func decToDest must export first
arg = argDest.Interface()

tiltwind avatar Aug 25 '23 01:08 tiltwind

@tiltwind Thanks for your suggestions!

justxuewei avatar Aug 25 '23 01:08 justxuewei

Convert the arg to the target type:

dec, err = decoder.Decode() 
if argType != dec.Type {
  decValue := hessian.EnsurePackValue(dec)
  argDest:= reflect.new(argType)
  hessian.SetValue(argDest, decValue)
  arg = argDest.Interface()
}
else
{
  arg = dec
}

tiltwind avatar Aug 25 '23 01:08 tiltwind