mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
There is a special case where message factories can be confused: if a module
written in C++ with pybind11 links against a self-recursive message, and that
message is part of another message loaded from Python, then the confusion
will happen.
Example:
# This one is also linked into the C++ module.
message SelfRecursive {
optional SelfRecursive self_recursive = 1;
}
# This one is used only in Python and not linked.
message OnlyUsedInPython {
optional SelfRecursive self_recursive = 2;
}
The caching through message_factory::RegisterMessageClass then happens on one
instance of the factory, but traversal with the lookup in another.
This occurs in the pure Python and upb implementations that have their own
default descriptor pools (and thus message factory).
Fix this by using the already passed message factory to registering the
message class to cache.
A test accounts for this case to avoid regressions.
PiperOrigin-RevId: 642551744
44 lines
1.3 KiB
Python
44 lines
1.3 KiB
Python
"""Regression test for self or indirect recursive messages with pybind11."""
|
|
|
|
from google.protobuf.internal import pybind11_test_module
|
|
from google.protobuf.internal import self_recursive_from_py_pb2
|
|
from google3.testing.pybase import unittest
|
|
|
|
|
|
class RecursiveMessagePybind11Test(unittest.TestCase):
|
|
|
|
def test_self_recursive_message_callback(self):
|
|
called = False
|
|
|
|
def callback(
|
|
msg: self_recursive_from_py_pb2.ContainsSelfRecursive,
|
|
) -> None:
|
|
nonlocal called
|
|
called = True
|
|
|
|
# Without proper handling of message factories (in pyext/message.cc New)
|
|
# this will stack overflow
|
|
pybind11_test_module.invoke_callback_on_message(
|
|
callback, self_recursive_from_py_pb2.ContainsSelfRecursive()
|
|
)
|
|
self.assertTrue(called)
|
|
|
|
def test_indirect_recursive_message_callback(self):
|
|
called = False
|
|
|
|
def callback(
|
|
msg: self_recursive_from_py_pb2.ContainsIndirectRecursive,
|
|
) -> None:
|
|
nonlocal called
|
|
called = True
|
|
|
|
# Without proper handling of message factories (in pyext/message.cc New)
|
|
# this will stack overflow
|
|
pybind11_test_module.invoke_callback_on_message(
|
|
callback, self_recursive_from_py_pb2.ContainsIndirectRecursive()
|
|
)
|
|
self.assertTrue(called)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|