From c7c24f841322528c17714482d150b769d0afcddb Mon Sep 17 00:00:00 2001 From: imarkov <imarkov@tarantool.org> Date: Thu, 22 Feb 2018 11:55:43 +0300 Subject: [PATCH] fio: Fix race condition in fio.read When fio.read from multiple fibers is performed, as fio.read yields before performing actual read operation and ibuf shared among several fibers may be corrupted and read data is mixed. The fix is to create new ibuf for each fio.read call in case buffer is not specified. Closes #3187 --- src/lua/fio.lua | 3 +- test/app/fio.result | 70 +++++++++++++++++++++++++++++++++++++++++++ test/app/fio.test.lua | 29 ++++++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/lua/fio.lua b/src/lua/fio.lua index d48c709b15..73719df90e 100644 --- a/src/lua/fio.lua +++ b/src/lua/fio.lua @@ -40,8 +40,7 @@ fio_methods.read = function(self, buf, size) end if not ffi.istype(const_char_ptr_t, buf) then size = buf or size - tmpbuf = buffer.IBUF_SHARED - tmpbuf:reset() + tmpbuf = buffer.ibuf() buf = tmpbuf:reserve(size) end local res, err = internal.read(self.fh, buf, size) diff --git a/test/app/fio.result b/test/app/fio.result index 0fc8582530..6c4609855f 100644 --- a/test/app/fio.result +++ b/test/app/fio.result @@ -1067,6 +1067,76 @@ fio.unlink(tmpfile) --- - true ... +tmp1 = fio.pathjoin(tmpdir, "tmp1") +--- +... +tmp2= fio.pathjoin(tmpdir, "tmp2") +--- +... +test_run:cmd("setopt delimiter ';'") +--- +- true +... +function write_file(name, odd) + local fh = fio.open(name, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, 0777) + if odd then + fh:write(string.rep('1', 100)) + else + fh:write(string.rep('2', 100)) + end + fh:write(name) + fh:seek(0) + return fh +end; +--- +... +test_run:cmd("setopt delimiter ''"); +--- +- true +... +fh1 = write_file(tmp1) +--- +... +fh2 = write_file(tmp2) +--- +... +fiber = require('fiber') +--- +... +digest = require('digest') +--- +... +str = fh1:read() +--- +... +fh1:seek(0) +--- +- 0 +... +hash = digest.crc32(str) +--- +... +ch = fiber.channel(1) +--- +... +f1 = fiber.create(function() str = fh1:read() ch:put(digest.crc32(str)) end) +--- +... +f2 = fiber.create(function() str = fh2:read() end) +--- +... +ch:get() == hash +--- +- true +... +fio.unlink(tmp1) +--- +- true +... +fio.unlink(tmp2) +--- +- true +... fio.rmdir(tmpdir) --- - true diff --git a/test/app/fio.test.lua b/test/app/fio.test.lua index cd0bc16c65..0850413d9b 100644 --- a/test/app/fio.test.lua +++ b/test/app/fio.test.lua @@ -342,4 +342,33 @@ fio.path.lexists(link) fio.unlink(link) fio.unlink(tmpfile) +tmp1 = fio.pathjoin(tmpdir, "tmp1") +tmp2= fio.pathjoin(tmpdir, "tmp2") +test_run:cmd("setopt delimiter ';'") +function write_file(name, odd) + local fh = fio.open(name, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, 0777) + if odd then + fh:write(string.rep('1', 100)) + else + fh:write(string.rep('2', 100)) + end + fh:write(name) + fh:seek(0) + return fh +end; +test_run:cmd("setopt delimiter ''"); +fh1 = write_file(tmp1) +fh2 = write_file(tmp2) +fiber = require('fiber') +digest = require('digest') +str = fh1:read() +fh1:seek(0) +hash = digest.crc32(str) +ch = fiber.channel(1) +f1 = fiber.create(function() str = fh1:read() ch:put(digest.crc32(str)) end) +f2 = fiber.create(function() str = fh2:read() end) +ch:get() == hash + +fio.unlink(tmp1) +fio.unlink(tmp2) fio.rmdir(tmpdir) -- GitLab