From 8d1b207c9620d127080db92e2d94edec370d2bf1 Mon Sep 17 00:00:00 2001 From: Shizuo Fujita Date: Thu, 2 Jul 2026 23:23:49 +0900 Subject: [PATCH] Validate Buffer#read_frame argument to prevent SEGV read_frame passed its data argument straight to buffer_read_frame(), which appends to it via rb_str_cat() without any type check. A non-String argument was dereferenced as a char* and crashed the VM instead of raising an error. Coerce data with StringValue() and reject frozen strings with rb_str_modify(), matching the validation already done by #append and #prepend. Add specs covering non-String, frozen String, and to_str coercion cases. --- ext/cool.io/buffer.c | 3 +++ spec/iobuffer_spec.rb | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/ext/cool.io/buffer.c b/ext/cool.io/buffer.c index 8509c7e..cd3f345 100644 --- a/ext/cool.io/buffer.c +++ b/ext/cool.io/buffer.c @@ -352,6 +352,9 @@ Coolio_Buffer_read_frame(VALUE self, VALUE data, VALUE mark) TypedData_Get_Struct(self, struct buffer, &Coolio_Buffer_type, buf); + StringValue(data); + rb_str_modify(data); + if (buffer_read_frame(buf, data, mark_c)) { return Qtrue; } else { diff --git a/spec/iobuffer_spec.rb b/spec/iobuffer_spec.rb index a6cadf3..1f03c84 100644 --- a/spec/iobuffer_spec.rb +++ b/spec/iobuffer_spec.rb @@ -142,6 +142,25 @@ expect(data).to eq "foo\nbarbaz" expect(buffer.to_str).to eq "" end + + it "raises TypeError instead of crashing when data is not a String" do + buffer << "hello world" + expect { buffer.read_frame 12345, " ".ord }.to raise_error(TypeError) + expect { buffer.read_frame nil, " ".ord }.to raise_error(TypeError) + expect { buffer.read_frame [], " ".ord }.to raise_error(TypeError) + end + + it "raises FrozenError when data is a frozen String" do + buffer << "hello world" + expect { buffer.read_frame "frozen".freeze, " ".ord }.to raise_error(FrozenError) + end + + it "coerces objects responding to #to_str" do + buffer << "foo\nbar" + convertible = Object.new + def convertible.to_str; +""; end + expect(buffer.read_frame convertible, "\n".ord).to eq true + end end end