This is an automated email from the ASF dual-hosted git repository.

Alanxtl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git


The following commit(s) were added to refs/heads/develop by this push:
     new c32066f97 fix(filter/generic): guard $invoke arg type assertions to 
avoid panic (#3680)
c32066f97 is described below

commit c32066f97c2ff2ae9470b89f11d30a7e3567c019
Author: Lcos <[email protected]>
AuthorDate: Tue Aug 18 23:01:33 2026 +0800

    fix(filter/generic): guard $invoke arg type assertions to avoid panic 
(#3680)
    
    * fix(filter/generic): guard $invoke arg type assertions to avoid panic
    
    IsGenericInvocation only guarantees len(Arguments)==3, not the element
    types. The two bare type assertions in genericServiceFilter.Invoke
    (arg[0].(string) and arg[2].([]hessian.Object)) could panic on a
    malformed or malicious $invoke request. Replace them with comma-ok
    form and return a perrors-wrapped error via RPCResult{Err}, matching
    the existing error-return style in the same function.
    
    Fixes #3679
    
    Signed-off-by: Lcos <[email protected]>
    Signed-off-by: user.email <[email protected]>
    
    * Update filter/generic/service_filter.go
    
    Co-authored-by: Xuetao Li <[email protected]>
    
    ---------
    
    Signed-off-by: Lcos <[email protected]>
    Signed-off-by: user.email <[email protected]>
    Co-authored-by: Xuetao Li <[email protected]>
---
 filter/generic/service_filter.go      | 10 +++++--
 filter/generic/service_filter_test.go | 49 +++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/filter/generic/service_filter.go b/filter/generic/service_filter.go
index 64619b56c..480b82264 100644
--- a/filter/generic/service_filter.go
+++ b/filter/generic/service_filter.go
@@ -76,10 +76,16 @@ func (f *genericServiceFilter) Invoke(ctx context.Context, 
invoker base.Invoker,
        }
 
        // get real invocation info from the generic invocation
-       mtdName := inv.Arguments()[0].(string)
+       mtdName, ok := inv.Arguments()[0].(string)
+       if !ok {
+               return &result.RPCResult{Err: perrors.Errorf("$invoke: arg[0] 
must be string, got %T", inv.Arguments()[0])}
+       }
        // types are not required in dubbo-go, for dubbo-go client to dubbo-go 
server, types could be nil
        types := inv.Arguments()[1]
-       args := inv.Arguments()[2].([]hessian.Object)
+       args, ok := inv.Arguments()[2].([]hessian.Object)
+       if !ok {
+               return &result.RPCResult{Err: perrors.Errorf("$invoke: arg[2] 
must be []hessian.Object, got %T", inv.Arguments()[2])}
+       }
 
        logger.Debugf("[Filter][Generic] received a generic invocation, 
methodName=%s types=%v args=%v", mtdName, types, args)
 
diff --git a/filter/generic/service_filter_test.go 
b/filter/generic/service_filter_test.go
index 4bee9cfd3..4fd3c68f2 100644
--- a/filter/generic/service_filter_test.go
+++ b/filter/generic/service_filter_test.go
@@ -269,6 +269,55 @@ func TestServiceFilter_InvokeWithUnsupportedGenericMode(t 
*testing.T) {
        }
 }
 
+// TestServiceFilter_InvokeRejectsMalformedArgs ensures a $invoke with 
wrong-typed
+// arguments returns an error instead of panicking. See 
service_filter.go:79,82.
+func TestServiceFilter_InvokeRejectsMalformedArgs(t *testing.T) {
+       filter := &genericServiceFilter{}
+
+       cases := []struct {
+               name string
+               args []any
+               want string
+       }{
+               {
+                       name: "arg0-not-string",
+                       args: []any{123, []string{}, []hessian.Object{}},
+                       want: "$invoke: arg[0] must be string, got int",
+               },
+               {
+                       name: "arg0-nil",
+                       args: []any{nil, []string{}, []hessian.Object{}},
+                       want: "$invoke: arg[0] must be string, got <nil>",
+               },
+               {
+                       name: "arg2-not-hessian-slice",
+                       args: []any{"Hello", []string{}, "not-a-slice"},
+                       want: "$invoke: arg[2] must be []hessian.Object, got 
string",
+               },
+               {
+                       name: "arg2-nil",
+                       args: []any{"Hello", []string{}, nil},
+                       want: "$invoke: arg[2] must be []hessian.Object, got 
<nil>",
+               },
+       }
+
+       for _, tc := range cases {
+               t.Run(tc.name, func(t *testing.T) {
+                       inv := invocation.NewRPCInvocation(constant.Generic, 
tc.args,
+                               map[string]any{constant.GenericKey: "true"})
+
+                       ctrl := gomock.NewController(t)
+                       mockInvoker := mock.NewMockInvoker(ctrl)
+                       mockInvoker.EXPECT().Invoke(gomock.Any(), 
gomock.Any()).Times(0)
+
+                       res := filter.Invoke(context.Background(), mockInvoker, 
inv)
+
+                       require.EqualError(t, res.Error(), tc.want)
+                       assert.Nil(t, res.Result())
+               })
+       }
+}
+
 func TestServiceFilter_InvokeWithEmptyGenericModeUsesDefault(t *testing.T) {
        filter := &genericServiceFilter{}
        service := &MockHelloService{}

Reply via email to