protocolbuffers/protobuf

Protobuf's constant initialization is not actually constant on Windows

Open

#10.159 aperta il 21 giu 2022

Vedi su GitHub
 (20 commenti) (5 reazioni) (2 assegnatari)C++ (16.128 fork)batch import
c++help wantedwait for user actionwindows

Metriche repository

Star
 (71.223 star)
Metriche merge PR
 (Merge medio 2g 11h) (185 PR mergiate in 30 g)

Descrizione

What version of protobuf and what language are you using? Version: main Language: C++

What operating system (Linux, Windows, ...) and version? Windows 10 20H2

What runtime / compiler are you using (e.g., python version or gcc version) clang-cl from Visual Studio 2019

What did you do? Steps to reproduce the behavior:

  1. Install Visual Studio 2019
  2. In the installer, include "C++ Clang tools for Windows"
  3. git clone https://github.com/protocolbuffers/protobuf.git
  4. cd protobuf
  5. git submodule update --init --recursive
  6. cmake -B build-shared -D BUILD_SHARED_LIBS=1 -T ClangCL
  7. cmake --build build-shared --parallel 16

What did you expect to see The build should succeed

What did you see instead? The build fails with errors like:

...\protobuf\src\google\protobuf\compiler\plugin.pb.cc(75,31): message : required by 'require_constant_initializatio
n' attribute here [...\protobuf\build-shared\libprotoc.vcxproj]
...\protobuf\src\google/protobuf/port_def.inc(656,30): message : expanded from macro 'PROTOBUF_CONSTINIT' [...\pr
otobuf\build-shared\libprotoc.vcxproj]
...\protobuf\src\google\protobuf\compiler\plugin.pb.cc(91,125): error : variable does not have a constant initialize
r [...\protobuf\build-shared\libprotoc.vcxproj]

Anything else we should know about your project / environment This was an issue updating protobuf in Chromium. We've applied a workaround by patching out the PROTOBUF_CONSTINIT in some configurations, but the root problem is that protobuf's new constant initialization was not actually cross-platform, and relies on assumption that aren't actually universally true.

While, for the repro steps, I used clang-cl, this is only because protobuf has a pre-C++20 version of PROTOBUF_CONSTINIT for Clang, [[clang::require_constant_initialization]]. When protobuf moves to C++20, I expect it will have the same problem on MSVC.

This happens because the protobuf constant initialization assumes it can reference &fixed_address_empty_string. fixed_address_empty_string lives in the protobuf dll, so when referenced from another dll or exe, is __declspec(dllimport). But pointers to dllimport variables require a static initializer on Windows. See https://godbolt.org/z/5rn4xWrhE. As I understand it, Windows does not have a suitable relocation to express this.

As a result, the new constant initialization actually requires a per-message static initializer, which trips PROTOBUF_CONSTINIT and fails to build.

Guida contributor