Skip to content

[ruby] grpc protoc plugin could generate broken request/response namespaces #23746

@dazuma

Description

@dazuma

What version of gRPC and what language are you using?

gRPC 1.30.2 on Ruby on Ubuntu bionic. Specifically the protoc plugin distributed as part of https://rubygems.org/gems/grpc-tools/versions/1.30.2

What did you do?

Running the grpc protoc plugin on the grafeas.v1 proto (as part of client library codegen).

The result looks like this

An excerpt with comments removed:

require 'grpc'
require 'grafeas/v1/grafeas_pb'

module Grafeas
  module V1
    module Grafeas
      class Service

        include GRPC::GenericService

        self.marshal_class_method = :encode
        self.unmarshal_class_method = :decode
        self.service_name = 'grafeas.v1.Grafeas'

        rpc :GetOccurrence, Grafeas::V1::GetOccurrenceRequest, Grafeas::V1::Occurrence  # <-- error here

# and additional lines...

The indicated line results in an error:

/path/to/grafeas_services_pb.rb:48:in `<class:Service>': uninitialized constant Grafeas::V1::Grafeas::V1 (NameError)
Did you mean?  Grafeas::V1

This is happening because when Ruby does constant lookup on Grafeas::V1::GetOccurrenceRequest, it searches lexically up the namespace chain for Grafeas and instead of the toplevel Grafeas module, the first one it finds is actually the Grafeas::V1::Grafeas module.

The fix is to prefix the namespace with :: which tells Ruby to search from the toplevel instead. That is, the above line should look like:

        rpc :GetOccurrence, ::Grafeas::V1::GetOccurrenceRequest, ::Grafeas::V1::Occurrence

This is always safe to do whenever you are providing a "fully qualified" name, as you are above. (In fact, for generated code, it is good practice always to do it, specifically to avoid this bug.)

Note that this is probably a regression from #23501 which, it seems, changed the behavior so that fully-qualified request and response class names are always generated.

grpc 1.30.1 generates:

# Works because GetOccurrenceRequest is a "relative" class name
# i.e. it resolves correctly to Grafeas::V1::GetOccurrenceRequest
# and Grafeas::V1::Occurrence.
# (However, this version suffered from #23490 which was tangetially related)
rpc :GetOccurrence, GetOccurrenceRequest, Occurrence

grpc 1.30.2 generates:

# Does not work. Resolves incorrectly to 
# Grafeas::V1::Grafeas::V1::GetOccurrenceRequest and
# Grafeas::V1::Grafeas::V1::Occurrence
rpc :GetOccurrence, Grafeas::V1::GetOccurrenceRequest, Grafeas::V1::Occurrence

What we want:

# Explicitly do absolute rather than relative lookup. Resolves correctly to 
# Grafeas::V1::GetOccurrenceRequest and Grafeas::V1::Occurrence
rpc :GetOccurrence, ::Grafeas::V1::GetOccurrenceRequest, ::Grafeas::V1::Occurrence

/cc @stanley-cheung

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions