avoid stack overflow when escaping large strings

Attempting to escape large, untrusted strings cause stack
overflows (easier under Ruby 1.9 using pthreads) leading to
SystemStackError on small overflows and segmentation faults on
large overflows.  Instead of allocating on the stack, we'll
allocate a string buffer from the heap.

This has the unfortunate effect of reducing escape performance
for common cases, but in my experience SQL escaping isn't much
of a bottleneck.

For reference, Ruby 1.9.2-p0 with pthreads gets a stack size of
512K and the default process stack size is 8MB on both x86 and
x86_64 Linux.
This commit is contained in:
Eric Wong 2010-08-24 04:07:55 +00:00
parent 4f9625f877
commit 1100288eba
2 changed files with 15 additions and 3 deletions

View File

@ -342,15 +342,15 @@ static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
#endif
oldLen = RSTRING_LEN(str);
char escaped[(oldLen*2)+1];
newStr = rb_str_new(0, oldLen*2+1);
REQUIRE_OPEN_DB(client);
newLen = mysql_real_escape_string(client, escaped, StringValuePtr(str), oldLen);
newLen = mysql_real_escape_string(client, RSTRING_PTR(newStr), StringValuePtr(str), oldLen);
if (newLen == oldLen) {
// no need to return a new ruby string if nothing changed
return str;
} else {
newStr = rb_str_new(escaped, newLen);
rb_str_resize(newStr, newLen);
#ifdef HAVE_RUBY_ENCODING_H
rb_enc_associate(newStr, conn_enc);
if (default_internal_enc) {

View File

@ -144,6 +144,18 @@ describe Mysql2::Client do
@client.escape(str).object_id.should eql(str.object_id)
end
it "#escape should not overflow the thread stack" do
lambda {
Thread.new { @client.escape("'" * 256 * 1024) }.join
}.should_not raise_error(SystemStackError)
end
it "#escape should not overflow the process stack" do
lambda {
Thread.new { @client.escape("'" * 1024 * 1024 * 4) }.join
}.should_not raise_error(SystemStackError)
end
it "should respond to #info" do
@client.should respond_to(:info)
end