Skip to content

Commit 47836ce

Browse files
committed
bugfix: segmentation faults might happen when multiple "light threads" in the same request manipuate a stream cosocket object in turn. thanks Aviram Cohen for the report.
1 parent c005354 commit 47836ce

File tree

3 files changed

+113
-19
lines changed

3 files changed

+113
-19
lines changed

src/ngx_http_lua_sleep.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ ngx_http_lua_sleep_cleanup(void *data)
138138
ngx_http_lua_co_ctx_t *coctx = data;
139139

140140
if (coctx->sleep.timer_set) {
141-
dd("cleanup: deleting timer for ngx.sleep");
141+
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
142+
"lua clean up the timer for pending ngx.sleep");
142143

143144
ngx_del_timer(&coctx->sleep);
144145
}

src/ngx_http_lua_socket_tcp.c

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx)
800800
ngx_resolve_name_done(ctx);
801801

802802
u->waiting = 0;
803+
u->co_ctx = NULL;
803804

804805
if (waiting) {
805806
lctx->resume_handler = ngx_http_lua_socket_tcp_resume;
@@ -1233,6 +1234,7 @@ ngx_http_lua_socket_tcp_receive(lua_State *L)
12331234
}
12341235

12351236
u->waiting = 0;
1237+
u->co_ctx = NULL;
12361238

12371239
rc = ngx_http_lua_socket_tcp_read(r, u);
12381240

@@ -1835,6 +1837,7 @@ ngx_http_lua_socket_tcp_send(lua_State *L)
18351837

18361838
#if 1
18371839
u->waiting = 0;
1840+
u->co_ctx = NULL;
18381841
#endif
18391842

18401843
ngx_http_lua_probe_socket_tcp_send_start(r, u, b->pos, len);
@@ -2281,32 +2284,28 @@ ngx_http_lua_socket_handle_success(ngx_http_request_t *r,
22812284
ngx_http_lua_socket_tcp_upstream_t *u)
22822285
{
22832286
ngx_http_lua_ctx_t *ctx;
2287+
ngx_http_lua_co_ctx_t *coctx;
22842288

22852289
#if 1
22862290
u->read_event_handler = ngx_http_lua_socket_dummy_handler;
22872291
u->write_event_handler = ngx_http_lua_socket_dummy_handler;
22882292
#endif
22892293

2290-
if (u->co_ctx) {
2291-
u->co_ctx->cleanup = NULL;
2292-
}
2293-
2294-
#if 0
2295-
if (u->eof) {
2296-
ngx_http_lua_socket_tcp_finalize(r, u);
2297-
}
2298-
#endif
2299-
23002294
if (u->waiting) {
23012295
u->waiting = 0;
23022296

2297+
ngx_http_lua_assert(u->co_ctx != NULL);
2298+
coctx = u->co_ctx;
2299+
coctx->cleanup = NULL;
2300+
u->co_ctx = NULL;
2301+
23032302
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
23042303
if (ctx == NULL) {
23052304
return;
23062305
}
23072306

23082307
ctx->resume_handler = ngx_http_lua_socket_tcp_resume;
2309-
ctx->cur_co_ctx = u->co_ctx;
2308+
ctx->cur_co_ctx = coctx;
23102309

23112310
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
23122311
"lua tcp socket waking up the current request");
@@ -2321,6 +2320,7 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r,
23212320
ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type)
23222321
{
23232322
ngx_http_lua_ctx_t *ctx;
2323+
ngx_http_lua_co_ctx_t *coctx;
23242324

23252325
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
23262326
"lua tcp socket handle error");
@@ -2331,23 +2331,24 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r,
23312331
ngx_http_lua_socket_tcp_finalize(r, u);
23322332
#endif
23332333

2334-
if (u->co_ctx) {
2335-
u->co_ctx->cleanup = NULL;
2336-
}
2337-
23382334
u->read_event_handler = ngx_http_lua_socket_dummy_handler;
23392335
u->write_event_handler = ngx_http_lua_socket_dummy_handler;
23402336

23412337
if (u->waiting) {
23422338
u->waiting = 0;
23432339

2340+
ngx_http_lua_assert(u->co_ctx != NULL);
2341+
coctx = u->co_ctx;
2342+
coctx->cleanup = NULL;
2343+
u->co_ctx = NULL;
2344+
23442345
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
23452346
if (ctx == NULL) {
23462347
return;
23472348
}
23482349

23492350
ctx->resume_handler = ngx_http_lua_socket_tcp_resume;
2350-
ctx->cur_co_ctx = u->co_ctx;
2351+
ctx->cur_co_ctx = coctx;
23512352

23522353
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
23532354
"lua tcp socket waking up the current request");
@@ -2792,6 +2793,7 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L)
27922793
}
27932794

27942795
u->waiting = 0;
2796+
u->co_ctx = NULL;
27952797

27962798
rc = ngx_http_lua_socket_tcp_read(r, u);
27972799

t/058-tcp-socket.t

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua;
55

66
repeat_each(2);
77

8-
plan tests => repeat_each() * 126;
8+
plan tests => repeat_each() * 130;
99

1010
our $HtmlDir = html_dir;
1111

@@ -15,7 +15,7 @@ $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8';
1515
#log_level 'warn';
1616
log_level 'debug';
1717

18-
#no_long_string();
18+
no_long_string();
1919
#no_diff();
2020
run_tests();
2121

@@ -2575,3 +2575,94 @@ close: 1 nil
25752575
--- no_error_log
25762576
[error]
25772577
2578+
2579+
2580+
=== TEST 42: u->coctx left over bug
2581+
--- config
2582+
server_tokens off;
2583+
location = /t {
2584+
#set $port 5000;
2585+
set $port $TEST_NGINX_SERVER_PORT;
2586+
2587+
content_by_lua '
2588+
local sock = ngx.socket.tcp()
2589+
local port = ngx.var.port
2590+
local ok, err = sock:connect("127.0.0.1", port)
2591+
if not ok then
2592+
ngx.say("failed to connect: ", err)
2593+
return
2594+
end
2595+
2596+
ngx.say("connected: ", ok)
2597+
2598+
local req = "GET /foo HTTP/1.0\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n"
2599+
-- req = "OK"
2600+
2601+
local bytes, err = sock:send(req)
2602+
if not bytes then
2603+
ngx.say("failed to send request: ", err)
2604+
return
2605+
end
2606+
2607+
ngx.say("request sent: ", bytes)
2608+
2609+
local ready = false
2610+
local fatal = false
2611+
2612+
function f()
2613+
local line, err, part = sock:receive()
2614+
if not line then
2615+
ngx.say("failed to receive the 1st line: ", err, " [", part, "]")
2616+
fatal = true
2617+
return
2618+
end
2619+
ready = true
2620+
ngx.sleep(1)
2621+
end
2622+
2623+
local st = ngx.thread.spawn(f)
2624+
while true do
2625+
if fatal then
2626+
return
2627+
end
2628+
2629+
if not ready then
2630+
ngx.sleep(0.01)
2631+
else
2632+
break
2633+
end
2634+
end
2635+
2636+
while true do
2637+
local line, err, part = sock:receive()
2638+
if line then
2639+
-- ngx.say("received: ", line)
2640+
2641+
else
2642+
-- ngx.say("failed to receive a line: ", err, " [", part, "]")
2643+
break
2644+
end
2645+
end
2646+
2647+
ok, err = sock:close()
2648+
ngx.say("close: ", ok, " ", err)
2649+
ngx.exit(0)
2650+
';
2651+
}
2652+
2653+
location /foo {
2654+
content_by_lua 'ngx.sleep(0.1) ngx.say("foo")';
2655+
more_clear_headers Date;
2656+
}
2657+
2658+
--- request
2659+
GET /t
2660+
--- response_body
2661+
connected: 1
2662+
request sent: 57
2663+
close: nil closed
2664+
--- no_error_log
2665+
[error]
2666+
--- error_log
2667+
lua clean up the timer for pending ngx.sleep
2668+

0 commit comments

Comments
 (0)