rails/rails — Issue #4777: SQLite adapter does not escape binary data properly
Author: cfeist
Created: 2012-01-31 06:27:08+00:00
State: open

If you create a file with the contents of '%00' and attempt to put it in an sqlite blob the SQLite connector will corrupt the data when it stores it in the database.

I've seen this happen in several versions of Rails, including 3.2.

It is easily reproducible with the standard tests. Just apply the following patch (which adds a file containing '%00'):

SHA: 6e240b5ac2ca0c61507ea57be649e4dfb784c286

Then run 'ruby -Itest test/cases/binary_test.rb' inside the rails/activerecord directory. And you'll see the failure with the following output:

feist@fu:~/rails/activerecord$ ruby -Itest test/cases/binary_test.rb
Using sqlite3 with Identity Map off
Loaded suite test/cases/binary_test
Started
F.
Finished in 0.087877 seconds.

1) Failure:
test_load_save(BinaryTest) [test/cases/binary_test.rb:40]:
Newly assigned data differs from original.
<"%00\n"> expected but was
<"\x00\n">.

2 tests, 9 assertions, 1 failures, 0 errors, 0 skips

Test run options: --seed 51308

The problem is caused because this unnecessary code is still present in rails/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb (which doesn't properly escape binary blobs)

```ruby
def string_to_binary(value)
value.gsub(/\0|\%/n) do |b|
case b
when "\0" then "%00"
when "%" then "%25"
end
end
end

def binary_to_string(value)
if value.respond_to?(:force_encoding) && value.encoding != Encoding::ASCII_8BIT
value = value.force_encoding(Encoding::ASCII_8BIT)
end

value.gsub(/%00|%25/n) do |b|
case b
when "%00" then "\0"
when "%25" then "%"
end
end
end
```

I've removed the offending code (and left in the force_encoding option for binary_to_string) with the commit here:
SHA: b38c9b85b0d334c4f2ff88466f080b77e60d65d3

Please let me know if there is anything I need to fix.