Crash in MessageLite::AccessCachedSize due to GetClassData() returning nullptr in custom message class

104 views
Skip to first unread message

Sacheta Saini

unread,
Jun 18, 2025, 4:05:20 AMJun 18
to Protocol Buffers
Description:

Hey team,
I'm Sacheta, one of the maintainers of the labview-grpc (https://github.com/ni/grpc-labview)  repository.

We're attempting to upgrade gRPC from v1.62.0 to v1.70.0 and are encountering a blocking crash due to changes in protobuf's code. We’d really appreciate any guidance or workaround — otherwise, we may be forced to re-architect major parts of our integration to support this upgrade.


Problem Summary:

During a unary gRPC call, we hit a read access violation in MessageLite::AccessCachedSize(). The crash occurs because our override of GetClassData() returns nullptr, and the protobuf runtime does not check for null before dereferencing.


Context:
  • LabVIEW is not a supported language for gRPC and doesn't allow us to run protoc.
  • To integrate with gRPC, we created a custom message class (LVMessage) that manually inherits from google::protobuf::Message and implements our own serialization/parsing logic internally using a few methods from protobuf::Message class.
  • This worked fine in earlier protobuf versions, where GetClassData()  had a default implementation.
  • But now when we tried upgrading to v1.70.0 (protobuf: v3.29.0), GetClassData() seems to have become a pure virtual method required for internal size/cache computations.

What We Tried:
  • We initially provided a minimal override of GetClassData() that returned nullptr. This compiled, but resulted in a crash during serialization:
  • Error:
    • Unhandled exception: read access violation.MessageLite::GetClassData() returned nullptr.
  • Callstack: 
textCopyEditMessageLite::AccessCachedSize()<- MessageLite::GetCachedSize()<- SerializeWithCachedSizesToArray()<- grpc::GenericSerialize()<- grpc::BlockingUnaryCallImpl()

 

  • We then investigated how protoc-generated classes implement GetClassData(), and discovered that they return a pointer to a ClassData structure.
  • However, this structure is:
    • Internally generated
    • Tightly coupled with the protoc output
    • Contains metadata (field descriptors, cached size offsets, parsing tables, etc.) that are not publicly accessible or replicable by hand
  • Due to this, we found it impractical and unsupported to construct a valid ClassData manually.

Questions:
  1. If there’s a supported way to override or stub GetClassData() safely, please advise.
  2. Is it supported to manually subclass Message or MessageLite without using protoc-generated code?
  3. Are there any alternatives  that allow basic serialization without relying on ClassData?
 

Em Rauch

unread,
Jun 23, 2025, 2:26:30 PMJun 23
to Sacheta Saini, Protocol Buffers
> Is it supported to manually subclass Message or MessageLite without using protoc-generated code?

Unfortunately, manually subclassing the baseclasses of gencode really is not an intended usage modality (we should update our documentation to make this more clear here regardless).

Can you clarify a bit why you are doing it here so we can help advise how to best move forward? Generally if you don't want to use a specific Protobuf generated type for your API, the well-lit path is to hook up whatever you'd like as an alternate Codec in gRPC, rather than having gRPC believe it is still using Protobuf and then integrating via some handwritten "Protobuf-gencode-like" types 

--
You received this message because you are subscribed to the Google Groups "Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to protobuf+u...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/protobuf/a3b5842a-a448-473e-9382-f12a57799e46n%40googlegroups.com.

Sacheta Saini

unread,
Jul 1, 2025, 8:58:37 PMJul 1
to Protocol Buffers

Hi EM,

Thanks for the clarification — that helps.

Just to explain our current setup more clearly:

Why we're not using protoc:
We avoided using the protoc compiler because it generates C++ code that must be compiled separately for each platform. Since LabVIEW is platform-independent, we wanted to maintain that property and avoid introducing platform-specific native binaries.

About the LVMessage class:
The purpose of the LVMessage class in the grpc-labview project is to allow LabVIEW—an environment that cannot use the standard protoc code generation workflow—to dynamically construct, serialize, and deserialize Protocol Buffers messages at runtime. We are doing this to provide the marshalling code between LabVIEW Data types and protobuf data types. To support this, we manually inherit from google::protobuf::Message and use select methods from the base class to assist with parsing and serialization. 

Em Rauch

unread,
Jul 2, 2025, 8:04:48 AMJul 2
to Sacheta Saini, Protocol Buffers
I think you'll get more relevant help on a gRPC forum.

I'm still not quite following all of the nuances, but in general if you want to use gRPC and write your own code in the parsing/serializing code, thats fully supported by gRPC and the intended pattern is not to achieve it by inheriting from google::protobuf::Message.

Instead you should use gRPC with your own Codec registered, which is the first class feature you to implement the parse/serialize behavior however you want to. Once you have your own Codec registered in gRPC there's a number of ways to use Protobuf as a helper library to assist in using Protobuf binary wire format encoding depending on the details, including using coded_stream.h and reading/writing the lower level wire format directly, or using DynamicMessage with some descriptor you somehow generated separately, or maybe with a google.protobuf.Struct, or whatever other specific schema that you can establish ahead of time.

Reply all
Reply to author
Forward
0 new messages