I've been working on <https://fedoraproject.org/wiki/Changes/Protobuf_5.x/6.x> 
and testing the packages in copr://mochaa/protobuf for the previous two years.
It's unviable to package Protobuf and gRPC as shared libraries without 
introducing bugs in applications dependent on them.

1. Protobuf (and generally their consumers) doesn't account for 
multi-consumer-in-one-process situations when shared.
Example: mozc, https://github.com/google/mozc/issues/387
`libmozc.so`, the input engine, initializes protobuf on start. Its `mozc_tool` 
executable, which doesn't depend on `libmozc.so` (and doesn't have a need to), 
also initializes protobuf on start.
`mozc_tool` uses Qt, so `libmozc.so` will get loaded through the platform input 
plugin. This triggers a crash in `libprotobuf.so`, because it shares the global 
state between `dict_tool` and `libmozc.so`. `mozc_tool` and `libmozc.so` trying 
to register the same proto twice will fail the CHECK().

2. gRPC depends on upb's internal global state.
Although upb's document says it does not have global state, it crashes on tests 
if there are multiple definitions in different object files. This should be an 
ODR violation, but ASan & UBSan both report nothing in this case.
Example A: https://github.com/grpc/grpc/issues/41613
By default, gRPC has its own build of upb with visibility=default and follows 
`BUILD_SHARED_LIBS`. However, Protobuf upstream says upb is not designed for 
shared library usage and forces you to build a static library with 
visibility=hidden.
If we patch gRPC to use the system-provided static upb while building shared 
gRPC, different components as .so will link different copies of upb but still 
assume it's the same one.
Example B:
Although it was intended to be an internal dependency, gRPC's vendored upb 
build exports all symbols.
If an application links to both gRPC and upb independently, symbols from one 
will take precedence over the other, depending on the order of the linker 
command line, and can crash the application because of the aforementioned 
reasons.

There are possibly more quirks I didn't know.

Alternative solutions I could think of are not viable:
- Using the vendored copy of upb. This is prone to the problem in Example B.
- Forcing upb to be built as a shared library with visibility=default. When 
multiple consumers link to the same upb.so in the same process, it may crash.
- Building a shared upb with different symbol names (either through patchelf or 
a wrapper header) *could* do the job, but it relies on our own to make sure the 
behavior is the same as upstream. It will be needed to update every time if 
upstream changes the interface, which is very likely considering upb doesn't 
have a stable interface.
- Provide shared by default, static as a subpackage. Not possible because the 
exported CMake targets can only be one of shared or static.

This situation will likely not change because a) Google does not have a use for 
it. b) Can't afford API breakage.

I'm also strongly against bundling those libraries due to the lack of tests. 
Running the test suite requires enormous setup but can ensure things weren't 
broken, especially on ppc64le and s390x.

There are limitations to a shared library "by design", but mostly due to code 
that doesn't account for shared usage.
Please leave your opinion about this.
-- 
_______________________________________________
devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedoraproject.org/archives/list/[email protected]
Do not reply to spam, report it: 
https://forge.fedoraproject.org/infra/tickets/issues/new

Reply via email to