From 8864deb4d53853ad1974e96bcbb8b75520c630dd Mon Sep 17 00:00:00 2001 From: Doug Fawley Date: Wed, 24 Jul 2024 14:52:45 -0700 Subject: [PATCH] cmd/protoc-gen-go-grpc: test the embedded struct at registration time for proper usage (#7438) --- .../grpc_lb_v1/load_balancer_grpc.pb.go | 17 ++- channelz/grpc_channelz_v1/channelz_grpc.pb.go | 17 ++- cmd/protoc-gen-go-grpc/README.md | 7 ++ cmd/protoc-gen-go-grpc/go.mod | 14 ++- cmd/protoc-gen-go-grpc/go.sum | 14 ++- cmd/protoc-gen-go-grpc/grpc.go | 17 ++- cmd/protoc-gen-go-grpc/unimpl_test.go | 46 +++++++ .../proto/grpc_gcp/handshaker_grpc.pb.go | 17 ++- examples/features/proto/echo/echo_grpc.pb.go | 17 ++- .../helloworld/helloworld_grpc.pb.go | 17 ++- .../routeguide/route_guide_grpc.pb.go | 17 ++- health/grpc_health_v1/health_grpc.pb.go | 17 ++- internal/proto/grpc_lookup_v1/rls_grpc.pb.go | 17 ++- .../grpc_testing/benchmark_service_grpc.pb.go | 17 ++- .../report_qps_scenario_service_grpc.pb.go | 17 ++- interop/grpc_testing/test_grpc.pb.go | 119 ++++++++++++++---- .../grpc_testing/worker_service_grpc.pb.go | 17 ++- .../stress/grpc_testing/metrics_grpc.pb.go | 17 ++- profiling/proto/service_grpc.pb.go | 17 ++- .../grpc_reflection_v1/reflection_grpc.pb.go | 17 ++- .../reflection_grpc.pb.go | 17 ++- reflection/grpc_testing/test_grpc.pb.go | 17 ++- 22 files changed, 412 insertions(+), 77 deletions(-) create mode 100644 cmd/protoc-gen-go-grpc/unimpl_test.go diff --git a/balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go b/balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go index 69cc6c005f82..f31693ec598f 100644 --- a/balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go +++ b/balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go @@ -78,13 +78,17 @@ type LoadBalancerServer interface { BalanceLoad(grpc.BidiStreamingServer[LoadBalanceRequest, LoadBalanceResponse]) error } -// UnimplementedLoadBalancerServer should be embedded to have forward compatible implementations. -type UnimplementedLoadBalancerServer struct { -} +// UnimplementedLoadBalancerServer should be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedLoadBalancerServer struct{} func (UnimplementedLoadBalancerServer) BalanceLoad(grpc.BidiStreamingServer[LoadBalanceRequest, LoadBalanceResponse]) error { return status.Errorf(codes.Unimplemented, "method BalanceLoad not implemented") } +func (UnimplementedLoadBalancerServer) testEmbeddedByValue() {} // UnsafeLoadBalancerServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to LoadBalancerServer will @@ -94,6 +98,13 @@ type UnsafeLoadBalancerServer interface { } func RegisterLoadBalancerServer(s grpc.ServiceRegistrar, srv LoadBalancerServer) { + // If the following call pancis, it indicates UnimplementedLoadBalancerServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&LoadBalancer_ServiceDesc, srv) } diff --git a/channelz/grpc_channelz_v1/channelz_grpc.pb.go b/channelz/grpc_channelz_v1/channelz_grpc.pb.go index 3f5d8ea2c3ce..45b17d291140 100644 --- a/channelz/grpc_channelz_v1/channelz_grpc.pb.go +++ b/channelz/grpc_channelz_v1/channelz_grpc.pb.go @@ -175,9 +175,12 @@ type ChannelzServer interface { GetSocket(context.Context, *GetSocketRequest) (*GetSocketResponse, error) } -// UnimplementedChannelzServer should be embedded to have forward compatible implementations. -type UnimplementedChannelzServer struct { -} +// UnimplementedChannelzServer should be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedChannelzServer struct{} func (UnimplementedChannelzServer) GetTopChannels(context.Context, *GetTopChannelsRequest) (*GetTopChannelsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetTopChannels not implemented") @@ -200,6 +203,7 @@ func (UnimplementedChannelzServer) GetSubchannel(context.Context, *GetSubchannel func (UnimplementedChannelzServer) GetSocket(context.Context, *GetSocketRequest) (*GetSocketResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetSocket not implemented") } +func (UnimplementedChannelzServer) testEmbeddedByValue() {} // UnsafeChannelzServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ChannelzServer will @@ -209,6 +213,13 @@ type UnsafeChannelzServer interface { } func RegisterChannelzServer(s grpc.ServiceRegistrar, srv ChannelzServer) { + // If the following call pancis, it indicates UnimplementedChannelzServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Channelz_ServiceDesc, srv) } diff --git a/cmd/protoc-gen-go-grpc/README.md b/cmd/protoc-gen-go-grpc/README.md index 95635ce768a3..711d20edb2e8 100644 --- a/cmd/protoc-gen-go-grpc/README.md +++ b/cmd/protoc-gen-go-grpc/README.md @@ -19,3 +19,10 @@ E.g.: Note that this is not recommended, and the option is only provided to restore backward compatibility with previously-generated code. + +When embedding the `UnimplementedServer` in a struct that +implements the service, it should be embedded by _value_ instead of as a +_pointer_. If it is embedded as a pointer, it must be assigned to a valid, +non-nil pointer or else unimplemented methods would panic when called. This is +tested at service registration time, and will lead to a panic in +`RegisterServer` if it is not embedded properly. diff --git a/cmd/protoc-gen-go-grpc/go.mod b/cmd/protoc-gen-go-grpc/go.mod index 4583705cc89a..36f8123b7379 100644 --- a/cmd/protoc-gen-go-grpc/go.mod +++ b/cmd/protoc-gen-go-grpc/go.mod @@ -2,4 +2,16 @@ module google.golang.org/grpc/cmd/protoc-gen-go-grpc go 1.21 -require google.golang.org/protobuf v1.34.1 +require ( + google.golang.org/grpc v1.65.0 + google.golang.org/protobuf v1.34.1 +) + +require ( + golang.org/x/net v0.26.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect +) + +replace google.golang.org/grpc => ../.. diff --git a/cmd/protoc-gen-go-grpc/go.sum b/cmd/protoc-gen-go-grpc/go.sum index 33bede0bfd3e..ab56475dacbf 100644 --- a/cmd/protoc-gen-go-grpc/go.sum +++ b/cmd/protoc-gen-go-grpc/go.sum @@ -1,6 +1,12 @@ -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/cmd/protoc-gen-go-grpc/grpc.go b/cmd/protoc-gen-go-grpc/grpc.go index 08529b1966d5..abc216022928 100644 --- a/cmd/protoc-gen-go-grpc/grpc.go +++ b/cmd/protoc-gen-go-grpc/grpc.go @@ -84,9 +84,12 @@ func (serviceGenerateHelper) generateUnimplementedServerType(gen *protogen.Plugi mustOrShould = "should" } // Server Unimplemented struct for forward compatibility. - g.P("// Unimplemented", serverType, " ", mustOrShould, " be embedded to have forward compatible implementations.") - g.P("type Unimplemented", serverType, " struct {") - g.P("}") + g.P("// Unimplemented", serverType, " ", mustOrShould, " be embedded to have") + g.P("// forward compatible implementations.") + g.P("//") + g.P("// NOTE: this should be embedded by value instead of pointer to avoid a nil") + g.P("// pointer dereference when methods are called.") + g.P("type Unimplemented", serverType, " struct {}") g.P() for _, method := range service.Methods { nilArg := "" @@ -100,6 +103,7 @@ func (serviceGenerateHelper) generateUnimplementedServerType(gen *protogen.Plugi if *requireUnimplemented { g.P("func (Unimplemented", serverType, ") mustEmbedUnimplemented", serverType, "() {}") } + g.P("func (Unimplemented", serverType, ") testEmbeddedByValue() {}") g.P() } @@ -306,6 +310,13 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated } serviceDescVar := service.GoName + "_ServiceDesc" g.P("func Register", service.GoName, "Server(s ", grpcPackage.Ident("ServiceRegistrar"), ", srv ", serverType, ") {") + g.P("// If the following call pancis, it indicates Unimplemented", serverType, " was") + g.P("// embedded by pointer and is nil. This will cause panics if an") + g.P("// unimplemented method is ever invoked, so we test this at initialization") + g.P("// time to prevent it from happening at runtime later due to I/O.") + g.P("if t, ok := srv.(interface { testEmbeddedByValue() }); ok {") + g.P("t.testEmbeddedByValue()") + g.P("}") g.P("s.RegisterService(&", serviceDescVar, `, srv)`) g.P("}") g.P() diff --git a/cmd/protoc-gen-go-grpc/unimpl_test.go b/cmd/protoc-gen-go-grpc/unimpl_test.go new file mode 100644 index 000000000000..3828c171191d --- /dev/null +++ b/cmd/protoc-gen-go-grpc/unimpl_test.go @@ -0,0 +1,46 @@ +/* + * + * Copyright 2024 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package main_test + +import ( + "testing" + + "google.golang.org/grpc" + testgrpc "google.golang.org/grpc/interop/grpc_testing" +) + +type unimplEmbeddedByPointer struct { + *testgrpc.UnimplementedTestServiceServer +} + +type unimplEmbeddedByValue struct { + testgrpc.UnimplementedTestServiceServer +} + +func TestUnimplementedEmbedding(t *testing.T) { + // Embedded by value, this should succeed. + testgrpc.RegisterTestServiceServer(grpc.NewServer(), &unimplEmbeddedByValue{}) + defer func() { + if recover() == nil { + t.Fatalf("Expected panic; received none") + } + }() + // Embedded by pointer, this should panic. + testgrpc.RegisterTestServiceServer(grpc.NewServer(), &unimplEmbeddedByPointer{}) +} diff --git a/credentials/alts/internal/proto/grpc_gcp/handshaker_grpc.pb.go b/credentials/alts/internal/proto/grpc_gcp/handshaker_grpc.pb.go index e116cfdd70d6..1f5d870c47d0 100644 --- a/credentials/alts/internal/proto/grpc_gcp/handshaker_grpc.pb.go +++ b/credentials/alts/internal/proto/grpc_gcp/handshaker_grpc.pb.go @@ -87,14 +87,18 @@ type HandshakerServiceServer interface { mustEmbedUnimplementedHandshakerServiceServer() } -// UnimplementedHandshakerServiceServer must be embedded to have forward compatible implementations. -type UnimplementedHandshakerServiceServer struct { -} +// UnimplementedHandshakerServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedHandshakerServiceServer struct{} func (UnimplementedHandshakerServiceServer) DoHandshake(grpc.BidiStreamingServer[HandshakerReq, HandshakerResp]) error { return status.Errorf(codes.Unimplemented, "method DoHandshake not implemented") } func (UnimplementedHandshakerServiceServer) mustEmbedUnimplementedHandshakerServiceServer() {} +func (UnimplementedHandshakerServiceServer) testEmbeddedByValue() {} // UnsafeHandshakerServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to HandshakerServiceServer will @@ -104,6 +108,13 @@ type UnsafeHandshakerServiceServer interface { } func RegisterHandshakerServiceServer(s grpc.ServiceRegistrar, srv HandshakerServiceServer) { + // If the following call pancis, it indicates UnimplementedHandshakerServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&HandshakerService_ServiceDesc, srv) } diff --git a/examples/features/proto/echo/echo_grpc.pb.go b/examples/features/proto/echo/echo_grpc.pb.go index 9fb9f9e660e2..fe48a1f8f1b3 100644 --- a/examples/features/proto/echo/echo_grpc.pb.go +++ b/examples/features/proto/echo/echo_grpc.pb.go @@ -138,9 +138,12 @@ type EchoServer interface { mustEmbedUnimplementedEchoServer() } -// UnimplementedEchoServer must be embedded to have forward compatible implementations. -type UnimplementedEchoServer struct { -} +// UnimplementedEchoServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedEchoServer struct{} func (UnimplementedEchoServer) UnaryEcho(context.Context, *EchoRequest) (*EchoResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UnaryEcho not implemented") @@ -155,6 +158,7 @@ func (UnimplementedEchoServer) BidirectionalStreamingEcho(grpc.BidiStreamingServ return status.Errorf(codes.Unimplemented, "method BidirectionalStreamingEcho not implemented") } func (UnimplementedEchoServer) mustEmbedUnimplementedEchoServer() {} +func (UnimplementedEchoServer) testEmbeddedByValue() {} // UnsafeEchoServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to EchoServer will @@ -164,6 +168,13 @@ type UnsafeEchoServer interface { } func RegisterEchoServer(s grpc.ServiceRegistrar, srv EchoServer) { + // If the following call pancis, it indicates UnimplementedEchoServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Echo_ServiceDesc, srv) } diff --git a/examples/helloworld/helloworld/helloworld_grpc.pb.go b/examples/helloworld/helloworld/helloworld_grpc.pb.go index 24eeab8566ca..3af8b5dbd473 100644 --- a/examples/helloworld/helloworld/helloworld_grpc.pb.go +++ b/examples/helloworld/helloworld/helloworld_grpc.pb.go @@ -75,14 +75,18 @@ type GreeterServer interface { mustEmbedUnimplementedGreeterServer() } -// UnimplementedGreeterServer must be embedded to have forward compatible implementations. -type UnimplementedGreeterServer struct { -} +// UnimplementedGreeterServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedGreeterServer struct{} func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) { return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented") } func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {} +func (UnimplementedGreeterServer) testEmbeddedByValue() {} // UnsafeGreeterServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to GreeterServer will @@ -92,6 +96,13 @@ type UnsafeGreeterServer interface { } func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) { + // If the following call pancis, it indicates UnimplementedGreeterServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Greeter_ServiceDesc, srv) } diff --git a/examples/route_guide/routeguide/route_guide_grpc.pb.go b/examples/route_guide/routeguide/route_guide_grpc.pb.go index 490f6e462d1c..a96d43579af1 100644 --- a/examples/route_guide/routeguide/route_guide_grpc.pb.go +++ b/examples/route_guide/routeguide/route_guide_grpc.pb.go @@ -167,9 +167,12 @@ type RouteGuideServer interface { mustEmbedUnimplementedRouteGuideServer() } -// UnimplementedRouteGuideServer must be embedded to have forward compatible implementations. -type UnimplementedRouteGuideServer struct { -} +// UnimplementedRouteGuideServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedRouteGuideServer struct{} func (UnimplementedRouteGuideServer) GetFeature(context.Context, *Point) (*Feature, error) { return nil, status.Errorf(codes.Unimplemented, "method GetFeature not implemented") @@ -184,6 +187,7 @@ func (UnimplementedRouteGuideServer) RouteChat(grpc.BidiStreamingServer[RouteNot return status.Errorf(codes.Unimplemented, "method RouteChat not implemented") } func (UnimplementedRouteGuideServer) mustEmbedUnimplementedRouteGuideServer() {} +func (UnimplementedRouteGuideServer) testEmbeddedByValue() {} // UnsafeRouteGuideServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to RouteGuideServer will @@ -193,6 +197,13 @@ type UnsafeRouteGuideServer interface { } func RegisterRouteGuideServer(s grpc.ServiceRegistrar, srv RouteGuideServer) { + // If the following call pancis, it indicates UnimplementedRouteGuideServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&RouteGuide_ServiceDesc, srv) } diff --git a/health/grpc_health_v1/health_grpc.pb.go b/health/grpc_health_v1/health_grpc.pb.go index 91b4c7c1b90a..a71597d0fa0f 100644 --- a/health/grpc_health_v1/health_grpc.pb.go +++ b/health/grpc_health_v1/health_grpc.pb.go @@ -149,9 +149,12 @@ type HealthServer interface { Watch(*HealthCheckRequest, grpc.ServerStreamingServer[HealthCheckResponse]) error } -// UnimplementedHealthServer should be embedded to have forward compatible implementations. -type UnimplementedHealthServer struct { -} +// UnimplementedHealthServer should be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedHealthServer struct{} func (UnimplementedHealthServer) Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Check not implemented") @@ -159,6 +162,7 @@ func (UnimplementedHealthServer) Check(context.Context, *HealthCheckRequest) (*H func (UnimplementedHealthServer) Watch(*HealthCheckRequest, grpc.ServerStreamingServer[HealthCheckResponse]) error { return status.Errorf(codes.Unimplemented, "method Watch not implemented") } +func (UnimplementedHealthServer) testEmbeddedByValue() {} // UnsafeHealthServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to HealthServer will @@ -168,6 +172,13 @@ type UnsafeHealthServer interface { } func RegisterHealthServer(s grpc.ServiceRegistrar, srv HealthServer) { + // If the following call pancis, it indicates UnimplementedHealthServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Health_ServiceDesc, srv) } diff --git a/internal/proto/grpc_lookup_v1/rls_grpc.pb.go b/internal/proto/grpc_lookup_v1/rls_grpc.pb.go index 3be9b94b7d31..cb01dea53b0c 100644 --- a/internal/proto/grpc_lookup_v1/rls_grpc.pb.go +++ b/internal/proto/grpc_lookup_v1/rls_grpc.pb.go @@ -71,14 +71,18 @@ type RouteLookupServiceServer interface { mustEmbedUnimplementedRouteLookupServiceServer() } -// UnimplementedRouteLookupServiceServer must be embedded to have forward compatible implementations. -type UnimplementedRouteLookupServiceServer struct { -} +// UnimplementedRouteLookupServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedRouteLookupServiceServer struct{} func (UnimplementedRouteLookupServiceServer) RouteLookup(context.Context, *RouteLookupRequest) (*RouteLookupResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RouteLookup not implemented") } func (UnimplementedRouteLookupServiceServer) mustEmbedUnimplementedRouteLookupServiceServer() {} +func (UnimplementedRouteLookupServiceServer) testEmbeddedByValue() {} // UnsafeRouteLookupServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to RouteLookupServiceServer will @@ -88,6 +92,13 @@ type UnsafeRouteLookupServiceServer interface { } func RegisterRouteLookupServiceServer(s grpc.ServiceRegistrar, srv RouteLookupServiceServer) { + // If the following call pancis, it indicates UnimplementedRouteLookupServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&RouteLookupService_ServiceDesc, srv) } diff --git a/interop/grpc_testing/benchmark_service_grpc.pb.go b/interop/grpc_testing/benchmark_service_grpc.pb.go index 2e7a2d5450f4..9ea3390c3fd0 100644 --- a/interop/grpc_testing/benchmark_service_grpc.pb.go +++ b/interop/grpc_testing/benchmark_service_grpc.pb.go @@ -164,9 +164,12 @@ type BenchmarkServiceServer interface { mustEmbedUnimplementedBenchmarkServiceServer() } -// UnimplementedBenchmarkServiceServer must be embedded to have forward compatible implementations. -type UnimplementedBenchmarkServiceServer struct { -} +// UnimplementedBenchmarkServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedBenchmarkServiceServer struct{} func (UnimplementedBenchmarkServiceServer) UnaryCall(context.Context, *SimpleRequest) (*SimpleResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UnaryCall not implemented") @@ -184,6 +187,7 @@ func (UnimplementedBenchmarkServiceServer) StreamingBothWays(grpc.BidiStreamingS return status.Errorf(codes.Unimplemented, "method StreamingBothWays not implemented") } func (UnimplementedBenchmarkServiceServer) mustEmbedUnimplementedBenchmarkServiceServer() {} +func (UnimplementedBenchmarkServiceServer) testEmbeddedByValue() {} // UnsafeBenchmarkServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to BenchmarkServiceServer will @@ -193,6 +197,13 @@ type UnsafeBenchmarkServiceServer interface { } func RegisterBenchmarkServiceServer(s grpc.ServiceRegistrar, srv BenchmarkServiceServer) { + // If the following call pancis, it indicates UnimplementedBenchmarkServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&BenchmarkService_ServiceDesc, srv) } diff --git a/interop/grpc_testing/report_qps_scenario_service_grpc.pb.go b/interop/grpc_testing/report_qps_scenario_service_grpc.pb.go index aa2dfd2f04e9..4ffbb99f2b11 100644 --- a/interop/grpc_testing/report_qps_scenario_service_grpc.pb.go +++ b/interop/grpc_testing/report_qps_scenario_service_grpc.pb.go @@ -74,15 +74,19 @@ type ReportQpsScenarioServiceServer interface { mustEmbedUnimplementedReportQpsScenarioServiceServer() } -// UnimplementedReportQpsScenarioServiceServer must be embedded to have forward compatible implementations. -type UnimplementedReportQpsScenarioServiceServer struct { -} +// UnimplementedReportQpsScenarioServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedReportQpsScenarioServiceServer struct{} func (UnimplementedReportQpsScenarioServiceServer) ReportScenario(context.Context, *ScenarioResult) (*Void, error) { return nil, status.Errorf(codes.Unimplemented, "method ReportScenario not implemented") } func (UnimplementedReportQpsScenarioServiceServer) mustEmbedUnimplementedReportQpsScenarioServiceServer() { } +func (UnimplementedReportQpsScenarioServiceServer) testEmbeddedByValue() {} // UnsafeReportQpsScenarioServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ReportQpsScenarioServiceServer will @@ -92,6 +96,13 @@ type UnsafeReportQpsScenarioServiceServer interface { } func RegisterReportQpsScenarioServiceServer(s grpc.ServiceRegistrar, srv ReportQpsScenarioServiceServer) { + // If the following call pancis, it indicates UnimplementedReportQpsScenarioServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&ReportQpsScenarioService_ServiceDesc, srv) } diff --git a/interop/grpc_testing/test_grpc.pb.go b/interop/grpc_testing/test_grpc.pb.go index 4f0ae5b97598..8a36c738a385 100644 --- a/interop/grpc_testing/test_grpc.pb.go +++ b/interop/grpc_testing/test_grpc.pb.go @@ -223,9 +223,12 @@ type TestServiceServer interface { mustEmbedUnimplementedTestServiceServer() } -// UnimplementedTestServiceServer must be embedded to have forward compatible implementations. -type UnimplementedTestServiceServer struct { -} +// UnimplementedTestServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedTestServiceServer struct{} func (UnimplementedTestServiceServer) EmptyCall(context.Context, *Empty) (*Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method EmptyCall not implemented") @@ -252,6 +255,7 @@ func (UnimplementedTestServiceServer) UnimplementedCall(context.Context, *Empty) return nil, status.Errorf(codes.Unimplemented, "method UnimplementedCall not implemented") } func (UnimplementedTestServiceServer) mustEmbedUnimplementedTestServiceServer() {} +func (UnimplementedTestServiceServer) testEmbeddedByValue() {} // UnsafeTestServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to TestServiceServer will @@ -261,6 +265,13 @@ type UnsafeTestServiceServer interface { } func RegisterTestServiceServer(s grpc.ServiceRegistrar, srv TestServiceServer) { + // If the following call pancis, it indicates UnimplementedTestServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&TestService_ServiceDesc, srv) } @@ -464,14 +475,18 @@ type UnimplementedServiceServer interface { mustEmbedUnimplementedUnimplementedServiceServer() } -// UnimplementedUnimplementedServiceServer must be embedded to have forward compatible implementations. -type UnimplementedUnimplementedServiceServer struct { -} +// UnimplementedUnimplementedServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedUnimplementedServiceServer struct{} func (UnimplementedUnimplementedServiceServer) UnimplementedCall(context.Context, *Empty) (*Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method UnimplementedCall not implemented") } func (UnimplementedUnimplementedServiceServer) mustEmbedUnimplementedUnimplementedServiceServer() {} +func (UnimplementedUnimplementedServiceServer) testEmbeddedByValue() {} // UnsafeUnimplementedServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to UnimplementedServiceServer will @@ -481,6 +496,13 @@ type UnsafeUnimplementedServiceServer interface { } func RegisterUnimplementedServiceServer(s grpc.ServiceRegistrar, srv UnimplementedServiceServer) { + // If the following call pancis, it indicates UnimplementedUnimplementedServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&UnimplementedService_ServiceDesc, srv) } @@ -572,9 +594,12 @@ type ReconnectServiceServer interface { mustEmbedUnimplementedReconnectServiceServer() } -// UnimplementedReconnectServiceServer must be embedded to have forward compatible implementations. -type UnimplementedReconnectServiceServer struct { -} +// UnimplementedReconnectServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedReconnectServiceServer struct{} func (UnimplementedReconnectServiceServer) Start(context.Context, *ReconnectParams) (*Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Start not implemented") @@ -583,6 +608,7 @@ func (UnimplementedReconnectServiceServer) Stop(context.Context, *Empty) (*Recon return nil, status.Errorf(codes.Unimplemented, "method Stop not implemented") } func (UnimplementedReconnectServiceServer) mustEmbedUnimplementedReconnectServiceServer() {} +func (UnimplementedReconnectServiceServer) testEmbeddedByValue() {} // UnsafeReconnectServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ReconnectServiceServer will @@ -592,6 +618,13 @@ type UnsafeReconnectServiceServer interface { } func RegisterReconnectServiceServer(s grpc.ServiceRegistrar, srv ReconnectServiceServer) { + // If the following call pancis, it indicates UnimplementedReconnectServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&ReconnectService_ServiceDesc, srv) } @@ -709,9 +742,12 @@ type LoadBalancerStatsServiceServer interface { mustEmbedUnimplementedLoadBalancerStatsServiceServer() } -// UnimplementedLoadBalancerStatsServiceServer must be embedded to have forward compatible implementations. -type UnimplementedLoadBalancerStatsServiceServer struct { -} +// UnimplementedLoadBalancerStatsServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedLoadBalancerStatsServiceServer struct{} func (UnimplementedLoadBalancerStatsServiceServer) GetClientStats(context.Context, *LoadBalancerStatsRequest) (*LoadBalancerStatsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetClientStats not implemented") @@ -721,6 +757,7 @@ func (UnimplementedLoadBalancerStatsServiceServer) GetClientAccumulatedStats(con } func (UnimplementedLoadBalancerStatsServiceServer) mustEmbedUnimplementedLoadBalancerStatsServiceServer() { } +func (UnimplementedLoadBalancerStatsServiceServer) testEmbeddedByValue() {} // UnsafeLoadBalancerStatsServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to LoadBalancerStatsServiceServer will @@ -730,6 +767,13 @@ type UnsafeLoadBalancerStatsServiceServer interface { } func RegisterLoadBalancerStatsServiceServer(s grpc.ServiceRegistrar, srv LoadBalancerStatsServiceServer) { + // If the following call pancis, it indicates UnimplementedLoadBalancerStatsServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&LoadBalancerStatsService_ServiceDesc, srv) } @@ -864,9 +908,12 @@ type HookServiceServer interface { mustEmbedUnimplementedHookServiceServer() } -// UnimplementedHookServiceServer must be embedded to have forward compatible implementations. -type UnimplementedHookServiceServer struct { -} +// UnimplementedHookServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedHookServiceServer struct{} func (UnimplementedHookServiceServer) Hook(context.Context, *Empty) (*Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Hook not implemented") @@ -878,6 +925,7 @@ func (UnimplementedHookServiceServer) ClearReturnStatus(context.Context, *Empty) return nil, status.Errorf(codes.Unimplemented, "method ClearReturnStatus not implemented") } func (UnimplementedHookServiceServer) mustEmbedUnimplementedHookServiceServer() {} +func (UnimplementedHookServiceServer) testEmbeddedByValue() {} // UnsafeHookServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to HookServiceServer will @@ -887,6 +935,13 @@ type UnsafeHookServiceServer interface { } func RegisterHookServiceServer(s grpc.ServiceRegistrar, srv HookServiceServer) { + // If the following call pancis, it indicates UnimplementedHookServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&HookService_ServiceDesc, srv) } @@ -1035,9 +1090,12 @@ type XdsUpdateHealthServiceServer interface { mustEmbedUnimplementedXdsUpdateHealthServiceServer() } -// UnimplementedXdsUpdateHealthServiceServer must be embedded to have forward compatible implementations. -type UnimplementedXdsUpdateHealthServiceServer struct { -} +// UnimplementedXdsUpdateHealthServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedXdsUpdateHealthServiceServer struct{} func (UnimplementedXdsUpdateHealthServiceServer) SetServing(context.Context, *Empty) (*Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method SetServing not implemented") @@ -1050,6 +1108,7 @@ func (UnimplementedXdsUpdateHealthServiceServer) SendHookRequest(context.Context } func (UnimplementedXdsUpdateHealthServiceServer) mustEmbedUnimplementedXdsUpdateHealthServiceServer() { } +func (UnimplementedXdsUpdateHealthServiceServer) testEmbeddedByValue() {} // UnsafeXdsUpdateHealthServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to XdsUpdateHealthServiceServer will @@ -1059,6 +1118,13 @@ type UnsafeXdsUpdateHealthServiceServer interface { } func RegisterXdsUpdateHealthServiceServer(s grpc.ServiceRegistrar, srv XdsUpdateHealthServiceServer) { + // If the following call pancis, it indicates UnimplementedXdsUpdateHealthServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&XdsUpdateHealthService_ServiceDesc, srv) } @@ -1183,15 +1249,19 @@ type XdsUpdateClientConfigureServiceServer interface { mustEmbedUnimplementedXdsUpdateClientConfigureServiceServer() } -// UnimplementedXdsUpdateClientConfigureServiceServer must be embedded to have forward compatible implementations. -type UnimplementedXdsUpdateClientConfigureServiceServer struct { -} +// UnimplementedXdsUpdateClientConfigureServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedXdsUpdateClientConfigureServiceServer struct{} func (UnimplementedXdsUpdateClientConfigureServiceServer) Configure(context.Context, *ClientConfigureRequest) (*ClientConfigureResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Configure not implemented") } func (UnimplementedXdsUpdateClientConfigureServiceServer) mustEmbedUnimplementedXdsUpdateClientConfigureServiceServer() { } +func (UnimplementedXdsUpdateClientConfigureServiceServer) testEmbeddedByValue() {} // UnsafeXdsUpdateClientConfigureServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to XdsUpdateClientConfigureServiceServer will @@ -1201,6 +1271,13 @@ type UnsafeXdsUpdateClientConfigureServiceServer interface { } func RegisterXdsUpdateClientConfigureServiceServer(s grpc.ServiceRegistrar, srv XdsUpdateClientConfigureServiceServer) { + // If the following call pancis, it indicates UnimplementedXdsUpdateClientConfigureServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&XdsUpdateClientConfigureService_ServiceDesc, srv) } diff --git a/interop/grpc_testing/worker_service_grpc.pb.go b/interop/grpc_testing/worker_service_grpc.pb.go index de04fd006b17..9a595038fc99 100644 --- a/interop/grpc_testing/worker_service_grpc.pb.go +++ b/interop/grpc_testing/worker_service_grpc.pb.go @@ -145,9 +145,12 @@ type WorkerServiceServer interface { mustEmbedUnimplementedWorkerServiceServer() } -// UnimplementedWorkerServiceServer must be embedded to have forward compatible implementations. -type UnimplementedWorkerServiceServer struct { -} +// UnimplementedWorkerServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedWorkerServiceServer struct{} func (UnimplementedWorkerServiceServer) RunServer(grpc.BidiStreamingServer[ServerArgs, ServerStatus]) error { return status.Errorf(codes.Unimplemented, "method RunServer not implemented") @@ -162,6 +165,7 @@ func (UnimplementedWorkerServiceServer) QuitWorker(context.Context, *Void) (*Voi return nil, status.Errorf(codes.Unimplemented, "method QuitWorker not implemented") } func (UnimplementedWorkerServiceServer) mustEmbedUnimplementedWorkerServiceServer() {} +func (UnimplementedWorkerServiceServer) testEmbeddedByValue() {} // UnsafeWorkerServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to WorkerServiceServer will @@ -171,6 +175,13 @@ type UnsafeWorkerServiceServer interface { } func RegisterWorkerServiceServer(s grpc.ServiceRegistrar, srv WorkerServiceServer) { + // If the following call pancis, it indicates UnimplementedWorkerServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&WorkerService_ServiceDesc, srv) } diff --git a/interop/stress/grpc_testing/metrics_grpc.pb.go b/interop/stress/grpc_testing/metrics_grpc.pb.go index 7d18e153bd63..a57de111efcd 100644 --- a/interop/stress/grpc_testing/metrics_grpc.pb.go +++ b/interop/stress/grpc_testing/metrics_grpc.pb.go @@ -104,9 +104,12 @@ type MetricsServiceServer interface { mustEmbedUnimplementedMetricsServiceServer() } -// UnimplementedMetricsServiceServer must be embedded to have forward compatible implementations. -type UnimplementedMetricsServiceServer struct { -} +// UnimplementedMetricsServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedMetricsServiceServer struct{} func (UnimplementedMetricsServiceServer) GetAllGauges(*EmptyMessage, grpc.ServerStreamingServer[GaugeResponse]) error { return status.Errorf(codes.Unimplemented, "method GetAllGauges not implemented") @@ -115,6 +118,7 @@ func (UnimplementedMetricsServiceServer) GetGauge(context.Context, *GaugeRequest return nil, status.Errorf(codes.Unimplemented, "method GetGauge not implemented") } func (UnimplementedMetricsServiceServer) mustEmbedUnimplementedMetricsServiceServer() {} +func (UnimplementedMetricsServiceServer) testEmbeddedByValue() {} // UnsafeMetricsServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to MetricsServiceServer will @@ -124,6 +128,13 @@ type UnsafeMetricsServiceServer interface { } func RegisterMetricsServiceServer(s grpc.ServiceRegistrar, srv MetricsServiceServer) { + // If the following call pancis, it indicates UnimplementedMetricsServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&MetricsService_ServiceDesc, srv) } diff --git a/profiling/proto/service_grpc.pb.go b/profiling/proto/service_grpc.pb.go index eba4069b7bf8..3c9957564c16 100644 --- a/profiling/proto/service_grpc.pb.go +++ b/profiling/proto/service_grpc.pb.go @@ -93,9 +93,12 @@ type ProfilingServer interface { GetStreamStats(context.Context, *GetStreamStatsRequest) (*GetStreamStatsResponse, error) } -// UnimplementedProfilingServer should be embedded to have forward compatible implementations. -type UnimplementedProfilingServer struct { -} +// UnimplementedProfilingServer should be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedProfilingServer struct{} func (UnimplementedProfilingServer) Enable(context.Context, *EnableRequest) (*EnableResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Enable not implemented") @@ -103,6 +106,7 @@ func (UnimplementedProfilingServer) Enable(context.Context, *EnableRequest) (*En func (UnimplementedProfilingServer) GetStreamStats(context.Context, *GetStreamStatsRequest) (*GetStreamStatsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetStreamStats not implemented") } +func (UnimplementedProfilingServer) testEmbeddedByValue() {} // UnsafeProfilingServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ProfilingServer will @@ -112,6 +116,13 @@ type UnsafeProfilingServer interface { } func RegisterProfilingServer(s grpc.ServiceRegistrar, srv ProfilingServer) { + // If the following call pancis, it indicates UnimplementedProfilingServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Profiling_ServiceDesc, srv) } diff --git a/reflection/grpc_reflection_v1/reflection_grpc.pb.go b/reflection/grpc_reflection_v1/reflection_grpc.pb.go index f633e64a1382..985f3481046f 100644 --- a/reflection/grpc_reflection_v1/reflection_grpc.pb.go +++ b/reflection/grpc_reflection_v1/reflection_grpc.pb.go @@ -82,13 +82,17 @@ type ServerReflectionServer interface { ServerReflectionInfo(grpc.BidiStreamingServer[ServerReflectionRequest, ServerReflectionResponse]) error } -// UnimplementedServerReflectionServer should be embedded to have forward compatible implementations. -type UnimplementedServerReflectionServer struct { -} +// UnimplementedServerReflectionServer should be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedServerReflectionServer struct{} func (UnimplementedServerReflectionServer) ServerReflectionInfo(grpc.BidiStreamingServer[ServerReflectionRequest, ServerReflectionResponse]) error { return status.Errorf(codes.Unimplemented, "method ServerReflectionInfo not implemented") } +func (UnimplementedServerReflectionServer) testEmbeddedByValue() {} // UnsafeServerReflectionServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ServerReflectionServer will @@ -98,6 +102,13 @@ type UnsafeServerReflectionServer interface { } func RegisterServerReflectionServer(s grpc.ServiceRegistrar, srv ServerReflectionServer) { + // If the following call pancis, it indicates UnimplementedServerReflectionServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&ServerReflection_ServiceDesc, srv) } diff --git a/reflection/grpc_reflection_v1alpha/reflection_grpc.pb.go b/reflection/grpc_reflection_v1alpha/reflection_grpc.pb.go index 7d9ad63066aa..2e893cc336f4 100644 --- a/reflection/grpc_reflection_v1alpha/reflection_grpc.pb.go +++ b/reflection/grpc_reflection_v1alpha/reflection_grpc.pb.go @@ -79,13 +79,17 @@ type ServerReflectionServer interface { ServerReflectionInfo(grpc.BidiStreamingServer[ServerReflectionRequest, ServerReflectionResponse]) error } -// UnimplementedServerReflectionServer should be embedded to have forward compatible implementations. -type UnimplementedServerReflectionServer struct { -} +// UnimplementedServerReflectionServer should be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedServerReflectionServer struct{} func (UnimplementedServerReflectionServer) ServerReflectionInfo(grpc.BidiStreamingServer[ServerReflectionRequest, ServerReflectionResponse]) error { return status.Errorf(codes.Unimplemented, "method ServerReflectionInfo not implemented") } +func (UnimplementedServerReflectionServer) testEmbeddedByValue() {} // UnsafeServerReflectionServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ServerReflectionServer will @@ -95,6 +99,13 @@ type UnsafeServerReflectionServer interface { } func RegisterServerReflectionServer(s grpc.ServiceRegistrar, srv ServerReflectionServer) { + // If the following call pancis, it indicates UnimplementedServerReflectionServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&ServerReflection_ServiceDesc, srv) } diff --git a/reflection/grpc_testing/test_grpc.pb.go b/reflection/grpc_testing/test_grpc.pb.go index 6d8e2cd0679b..5c7b698b3ee5 100644 --- a/reflection/grpc_testing/test_grpc.pb.go +++ b/reflection/grpc_testing/test_grpc.pb.go @@ -85,9 +85,12 @@ type SearchServiceServer interface { mustEmbedUnimplementedSearchServiceServer() } -// UnimplementedSearchServiceServer must be embedded to have forward compatible implementations. -type UnimplementedSearchServiceServer struct { -} +// UnimplementedSearchServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedSearchServiceServer struct{} func (UnimplementedSearchServiceServer) Search(context.Context, *SearchRequest) (*SearchResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Search not implemented") @@ -96,6 +99,7 @@ func (UnimplementedSearchServiceServer) StreamingSearch(grpc.BidiStreamingServer return status.Errorf(codes.Unimplemented, "method StreamingSearch not implemented") } func (UnimplementedSearchServiceServer) mustEmbedUnimplementedSearchServiceServer() {} +func (UnimplementedSearchServiceServer) testEmbeddedByValue() {} // UnsafeSearchServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to SearchServiceServer will @@ -105,6 +109,13 @@ type UnsafeSearchServiceServer interface { } func RegisterSearchServiceServer(s grpc.ServiceRegistrar, srv SearchServiceServer) { + // If the following call pancis, it indicates UnimplementedSearchServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&SearchService_ServiceDesc, srv) }