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:
parent
4f9625f877
commit
1100288eba
|
@ -342,15 +342,15 @@ static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
oldLen = RSTRING_LEN(str);
|
oldLen = RSTRING_LEN(str);
|
||||||
char escaped[(oldLen*2)+1];
|
newStr = rb_str_new(0, oldLen*2+1);
|
||||||
|
|
||||||
REQUIRE_OPEN_DB(client);
|
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) {
|
if (newLen == oldLen) {
|
||||||
// no need to return a new ruby string if nothing changed
|
// no need to return a new ruby string if nothing changed
|
||||||
return str;
|
return str;
|
||||||
} else {
|
} else {
|
||||||
newStr = rb_str_new(escaped, newLen);
|
rb_str_resize(newStr, newLen);
|
||||||
#ifdef HAVE_RUBY_ENCODING_H
|
#ifdef HAVE_RUBY_ENCODING_H
|
||||||
rb_enc_associate(newStr, conn_enc);
|
rb_enc_associate(newStr, conn_enc);
|
||||||
if (default_internal_enc) {
|
if (default_internal_enc) {
|
||||||
|
|
|
@ -144,6 +144,18 @@ describe Mysql2::Client do
|
||||||
@client.escape(str).object_id.should eql(str.object_id)
|
@client.escape(str).object_id.should eql(str.object_id)
|
||||||
end
|
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
|
it "should respond to #info" do
|
||||||
@client.should respond_to(:info)
|
@client.should respond_to(:info)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue