ํผ๋๋ก ๋์๊ฐ๊ธฐ
Dev.toSecurity
์๋ฌธ ์ฝ๊ธฐ
LRU ์บ์ ๋ฐ Lifecycle ์ ๋ฆฌ๋ฅผ ํตํ Nuclei ์์ง ๋ฉ๋ชจ๋ฆฌ ๋์ ์๋ฒฝ ํด๊ฒฐ
How I Debugged and Fixed Memory & Goroutine Leaks in ProjectDiscovery Nuclei Engine ๐
AI ์์ฝ
Context
Nuclei ์์ง์ ์ฅ๊ธฐ ์คํ ๋ง์ดํฌ๋ก์๋น์ค์ SDK ํํ๋ก ์๋ฒ ๋ฉ ์ ๋ฉ๋ชจ๋ฆฌ ํฝ์ฐฝ ๋ฐ Goroutine ๋์ ๋ฐ์. ํนํ unbounded sync.Map ์ฌ์ฉ๊ณผ ๋ช ์์ ์์ ํด์ ์ ์ฐจ ๋ถ์ฌ๋ก ์ธํ ์์คํ ๋ถ์์ ์ฑ ํ์ธ.
Technical Solution
- unbounded sync.Map์ 4,096 entries ์ ํ ๋ฐ 24์๊ฐ TTL ๊ธฐ๋ฐ์ expirable LRU Cache๋ก ๊ต์ฒดํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์ํ์ ์ค์
- protocolstate.Close() ๋ด PerHostRateLimitPool ํด์ ๋ก์ง์ ์ถ๊ฐํ์ฌ ๊ณ ๋ฆฝ๋ Goroutine ์ ๊ฑฐ
- NucleiEngine.Close() ์์ ์ Template Parser์ Purge() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ AST ์บ์ ๊ฐ์ ์ ๊ฑฐ
- Interface Type Assertion์ ํ์ฉํด ์ปค์คํ ํ์ ์ฌ์ฉ ์์๋ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๋ฉฐ ์์ ์ ๋ฆฌ ๊ธฐ๋ฅ์ ์ํํ๋ ์ ์ฐํ ๊ตฌ์กฐ ์ค๊ณ
- Engine Lifecycle ๋จ๊ณ์ ๋ง์ถ ์์ฐจ์ Teardown ํ๋ก์ธ์ค ๊ตฌ์ถ์ผ๋ก ๋ฆฌ์์ค ๋์ ๊ฒฝ๋ก ์ฐจ๋จ
์ค์ฒ ํฌ์ธํธ
- long-running ์ฑ์์ sync.Map ์ฌ์ฉ ์ TTL ๋ฐ ์ต๋ ํฌ๊ธฐ ์ ํ์ด ์๋ LRU ์บ์ ๊ฒํ - SDK ์ค๊ณ ์ Close() ๋๋ Purge() ๋ฉ์๋๋ฅผ ํตํ ๋ฐฑ๊ทธ๋ผ์ด๋ Goroutine ๋ฐ ์ฑ๋์ ๋ช ์์ ์ข ๋ฃ ๊ตฌํ - ๊ฐ๋ ฅํ ํ์ ์์กด์ฑ ์์ด ๊ธฐ๋ฅ์ ํ์ฅํ๊ธฐ ์ํด Interface Type Assertion ๊ธฐ๋ฐ์ Lifecycle Hook ์ ์ฉ