From ca51cbe93b0ea75840d4c8157e8e9c79fac37e14 Mon Sep 17 00:00:00 2001
From: Dmitry Simonenko <pmwkaa@gmail.com>
Date: Tue, 12 Mar 2013 17:43:00 +0400
Subject: [PATCH] lua-socket-race-fix: race fix in coeio_custom. Fix race
 between fiber_yield_timeout() and completed request during yield itself. In
 that case eio_poll will complete request and free its handle. eio_cancel try
 to cancel completed and freed request. Also, fix unpredictable result during
 timedout test.

---
 src/coeio.m            |  5 ++++-
 test/box/socket.result | 27 ++++++++++-----------------
 test/box/socket.test   | 20 ++++++++++----------
 3 files changed, 24 insertions(+), 28 deletions(-)

diff --git a/src/coeio.m b/src/coeio.m
index 1e5947d3a1..d966d8f590 100644
--- a/src/coeio.m
+++ b/src/coeio.m
@@ -122,6 +122,7 @@ struct coeio_task {
 	va_list ap;
 	/** Callback results. */
 	ssize_t result;
+	int complete;
 	int errorno;
 };
 
@@ -150,6 +151,7 @@ coeio_on_complete(eio_req *req)
 		struct coeio_task *task = req->data;
 		task->result = req->result;
 		task->errorno = req->errorno;
+		task->complete = 1;
 		fiber_wakeup(task->fiber);
 	}
 	return 0;
@@ -188,12 +190,13 @@ coeio_custom(ssize_t (*func)(va_list ap), ev_tstamp timeout, ...)
 	task.fiber = fiber;
 	task.func = func;
 	task.result = -1;
+	task.complete = 0;
 	va_start(task.ap, timeout);
 	struct eio_req *req = eio_custom(coeio_custom_cb, 0,
 					 coeio_on_complete, &task);
 	if (req == NULL) {
 		errno = ENOMEM;
-	} else if (fiber_yield_timeout(timeout)) {
+	} else if (fiber_yield_timeout(timeout) && !task.complete) {
 		/* timeout. */
 		errno = ETIMEDOUT;
 		task.result = -1;
diff --git a/test/box/socket.result b/test/box/socket.result
index 8bc0ba5fb5..befd43b982 100644
--- a/test/box/socket.result
+++ b/test/box/socket.result
@@ -92,17 +92,19 @@ lua s:close()
 lua s:close()
 ---
 ...
-lua s:connect('somewhereelse', '30303', 0.01)
+lua sr, se = s:connect('somewhereelse', '30303', 0.0001)
 ---
- - nil
- - timeout
- - 110
- - Connection timed out
 ...
-lua s:error()
+lua sr == nil and se == 'error' or se == 'timeout'
+---
+ - true
+...
+lua e = s:error()
 ---
- - 110
- - Connection timed out
+...
+lua e == -1 or e == 110
+---
+ - true
 ...
 lua s:close()
 ---
@@ -115,11 +117,6 @@ lua s:send(1)
 ---
 error: 'box.socket: socket is not initialized'
 ...
-lua s:error()
----
- - 110
- - Connection timed out
-...
 lua s = box.socket.tcp()
 ---
 ...
@@ -155,10 +152,6 @@ lua type(error_str)
 ---
  - string
 ...
-lua n
----
- - 163840
-...
 lua status
 ---
  - timeout
diff --git a/test/box/socket.test b/test/box/socket.test
index 49c4a5a9f1..180927a61c 100644
--- a/test/box/socket.test
+++ b/test/box/socket.test
@@ -54,22 +54,23 @@ exec admin "lua s:connect(123)"
 exec admin "lua s:close()"
 
 exec admin "lua s:close()"
-exec admin "lua s:connect('somewhereelse', '30303', 0.01)"
-# timedout
-exec admin "lua s:error()"
+exec admin "lua sr, se = s:connect('somewhereelse', '30303', 0.0001)"
+exec admin "lua sr == nil and se == 'error' or se == 'timeout'"
+
+# timedout or hostname resolution failed
+exec admin "lua e = s:error()"
+exec admin "lua e == -1 or e == 110"
 exec admin "lua s:close()"
 
-##################
-#                #
+#################
+#               #
 # socket:send() #
-#                #
-##################
+#               #
+#################
 
 # bad args
 exec admin "lua s:send()"
 exec admin "lua s:send(1)"
-# bad file descriptor
-exec admin "lua s:error()"
 
 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
@@ -87,7 +88,6 @@ exec admin "lua type(n)"
 exec admin "lua type(status)"
 exec admin "lua type(error_code)"
 exec admin "lua type(error_str)"
-exec admin "lua n"
 exec admin "lua status"
 exec admin "lua error_code"
 exec admin "lua error_str"
-- 
GitLab