[patches] [fio 1/1] fio: Fix race condition in fio.read

Ilya Markov imarkov at tarantool.org
Fri Mar 2 17:46:23 MSK 2018


From: imarkov <imarkov at tarantool.org>

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

branch gh-3187-fio-read-race
---
 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 d48c709..73719df 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 0fc8582..6c46098 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 cd0bc16..0850413 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)
-- 
2.7.4




More information about the Tarantool-patches mailing list