Skip to content

Commit 738bedc

Browse files
bugfix: posted event handler was called after event memory was freed. (#282)
1 parent e3d9af3 commit 738bedc

File tree

2 files changed

+142
-0
lines changed

2 files changed

+142
-0
lines changed

src/ngx_stream_lua_semaphore.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,10 @@ ngx_stream_lua_sema_handler(ngx_event_t *ev)
476476
ngx_queue_t *q;
477477

478478
sem = ev->data;
479+
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
480+
"semaphore handler: wait queue: %sempty, resource count: %d",
481+
ngx_queue_empty(&sem->wait_queue) ? "" : "not ",
482+
sem->resource_count);
479483

480484
while (!ngx_queue_empty(&sem->wait_queue) && sem->resource_count > 0) {
481485

@@ -572,6 +576,10 @@ ngx_stream_lua_ffi_sema_gc(ngx_stream_lua_sema_t *sem)
572576
"destroyed", sem);
573577
}
574578

579+
if (sem->sem_event.posted) {
580+
ngx_delete_posted_event(&sem->sem_event);
581+
}
582+
575583
ngx_stream_lua_free_sema(sem);
576584
}
577585

t/154-semaphore.t

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
use Test::Nginx::Socket::Lua::Stream;
2+
3+
repeat_each(2);
4+
5+
plan tests => repeat_each() * (blocks() * 3) + 1;
6+
7+
log_level("debug");
8+
no_long_string();
9+
#no_diff();
10+
run_tests();
11+
12+
__DATA__
13+
14+
=== TEST 1: timer + shutdown error log
15+
--- stream_server_config
16+
content_by_lua_block {
17+
local function test(pre)
18+
19+
local semaphore = require "ngx.semaphore"
20+
local sem = semaphore.new()
21+
22+
local function sem_wait()
23+
24+
local ok, err = sem:wait(10)
25+
if not ok then
26+
ngx.log(ngx.ERR, "err: ", err)
27+
else
28+
ngx.log(ngx.info, "wait success")
29+
end
30+
end
31+
32+
while not ngx.worker.exiting() do
33+
local co = ngx.thread.spawn(sem_wait)
34+
ngx.thread.wait(co)
35+
end
36+
end
37+
38+
local ok, err = ngx.timer.at(0, test)
39+
ngx.log(ngx.INFO, "hello, world")
40+
ngx.say("time: ", ok)
41+
}
42+
--- request
43+
GET /t
44+
--- stream_response_like eval
45+
time: 1
46+
--- grep_error_log eval: qr/hello, world|semaphore gc wait queue is not empty/
47+
--- grep_error_log_out
48+
hello, world
49+
--- shutdown_error_log
50+
--- no_shutdown_error_log
51+
semaphore gc wait queue is not empty
52+
53+
54+
55+
=== TEST 2: timer + shutdown error log (lua code cache off)
56+
FIXME: this test case leaks memory.
57+
--- stream_server_config
58+
lua_code_cache off;
59+
content_by_lua_block {
60+
local function test(pre)
61+
62+
local semaphore = require "ngx.semaphore"
63+
local sem = semaphore.new()
64+
65+
local function sem_wait()
66+
67+
local ok, err = sem:wait(10)
68+
if not ok then
69+
ngx.log(ngx.ERR, "err: ", err)
70+
else
71+
ngx.log(ngx.ERR, "wait success")
72+
end
73+
end
74+
75+
while not ngx.worker.exiting() do
76+
local co = ngx.thread.spawn(sem_wait)
77+
ngx.thread.wait(co)
78+
end
79+
end
80+
81+
local ok, err = ngx.timer.at(0, test)
82+
ngx.log(ngx.ERR, "hello, world")
83+
ngx.say("time: ", ok)
84+
}
85+
--- request
86+
GET /test
87+
--- stream_response_like eval
88+
time: 1
89+
--- grep_error_log eval: qr/hello, world|semaphore gc wait queue is not empty/
90+
--- grep_error_log_out
91+
hello, world
92+
--- shutdown_error_log
93+
--- no_shutdown_error_log
94+
semaphore gc wait queue is not empty
95+
--- SKIP
96+
97+
98+
99+
=== TEST 3: exit before post_handler was called
100+
If gc is called before the ngx_http_lua_sema_handler and free the sema memory
101+
ngx_http_lua_sema_handler would use the freed memory.
102+
--- stream_server_config
103+
content_by_lua_block {
104+
local semaphore = require "ngx.semaphore"
105+
local sem = semaphore.new()
106+
107+
local function sem_wait()
108+
ngx.log(ngx.INFO, "ngx.sem wait start")
109+
local ok, err = sem:wait(10)
110+
if not ok then
111+
ngx.log(ngx.ERR, "ngx.sem wait err: ", err)
112+
else
113+
ngx.log(ngx.INFO, "ngx.sem wait success")
114+
end
115+
end
116+
local co = ngx.thread.spawn(sem_wait)
117+
ngx.log(ngx.INFO, "ngx.sem post start")
118+
sem:post()
119+
ngx.log(ngx.INFO, "ngx.sem post end")
120+
ngx.say("hello")
121+
ngx.exit(200)
122+
ngx.say("not reach here")
123+
}
124+
--- request
125+
GET /t
126+
--- stream_response_like
127+
hello
128+
--- grep_error_log eval: qr/(ngx.sem .*?,|close stream connection|semaphore handler: wait queue: empty, resource count: 1)/
129+
--- grep_error_log_out
130+
ngx.sem wait start,
131+
ngx.sem post start,
132+
ngx.sem post end,
133+
close stream connection
134+
semaphore handler: wait queue: empty, resource count: 1

0 commit comments

Comments
 (0)