# # This file is part of ruby-ffi. # For licensing, see LICENSE.SPECS # require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper")) describe "String tests" do include FFI module StrLibTest extend FFI::Library ffi_lib TestLibrary::PATH attach_function :ptr_ret_pointer, [ :pointer, :int], :string attach_function :string_equals, [ :string, :string ], :int attach_function :string_dummy, [ :string ], :void attach_function :string_null, [ ], :string end it "MemoryPointer#get_string returns a tainted string" do mp = FFI::MemoryPointer.new 1024 mp.put_string(0, "test\0") str = mp.get_string(0) expect(str.tainted?).to be true end it "String returned by a method is tainted" do mp = FFI::MemoryPointer.new :pointer sp = FFI::MemoryPointer.new 1024 sp.put_string(0, "test") mp.put_pointer(0, sp) str = StrLibTest.ptr_ret_pointer(mp, 0) expect(str).to eq("test") expect(str).to be_tainted end it "Poison null byte raises error" do s = "123\0abc" expect { StrLibTest.string_equals(s, s) }.to raise_error end it "Tainted String parameter should throw a SecurityError" do $SAFE = 1 str = "test" str.taint begin expect(LibTest.string_equals(str, str)).to be false rescue SecurityError end end if false it "casts nil as NULL pointer" do expect(StrLibTest.string_dummy(nil)).to be_nil end it "return nil for NULL char*" do expect(StrLibTest.string_null).to be_nil end it "reads an array of strings until encountering a NULL pointer" do strings = ["foo", "bar", "baz", "testing", "ffi"] ptrary = FFI::MemoryPointer.new(:pointer, 6) ary = strings.inject([]) do |a, str| f = FFI::MemoryPointer.new(1024) f.put_string(0, str) a << f end ary.insert(3, nil) ptrary.write_array_of_pointer(ary) expect(ptrary.get_array_of_string(0)).to eq(["foo", "bar", "baz"]) end it "reads an array of strings of the size specified, substituting nil when a pointer is NULL" do strings = ["foo", "bar", "baz", "testing", "ffi"] ptrary = FFI::MemoryPointer.new(:pointer, 6) ary = strings.inject([]) do |a, str| f = FFI::MemoryPointer.new(1024) f.put_string(0, str) a << f end ary.insert(2, nil) ptrary.write_array_of_pointer(ary) expect(ptrary.get_array_of_string(0, 4)).to eq(["foo", "bar", nil, "baz"]) end it "reads an array of strings, taking a memory offset parameter" do strings = ["foo", "bar", "baz", "testing", "ffi"] ptrary = FFI::MemoryPointer.new(:pointer, 5) ary = strings.inject([]) do |a, str| f = FFI::MemoryPointer.new(1024) f.put_string(0, str) a << f end ptrary.write_array_of_pointer(ary) expect(ptrary.get_array_of_string(2 * FFI.type_size(:pointer), 3)).to eq(["baz", "testing", "ffi"]) end it "raises an IndexError when trying to read an array of strings out of bounds" do strings = ["foo", "bar", "baz", "testing", "ffi"] ptrary = FFI::MemoryPointer.new(:pointer, 5) ary = strings.inject([]) do |a, str| f = FFI::MemoryPointer.new(1024) f.put_string(0, str) a << f end ptrary.write_array_of_pointer(ary) expect { ptrary.get_array_of_string(0, 6) }.to raise_error end it "raises an IndexError when trying to read an array of strings using a negative offset" do strings = ["foo", "bar", "baz", "testing", "ffi"] ptrary = FFI::MemoryPointer.new(:pointer, 5) ary = strings.inject([]) do |a, str| f = FFI::MemoryPointer.new(1024) f.put_string(0, str) a << f end ptrary.write_array_of_pointer(ary) expect { ptrary.get_array_of_string(-1) }.to raise_error end end