THRIFT-6138: Give Ruby memory buffers private ownership - #3702
Conversation
There was a problem hiding this comment.
Pull request overview
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Updates Ruby MemoryBufferTransport to privately own its internal buffer by duplicating constructor input before normalizing encoding, preventing unexpected caller/transport side effects and allowing frozen inputs.
Changes:
- Duplicate constructor-provided buffers before forcing binary encoding.
- Update specs to validate private ownership behavior and frozen-input usability.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| lib/rb/lib/thrift/transport/memory_buffer_transport.rb | Make constructor duplicate input string before binary-encoding to ensure private mutable storage. |
| lib/rb/spec/base_transport_spec.rb | Replace shared-buffer spec with new expectations for private ownership and frozen-input behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Client: rb Co-Authored-By: OpenAI Codex (GPT-5.6) <codex@openai.com>
75ff595 to
f75f4f0
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (2)
lib/rb/spec/base_transport_spec.rb:317
- The expectation at line 317 uses
.bon the expected value, buteqonly checks==, which does not reliably assert the returned string’s encoding (ASCII-8BIT vs UTF-8 can still compare equal for compatible byte sequences). If the intent is to verify the transport returns binary-encoded data, add an explicit assertion on the returned value’s.encoding(and keep the byte/content assertion separately).
expect(source.encoding).to eq(Encoding::UTF_8)
source.replace("caller changed")
@buffer.write("!")
expect(source).to eq("caller changed")
expect(@buffer.read(@buffer.available)).to eq("this is a test!".b)
lib/rb/lib/thrift/transport/memory_buffer_transport.rb:28
- Calling
dupunconditionally on any non-nilbufferchanges the failure mode for non-String inputs (e.g.,TypeError: can't dup Integer) and may reject objects that are string-like viato_strifBytes.force_binary_encodingpreviously handled them. If this constructor is intended to accept string-like objects, consider coercing viato_str(orString(...)if appropriate) and raising a consistentArgumentErrorfor invalid types before duplicating.
def initialize(buffer = nil)
@buf = buffer ? Bytes.force_binary_encoding(buffer.dup) : Bytes.empty_byte_buffer
Ruby
MemoryBufferTransportcurrently retains a caller-supplied string as its internal storage. Mutating either object can therefore unexpectedly alter the other, frozen input can fail during later writes or resets, and construction can change the caller's string encoding.This change duplicates constructor input before normalizing it to binary encoding. The transport consequently owns a private mutable buffer: caller mutations no longer change unread bytes, transport operations no longer modify the caller's string, and frozen input remains usable.
This deliberately removes the historical shared-buffer behavior. Callers that intentionally treated the original string as a live view of the transport will instead need to read from the transport.
[skip ci]anywhere in the commit message to free up build resources.