dongsi073898
2019-08-04 05:10
浏览 377
已采纳

grpc:使用oneof会导致无效的内存地址或nil指针取消引用

I'm trying to send a proto3 struct to a gRPC server with Go. The struct has an oneof type, which I seem to populate fine. When sending the message to my gRPC client, I get a panic about invalid memory address or nil pointer reference.

I have the proto definition (full file is at https://github.com/MovingGauteng/geofancy-rs/blob/master/proto/geofancy.proto:

# proto3

message Document {
  string collection = 1;
  string id = 2;
  oneof geo {
    Point point = 4;
    LineString line = 5;
    Bounds bounds = 6;
    string geojson = 7;
  }
}

message Point { Coordinate coord = 1; }

message Coordinate {
  double lat = 1;
  double lng = 2;
}

The Go code is:

// create a coordinate
coord := geofancy.Coordinate{
  Lat: 10.2,
  Lng: -15.3,
}
// add coordinate to a point
point := geofancy.Point{
  Coord: &coord,
}

// these statements print valid data
log.Printf("Coord: %v", coord)
log.Printf("Point: %v", point)

// create document, add point to the oneof field
document := geofancy.Document{
  Collection:   "some-collection",
  Id:           "some-id",
  Geo:          &point,
}

// this prints the document correctly
log.Printf("Document: %v", document)

// connect to client
var opts []grpc.DialOption
opts = append(opts, grpc.WithInsecure())
var err error
conn, err := grpc.Dial("my-server:port", opts...)
if err != nil {
    log.Fatalf("fail to dial: %v", err)
}
defer conn.Close()
client := geofancy.NewGeofancyServiceClient(conn)

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// this panics each time
res, err := client.SetDocument(ctx, &document)

The stack trace looks like:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x10 pc=0x54d731]

goroutine 1 [running]:
my-project/vendor/github.com/golang/protobuf/proto.makeOneOfMarshaler.func1(0xc000068ce0, 0x0, 0x0)
        D:/projects/golang/src/my-project/vendor/github.com/golang/protobuf/proto/table_marshal.go:2373 +0x131
my-project/vendor/github.com/golang/protobuf/proto.(*marshalInfo).size(0xc0003021c0, 0xc000068cc0, 0xf9ef40)
        D:/projects/golang/src/my-project/vendor/github.com/golang/protobuf/proto/table_marshal.go:183 +0xa8
my-project/vendor/github.com/golang/protobuf/proto.(*InternalMessageInfo).Size(0xf9ef40, 0xae7fa0, 0xc000068cc0, 0x30448c0)
        D:/projects/golang/src/my-project/vendor/github.com/golang/protobuf/proto/table_marshal.go:125 +0x6e
my-project/vendor/my-protos.(*Document).XXX_Size(0xc000068cc0, 0xae7fa0)
        D:/projects/golang/src/my-project/vendor/my-protos/geofancy.pb.go:197 +0x4a
my-project/vendor/github.com/golang/protobuf/proto.(*Buffer).Marshal(0xc0002de698, 0xae7fa0, 0xc000068cc0, 0xc0000363f0, 0xc000068cc0)
        D:/projects/golang/src/my-project/vendor/github.com/golang/protobuf/proto/table_marshal.go:2740 +0x8c
my-project/vendor/google.golang.org/grpc/encoding/proto.marshal(0xa0c520, 0xc000068cc0, 0xc0002de690, 0x0, 0x0, 0xc000006000, 0x99a900, 0x1)        
        D:/projects/golang/src/my-project/vendor/google.golang.org/grpc/encoding/proto/proto.go:59 +0xe9
my-project/vendor/google.golang.org/grpc/encoding/proto.codec.Marshal(0xa0c520, 0xc000068cc0, 0x0, 0x2030000, 0x2030000, 0x30000, 0x20)
        D:/projects/golang/src/my-project/vendor/google.golang.org/grpc/encoding/proto/proto.go:74 +0xb4
my-project/vendor/google.golang.org/grpc.encode(0x3080168, 0xfbc400, 0xa0c520, 0xc000068cc0, 0xc000310020, 0xc000362000, 0x11d0008, 0x0, 0x0)       
        D:/projects/golang/src/my-project/vendor/google.golang.org/grpc/rpc_util.go:543 +0x59
my-project/vendor/google.golang.org/grpc.prepareMsg(0xa0c520, 0xc000068cc0, 0x3080168, 0xfbc400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        D:/projects/golang/src/my-project/vendor/google.golang.org/grpc/stream.go:1501 +0x8c
my-project/vendor/google.golang.org/grpc.(*clientStream).SendMsg(0xc00032e000, 0xa0c520, 0xc000068cc0, 0x0, 0x0)
        D:/projects/golang/src/my-project/vendor/google.golang.org/grpc/stream.go:681 +0x157
my-project/vendor/google.golang.org/grpc.invoke(0xaed320, 0xc000068f60, 0xa42207, 0x25, 0xa0c520, 0xc000068cc0, 0x9e3000, 0xc00003c840, 0xc000065180, 0x0, ...)
        D:/projects/golang/src/my-project/vendor/google.golang.org/grpc/call.go:70 +0xee
my-project/vendor/google.golang.org/grpc.(*ClientConn).Invoke(0xc000065180, 0xaed320, 0xc000068f60, 0xa42207, 0x25, 0xa0c520, 0xc000068cc0, 0x9e3000, 0xc00003c840, 0x0, ...)
        D:/projects/golang/src/my-project/vendor/google.golang.org/grpc/call.go:37 +0x1bb
my-project/vendor/my-protos.(*geofancyServiceClient).SetDocument(0xc000006030, 0xaed320, 0xc000068f60, 0xc000068cc0, 0x0, 0x0, 0x0, 0xc000065180, 0x0, 0x0)
        D:/projects/golang/src/my-project/vendor/my-protos/geofancy.pb.go:925 +0xd9
main.sendMyMessage(0xc0002e4000, 0x77359400)
        D:/projects/golang/src/my-project/main.go:89 +0x685
main.main()
        D:/projects/golang/src/my-project/main.go:117 +0xf4
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • duanli6618 2019-08-21 00:00
    已采纳

    I am surprised your code is compiling. I was so intrigued that I generated the Go code in my environment to understand it.

    The "geofancy.Document" struct cannot receive a Point as a value for the attribute Geo because it expects a generic "Document Geo" (that could be a Document_Point, a Document_LineString, etc...)

    The auto generated code has an interface that you can use in this case.

        // add coordinate to a point
        point := geofancy.Document_Point{
            Point: &geofancy.Point{
                Coord: &coord,
            },
        }
    

    Now your variable point is an struct that implements an interface acceptable by Geo.

    document := geofancy.Document{
      Collection:   "some-collection",
      Id:           "some-id",
      Geo:          &point,
    }
    

    I was not able to compile using your example because the was getting the error:

     cannot use &point (type **geofancy.Point) as type geofancy.isDocument_Geo in field value:
        **geofancy.Point does not implement geofancy.isDocument_Geo (missing geofancy.isDocument_Geo method)```
    
    已采纳该答案
    打赏 评论

相关推荐 更多相似问题