`gem install google-protobuf --platform ruby` fails on Windows with the native mswin toolchain (`x64-mswin64_140`, `cl.exe` and `nmake`). `Init_protobuf_c` in `protobuf.c` is annotated with the GCC-style `__attribute__((visibility("default")))`, which `cl.exe` cannot parse and rejects with a cascade of C2143/C2091 syntax errors. In addition, `extconf.rb` passes GCC-only flags (`-std=gnu99`, `-O3`, `-fvisibility=hidden`) that `cl.exe` does not understand.
This change replaces the attribute with Ruby's portable `RUBY_FUNC_EXPORTED` macro, which expands to `extern __declspec(dllexport)` under MSVC and to `__attribute__((__visibility__("default"))) extern` under GCC/Clang, so the symbol stays exported when the extension is built with `-fvisibility=hidden`. It also gives mswin its own `$CFLAGS` branch. `-std:c11` is required there because the MSVC atomics fallback in upb only uses its `_Generic` based implementation when `__STDC_VERSION__` is at least 201112L. The pre-C11 fallback returns `void*` from `upb_Atomic_Load`, and mswin Ruby compiles extensions with `-we4047` by default, which turns those conversion warnings into hard errors.
Verified on Windows 11 with Ruby 4.0.5 (`x64-mswin64_140`) and Visual Studio 2022 Build Tools (MSVC 14.51). Building the extension in-tree succeeds, and a gem built from the released 4.35.1 sources with this patch applied installs successfully and passes a `Struct` and `Timestamp` encode/decode round-trip. Precompiled `x64-mingw-ucrt` gems are unaffected because MinGW keeps using the existing GCC branch.
Generated with [Claude Code](https://claude.com/claude-code)
Closes#28433
COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/28433 from hsbt:claude/elated-goldwasser-3862b4 7d533bab6c
PiperOrigin-RevId: 963158243
Fixes#29023.
`Map#[]=` and `Message.new(map_field: {...})` build the map key as a `upb_StringView`
aliasing a Ruby String, then convert the value before `upb_Map_Set` copies the key. The
value conversion allocates, so it can trigger GC inside that window.
The aliased String is frequently a **temporary**: `Convert_RubyToUpb` replaces the caller's
object when the key is a Symbol (via `to_s`) or a String not already tagged UTF-8 (via
`Convert_CheckStringUtf8`), and nothing references the result once it returns. When GC
collects it, the freed block goes straight back to the next `upb_Arena_Malloc`, which
memcpys the *value* into it — leaving a silently corrupted key holding unrelated heap bytes,
tagged UTF-8 while containing invalid UTF-8, which then propagates into `encode`/`to_json`.
## The fix
Pass the arena at both insertion sites, so the key is copied before anything can allocate.
The lookup paths (`Map_index`, `Map_has_key`, `Map_delete`) keep the `NULL` fast path — they
consume the key immediately with no allocation in between, which is exactly the precondition
`Convert_StringData`'s comment describes. I reworded that comment, since it read as though
the aliasing were unconditionally safe; it holds for three of its five callers and not for
the two that insert.
Cost is one arena allocation per insert for string-typed keys. Non-string keys don't reach
`Convert_StringData` at all.
## Trigger
Needs both:
- a key that is a **Symbol**, or a String not already tagged UTF-8 — `ASCII-8BIT` is the
common case for anything read from a socket, a file, `Marshal`, or `String#pack`; and
- a value whose conversion allocates (a Symbol, or a non-UTF-8 String).
Plain UTF-8 keys are unaffected, which is presumably why this has gone unnoticed.
## Verification
Reproduces under **ordinary GC**, no `GC.stress` required — one corrupted key across 150k
iterations (0/50k, 0/50k, 1/50k), versus 100/100 with stress. That second number is an
existence proof rather than a rate.
Added regression tests to `ruby/tests/gc_test.rb` covering string keys, Symbol keys, and the
map-field kwarg path. Verified red/green against the same tree:
| ext build | new tests |
|---|---|
| unpatched `main` | 3 tests, **3 failures** |
| with this change | 3 tests, 300 assertions, **0 failures** |
Full Ruby suite green with the change on ruby 4.0.6 / arm64-darwin — `basic.rb` (133 tests,
157,864 assertions), `basic_proto2.rb` (93), `repeated_field_test.rb` (40),
`encode_decode_test.rb`, `memory_test.rb`, `object_cache_test.rb`, `well_known_types_test.rb`,
`service_test.rb`, `oom_test.rb`, `multi_level_nesting_test.rb` — 0 failures, 0 errors.
Reported separately via the channel in `SECURITY.md`, since this is a memory-safety issue in
an OT0 repository.
Closes#29026
COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/29026 from jeremy:ruby-map-key-use-after-free e11cc7dfe2
PiperOrigin-RevId: 961236703
Fixes#28927
I ran into this while packaging the OpenTelemetry Ruby auto-instrumentation as a prebuilt gem bundle (see #28927 for the full write up). The tl;dr: `bigdecimal` is only used by the test suite, so it only needs to be a development dependency. The only references are:
8baed752ce/ruby/tests/common_tests.rb (L9)8baed752ce/ruby/tests/common_tests.rb (L1708)
As a runtime dependency it causes pain for anyone vendoring the gem. `bigdecimal` is a native extension with no precompiled build, so it has to be compiled from source for each Ruby ABI, making it the one gem that stops a prebuilt bundle from working across Ruby versions, despite never being loaded at runtime.
This PR moves `bigdecimal` from a runtime to a development dependency. For consistency it also moves `bigdecimal` into the `test` group in the Gemfile, since that's the only environment that needs it.
Closes#28928
COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/28928 from mwear:ruby-bigdecimal-dev-dependency 6fb8ee4fad
PiperOrigin-RevId: 957450742
* `protoc`: Included in zips alongside binary
* Java: Generated classes have been added to the Maven `util` artifact
* Ruby: Generated classes have been added to gems
* CMake: `.proto` files are included in installation
PiperOrigin-RevId: 957382561
Prior to this change, the custom alloc function used with arenas would internally longjmp on allocation failure, which would then leak memory (as upb does not expect or permit longjmp from an alloc function, and has no way to free intermediate allocations).
PiperOrigin-RevId: 955635829