Skip to content

Commit b57d60d

Browse files
committed
bugfix: we did not call our coroutine cleanup handlers right after our coroutine completes (either successfully or unsuccessfully) otherwise segmentation fault might happen when the Lua VM throws out unexpected exceptions like "attempt to yield across C-call boundary". thanks Lipin Dmitriy for the report in openresty#361.
1 parent 509bb98 commit b57d60d

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

src/ngx_http_lua_util.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,11 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r,
11961196

11971197
case 0:
11981198

1199+
if (ctx->cur_co_ctx->cleanup) {
1200+
ctx->cur_co_ctx->cleanup(ctx->cur_co_ctx);
1201+
ctx->cur_co_ctx->cleanup = NULL;
1202+
}
1203+
11991204
ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1);
12001205

12011206
ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD;
@@ -1353,6 +1358,13 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r,
13531358
msg = "unknown reason";
13541359
}
13551360

1361+
#if 1
1362+
if (ctx->cur_co_ctx->cleanup) {
1363+
ctx->cur_co_ctx->cleanup(ctx->cur_co_ctx);
1364+
ctx->cur_co_ctx->cleanup = NULL;
1365+
}
1366+
#endif
1367+
13561368
ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 0);
13571369

13581370
ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD;

t/077-sleep.t

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ log_level('debug');
1010

1111
repeat_each(2);
1212

13-
plan tests => repeat_each() * 43;
13+
plan tests => repeat_each() * 51;
1414

1515
#no_diff();
1616
#no_long_string();
@@ -254,3 +254,55 @@ hello
254254
--- error_log
255255
API disabled in the context of log_by_lua*
256256

257+
258+
259+
=== TEST 11: ngx.sleep() fails to yield (xpcall err handler)
260+
--- config
261+
location = /t {
262+
content_by_lua '
263+
local function f()
264+
return error(1)
265+
end
266+
local function err()
267+
ngx.sleep(0.001)
268+
end
269+
xpcall(f, err)
270+
ngx.say("ok")
271+
';
272+
}
273+
--- request
274+
GET /t
275+
--- response_body
276+
ok
277+
--- error_log
278+
lua clean up the timer for pending ngx.sleep
279+
--- no_error_log
280+
[error]
281+
282+
283+
284+
=== TEST 12: ngx.sleep() fails to yield (require)
285+
--- http_config
286+
lua_package_path "$prefix/html/?.lua;;";
287+
--- config
288+
location = /t {
289+
content_by_lua '
290+
package.loaded["foosleep"] = nil
291+
require "foosleep";
292+
';
293+
}
294+
--- request
295+
GET /t
296+
--- user_files
297+
>>> foosleep.lua
298+
ngx.sleep(0.001)
299+
300+
--- response_body_like: 500 Internal Server Error
301+
--- error_code: 500
302+
--- wait: 0.2
303+
--- error_log eval
304+
[
305+
"lua clean up the timer for pending ngx.sleep",
306+
qr{runtime error: attempt to yield across (?:metamethod/)?C-call boundary},
307+
]
308+

0 commit comments

Comments
 (0)