PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
PVS-Studio ๋ถ„์„๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์žฅ ์ตœ๊ทผ์˜ ์‹œ๋‚˜๋ฆฌ์˜ค ์ค‘ ํ•˜๋‚˜๋Š” CI ์‹œ์Šคํ…œ๊ณผ์˜ ํ†ตํ•ฉ์ž…๋‹ˆ๋‹ค. ๊ฑฐ์˜ ๋ชจ๋“  ์—ฐ์† ํ†ตํ•ฉ ์‹œ์Šคํ…œ์˜ PVS-Studio ํ”„๋กœ์ ํŠธ ๋ถ„์„์€ ๋‹จ ๋ช‡ ๊ฐ€์ง€ ๋ช…๋ น์œผ๋กœ ๊ตฌ์ถ•๋  ์ˆ˜ ์žˆ์ง€๋งŒ ์šฐ๋ฆฌ๋Š” ์ด ํ”„๋กœ์„ธ์Šค๋ฅผ ๋”์šฑ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๊ณ„์† ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. PVS-Studio๋Š” ์ด์ œ ๋ถ„์„๊ธฐ ์ถœ๋ ฅ์„ TeamCity ํ˜•์‹(TeamCity Inspections Type)์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ๋ด…์‹œ๋‹ค.

์‚ฌ์šฉ๋œ ์†Œํ”„ํŠธ์›จ์–ด์— ๋Œ€ํ•œ ์ •๋ณด

PVS-์ŠคํŠœ๋””์˜ค โ€” ๋‹ค์–‘ํ•œ ์œ ํ˜•์˜ ์˜ค๋ฅ˜๋ฅผ ์ฐพ๊ณ  ์ˆ˜์ •ํ•˜๋Š” ์ž‘์—…์„ ์šฉ์ดํ•˜๊ฒŒ ํ•˜๋„๋ก ์„ค๊ณ„๋œ C, C++, C# ๋ฐ Java ์ฝ”๋“œ์˜ ์ •์  ๋ถ„์„๊ธฐ์ž…๋‹ˆ๋‹ค. ๋ถ„์„๊ธฐ๋Š” Windows, Linux ๋ฐ macOS์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ์‚ฌ์—์„œ๋Š” ๋ถ„์„๊ธฐ ์ž์ฒด๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ•ด๋‹น ๋ฐฐํฌํŒ์˜ ์ผ๋ถ€ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋„ ์ ๊ทน์ ์œผ๋กœ ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

CL๋ชจ๋‹ˆํ„ฐ โ€” ์ปดํŒŒ์ผ๋Ÿฌ ์‹คํ–‰์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ชจ๋‹ˆํ„ฐ๋ง ์„œ๋ฒ„์ž…๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ ๋นŒ๋“œ๋ฅผ ์‹œ์ž‘ํ•˜๊ธฐ ์ง์ „์— ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์Šค๋ˆ„ํ•‘ ๋ชจ๋“œ์—์„œ ์„œ๋ฒ„๋Š” ์ง€์›๋˜๋Š” ๋ชจ๋“  ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์‹คํ–‰์„ ๊ฐ€๋กœ์ฑ•๋‹ˆ๋‹ค. ์ด ์œ ํ‹ธ๋ฆฌํ‹ฐ๋Š” C/C++ ํ”„๋กœ์ ํŠธ๋ฅผ ๋ถ„์„ํ•˜๋Š” ๋ฐ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์€ ์ฃผ๋ชฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

PlogConverter โ€“ ๋ถ„์„๊ธฐ ๋ณด๊ณ ์„œ๋ฅผ ๋‹ค๋ฅธ ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ์ž…๋‹ˆ๋‹ค.

์—ฐ๊ตฌ์ค‘์ธ ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•œ ์ •๋ณด

์‹ค์ œ ์‚ฌ๋ก€์—์„œ ์ด ๊ธฐ๋Šฅ์„ ์‹œํ—˜ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. OpenRCT2 ํ”„๋กœ์ ํŠธ๋ฅผ ๋ถ„์„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์˜คํ”ˆRCT2 - RollerCoaster Tycoon 2(RCT2) ๊ฒŒ์ž„์„ ๊ณต๊ฐœ์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜์—ฌ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์œผ๋กœ ํ™•์žฅํ•˜๊ณ  ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฒŒ์ž„ ํ”Œ๋ ˆ์ด๋Š” ๋†€์ด๊ธฐ๊ตฌ, ์ƒ์ , ์‹œ์„ค์ด ํฌํ•จ๋œ ๋†€์ด๊ณต์›์„ ๊ฑด์„คํ•˜๊ณ  ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์„ ์ค‘์‹ฌ์œผ๋กœ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค. ํ”Œ๋ ˆ์ด์–ด๋Š” ์†๋‹˜์„ ํ–‰๋ณตํ•˜๊ฒŒ ํ•˜๋ฉด์„œ ์ด์ต์„ ์–ป๊ณ  ๊ณต์›์˜ ์ข‹์€ ํ‰ํŒ์„ ์œ ์ง€ํ•˜๋„๋ก ๋…ธ๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. OpenRCT2๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‹œ๋‚˜๋ฆฌ์˜ค์™€ ์ƒŒ๋“œ๋ฐ•์Šค ๋ชจ๋‘์—์„œ ํ”Œ๋ ˆ์ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ์ •ํ•ด์ง„ ์‹œ๊ฐ„ ๋‚ด์— ํŠน์ • ์ž‘์—…์„ ์™„๋ฃŒํ•ด์•ผ ํ•˜๋Š” ๋ฐ˜๋ฉด, ์ƒŒ๋“œ๋ฐ•์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ”Œ๋ ˆ์ด์–ด๋Š” ์ œํ•œ์ด๋‚˜ ์žฌ์ • ์—†์ด ๋ณด๋‹ค ์œ ์—ฐํ•œ ๊ณต์›์„ ๊ฑด์„คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์กฐ์ •

์‹œ๊ฐ„์„ ์ ˆ์•ฝํ•˜๊ธฐ ์œ„ํ•ด ์„ค์น˜ ๊ณผ์ •์„ ๊ฑด๋„ˆ๋›ฐ๊ณ  ์ปดํ“จํ„ฐ์—์„œ TeamCity ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰๋˜๋Š” ์ˆœ๊ฐ„๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. localhost:{์„ค์น˜ ํ”„๋กœ์„ธ์Šค ์ค‘์— ์ง€์ •๋œ ํฌํŠธ}(์ œ ๊ฒฝ์šฐ์—๋Š” localhost:9090)๋กœ ์ด๋™ํ•˜์—ฌ ์ธ์ฆ ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ž…์žฅ ํ›„ ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ธ์‚ฌ๋ฅผ ๋ฐ›๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค:

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ˆ˜๋™์„ ์„ ํƒํ•˜๊ณ  ํ•„๋“œ๋ฅผ ์ฑ„์›๋‹ˆ๋‹ค.

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
๋ฒ„ํŠผ์„ ๋ˆ„๋ฅธ ํ›„ ๋งŒ๋“ค๊ธฐ, ์„ค์ • ์ฐฝ์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
ํด๋ฆญํ•ด๋ณด์ž ๋นŒ๋“œ ๊ตฌ์„ฑ ๋งŒ๋“ค๊ธฐ.

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
ํ•„๋“œ๋ฅผ ์ฑ„์šฐ๊ณ  ํด๋ฆญํ•˜์„ธ์š”. ๋งŒ๋“ค๊ธฐ. ๋ฒ„์ „ ์ œ์–ด ์‹œ์Šคํ…œ์„ ์„ ํƒํ•˜๋ผ๋Š” ์ฐฝ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์†Œ์Šค๋Š” ์ด๋ฏธ ๋กœ์ปฌ์— ์žˆ์œผ๋ฏ€๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ.

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
๋งˆ์ง€๋ง‰์œผ๋กœ ํ”„๋กœ์ ํŠธ ์„ค์ •์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
์กฐ๋ฆฝ ๋‹จ๊ณ„๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ํด๋ฆญํ•˜์„ธ์š”. ๋นŒ๋“œ ๋‹จ๊ณ„ -> ๋นŒ๋“œ ๋‹จ๊ณ„ ์ถ”๊ฐ€.

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
์—ฌ๊ธฐ์„œ๋Š” ๋‹ค์Œ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

  • ๋Ÿฌ๋„ˆ ์œ ํ˜• -> ๋ช…๋ น์ค„
  • ์‹คํ–‰ -> ์‚ฌ์šฉ์ž ์ •์˜ ์Šคํฌ๋ฆฝํŠธ

ํ”„๋กœ์ ํŠธ ์ปดํŒŒ์ผ ๊ณผ์ •์—์„œ ๋ถ„์„์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์กฐ๋ฆฝ๊ณผ ๋ถ„์„์ด ํ•œ ๋‹จ๊ณ„๋กœ ์ด๋ฃจ์–ด์ ธ์•ผ ํ•˜๋ฏ€๋กœ ํ•ด๋‹น ํ•„๋“œ๋ฅผ ์ฑ„์›Œ์ฃผ์„ธ์š”. ์‚ฌ์šฉ์ž ์ •์˜ ์Šคํฌ๋ฆฝํŠธ:

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
๋‚˜์ค‘์— ๊ฐœ๋ณ„ ๋‹จ๊ณ„๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ถ„์„๊ธฐ ๋กœ๋“œ, ํ”„๋กœ์ ํŠธ ์กฐ๋ฆฝ, ๋ถ„์„, ๋ณด๊ณ ์„œ ์ถœ๋ ฅ ๋ฐ ํ˜•์‹ ์ง€์ •์— ๋‹จ XNUMX์ค„์˜ ์ฝ”๋“œ๋งŒ ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ ํ•ด์•ผ ํ•  ์ผ์€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ๊ฐ€๋…์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ๋‹ค์Œ์œผ๋กœ ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค. ๋งค๊ฐœ๋ณ€์ˆ˜ -> ์ƒˆ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ถ”๊ฐ€ ์„ธ ๊ฐ€์ง€ ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค ๋‹ฌ๋ฆฌ๊ธฐ ์˜ค๋ฅธ์ชฝ ์ƒ๋‹จ์— ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ๊ฐ€ ๊ตฌ์„ฑ๋˜๊ณ  ๋ถ„์„๋˜๋Š” ๋™์•ˆ ์Šคํฌ๋ฆฝํŠธ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ง์ ‘ ์Šคํฌ๋ฆฝํŠธ

๋จผ์ € ์ตœ์‹  PVS-Studio ๋ฐฐํฌํŒ์„ ๋‹ค์šด๋กœ๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด Chocolatey ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•ด ๋” ์•Œ๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•ด ํ•ด๋‹นํ•˜๋Š” ๋‚ด์šฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์‚ฌ:

choco install pvs-studio -y

๋‹ค์Œ์œผ๋กœ CLMonitor ํ”„๋กœ์ ํŠธ ๋นŒ๋“œ ์ถ”์  ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์‹œ์ž‘ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

%CLmon% monitor โ€“-attach

๊ทธ๋Ÿฐ ๋‹ค์Œ ํ”„๋กœ์ ํŠธ๋ฅผ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค. MSB ๋นŒ๋“œํ•ด์•ผ ํ•˜๋Š” MSBuild ๋ฒ„์ „์˜ ๊ฒฝ๋กœ์ž…๋‹ˆ๋‹ค.

%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable

PVS-Studio์˜ ๋กœ๊ทธ์ธ ๋ฐ ๋ผ์ด์„ผ์Šค ํ‚ค๋ฅผ ์ž…๋ ฅํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%

๋นŒ๋“œ๊ฐ€ ์™„๋ฃŒ๋œ ํ›„ CLMonitor๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์—ฌ ์ „์ฒ˜๋ฆฌ๋œ ํŒŒ์ผ๊ณผ ์ •์  ๋ถ„์„์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

%CLmon% analyze -l "c:ptest.plog"

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ฐฐํฌํŒ์˜ ๋‹ค๋ฅธ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. PlogConverter๋Š” ๋ณด๊ณ ์„œ๋ฅผ ํ‘œ์ค€ ํ˜•์‹์—์„œ TeamCity ์ „์šฉ ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋•๋ถ„์— ๋นŒ๋“œ์ฐฝ์—์„œ ๋ฐ”๋กœ ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"

๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„๋Š” ํ˜•์‹์ด ์ง€์ •๋œ ๋ณด๊ณ ์„œ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ‘œ์ค€ ์ถœ๋ ฅ, TeamCity ํŒŒ์„œ๊ฐ€ ์ด๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

type "C:tempptest.plog_TeamCity.txt"

์ „์ฒด ์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ:

choco install pvs-studio -y
%CLmon% monitor --attach
set platform=x64
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
%CLmon% analyze -l "c:ptest.plog"
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
type "C:tempptest.plog_TeamCity.txt"

๊ทธ๋™์•ˆ ํ”„๋กœ์ ํŠธ์˜ ์กฐ๋ฆฝ ๋ฐ ๋ถ„์„์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฏ€๋กœ ํƒญ์œผ๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ ๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์„ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
์ด์ œ ๋‹ค์Œ์„ ํด๋ฆญํ•ด ๋ณผ๊นŒ์š”? ๊ฒ€์‚ฌ ์ด๊ณ„๋ถ„์„๊ธฐ ๋ณด๊ณ ์„œ๋ฅผ ๋ณด๋ ค๋ฉด ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ๋”ฐ๋ฅด์„ธ์š”.

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
๊ฒฝ๊ณ ๋Š” ์ง„๋‹จ ๊ทœ์น™ ๋ฒˆํ˜ธ๋ณ„๋กœ ๊ทธ๋ฃนํ™”๋ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ํƒ์ƒ‰ํ•˜๋ ค๋ฉด ๊ฒฝ๊ณ ๊ฐ€ ์žˆ๋Š” ์ค„ ๋ฒˆํ˜ธ๋ฅผ ํด๋ฆญํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋ฅธ์ชฝ ์ƒ๋‹จ์— ์žˆ๋Š” ๋ฌผ์Œํ‘œ๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋ฌธ์„œ๊ฐ€ ํฌํ•จ๋œ ์ƒˆ ํƒญ์ด ์—ด๋ฆฝ๋‹ˆ๋‹ค. ๋ถ„์„๊ธฐ ๊ฒฝ๊ณ ๊ฐ€ ์žˆ๋Š” ์ค„ ๋ฒˆํ˜ธ๋ฅผ ํด๋ฆญํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ํƒ์ƒ‰ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ ์‹œ ์›๊ฒฉ ์ปดํ“จํ„ฐ์—์„œ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์†Œ์ŠคํŠธ๋ฆฌ๋ฃจํŠธ ์ฑ„์ ์ž. ์ด ๋ถ„์„๊ธฐ ์ž‘๋™ ๋ชจ๋“œ์— ๊ด€์‹ฌ์ด ์žˆ๋Š” ์‚ฌ๋žŒ์€ ๋ˆ„๊ตฌ๋‚˜ ํ•ด๋‹น ์„น์…˜์„ ์ˆ™์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ ์  ์„œ๋ฅ˜ ๋น„์น˜.

๋ถ„์„๊ธฐ ๊ฒฐ๊ณผ ๋ณด๊ธฐ

์ด์ œ ๋นŒ๋“œ ๋ฐฐํฌ ๋ฐ ๊ตฌ์„ฑ์ด ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฏ€๋กœ ์šฐ๋ฆฌ๊ฐ€ ๋ณด๊ณ  ์žˆ๋Š” ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐœ๊ฒฌ๋œ ๋ช‡ ๊ฐ€์ง€ ํฅ๋ฏธ๋กœ์šด ๊ฒฝ๊ณ ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฒฝ๊ณ  N1

V773 [CWE-401] '๊ฒฐ๊ณผ' ํฌ์ธํ„ฐ๋ฅผ ํ•ด์ œํ•˜์ง€ ์•Š๊ณ  ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. libopenrct2 ObjectFactory.cpp 443

Object* CreateObjectFromJson(....)
{
  Object* result = nullptr;
  ....
  result = CreateObject(entry);
  ....
  if (readContext.WasError())
  {
    throw std::runtime_error("Object has errors");
  }
  ....
}

Object* CreateObject(const rct_object_entry& entry)
{
  Object* result;
  switch (entry.GetType())
  {
    case OBJECT_TYPE_RIDE:
      result = new RideObject(entry);
      break;
    case OBJECT_TYPE_SMALL_SCENERY:
      result = new SmallSceneryObject(entry);
      break;
    case OBJECT_TYPE_LARGE_SCENERY:
      result = new LargeSceneryObject(entry);
      break;
    ....
    default:
      throw std::runtime_error("Invalid object type");
  }
  return result;
}

๋ถ„์„๊ธฐ๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋™์ ์œผ๋กœ ํ• ๋‹นํ•œ ํ›„ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. CreateObject, ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ง€์›Œ์ง€์ง€ ์•Š๊ณ  ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๊ฒฝ๊ณ  N2

V501 '|'์˜ ์™ผ์ชฝ๊ณผ ์˜ค๋ฅธ์ชฝ์— ๋™์ผํ•œ ํ•˜์œ„ ํ‘œํ˜„์‹ '(1ULL << WIDX_MONTH_BOX)'๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์šด์˜์ž. libopenrct2ui Cheats.cpp 487

static uint64_t window_cheats_page_enabled_widgets[] = 
{
  MAIN_CHEAT_ENABLED_WIDGETS |
  (1ULL << WIDX_NO_MONEY) |
  (1ULL << WIDX_ADD_SET_MONEY_GROUP) |
  (1ULL << WIDX_MONEY_SPINNER) |
  (1ULL << WIDX_MONEY_SPINNER_INCREMENT) |
  (1ULL << WIDX_MONEY_SPINNER_DECREMENT) |
  (1ULL << WIDX_ADD_MONEY) |
  (1ULL << WIDX_SET_MONEY) |
  (1ULL << WIDX_CLEAR_LOAN) |
  (1ULL << WIDX_DATE_SET) |
  (1ULL << WIDX_MONTH_BOX) |  // <=
  (1ULL << WIDX_MONTH_UP) |
  (1ULL << WIDX_MONTH_DOWN) |
  (1ULL << WIDX_YEAR_BOX) |
  (1ULL << WIDX_YEAR_UP) |
  (1ULL << WIDX_YEAR_DOWN) |
  (1ULL << WIDX_DAY_BOX) |
  (1ULL << WIDX_DAY_UP) |
  (1ULL << WIDX_DAY_DOWN) |
  (1ULL << WIDX_MONTH_BOX) |  // <=
  (1ULL << WIDX_DATE_GROUP) |
  (1ULL << WIDX_DATE_RESET),
  ....
};

์ •์  ๋ถ„์„๊ฐ€ ์™ธ์—๋Š” ์ด ์ฃผ์˜๋ ฅ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•  ์ˆ˜ ์žˆ๋Š” ์‚ฌ๋žŒ์ด ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๋ณต์‚ฌ-๋ถ™์—ฌ๋„ฃ๊ธฐ ์˜ˆ์ œ๋Š” ๋ฐ”๋กœ ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ์ข‹์Šต๋‹ˆ๋‹ค.

๊ฒฝ๊ณ  N3

V703 ํŒŒ์ƒ ํด๋ž˜์Šค 'RCT12BannerElement'์˜ 'ํ”Œ๋ž˜๊ทธ' ํ•„๋“œ๊ฐ€ ๊ธฐ๋ณธ ํด๋ž˜์Šค 'RCT12TileElementBase'์˜ ํ•„๋“œ๋ฅผ ๋ฎ์–ด์“ฐ๋Š” ๊ฒƒ์€ ์ด์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ผ์ธ์„ ํ™•์ธํ•˜์„ธ์š”: RCT12.h:570, RCT12.h:259. libopenrct2 RCT12.h 570

struct RCT12SpriteBase
{
  ....
  uint8_t flags;
  ....
};
struct rct1_peep : RCT12SpriteBase
{
  ....
  uint8_t flags;
  ....
};

๋ฌผ๋ก , ๊ธฐ๋ณธ ํด๋ž˜์Šค์™€ ํ•˜์œ„ ํด๋ž˜์Šค์— ๋™์ผํ•œ ์ด๋ฆ„์˜ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•ด์„œ ํ•ญ์ƒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ƒ์† ๊ธฐ์ˆ  ์ž์ฒด์—์„œ๋Š” ์ƒ์œ„ ํด๋ž˜์Šค์˜ ๋ชจ๋“  ํ•„๋“œ๊ฐ€ ํ•˜์œ„ ํด๋ž˜์Šค์— ์กด์žฌํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ƒ์†์ธ์— ๋™์ผํ•œ ์ด๋ฆ„์˜ ํ•„๋“œ๋ฅผ ์„ ์–ธํ•˜๋ฉด ํ˜ผ๋ž€์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๊ฒฝ๊ณ  N4

V793 'imageDirection / 8' ๋ฌธ์˜ ๊ฒฐ๊ณผ๊ฐ€ ์กฐ๊ฑด์˜ ์ผ๋ถ€์ธ ๊ฒƒ์€ ์ด์ƒํ•ฉ๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ์ด ์ง„์ˆ ์€ ๋‹ค๋ฅธ ๊ฒƒ๊ณผ ๋น„๊ต๋˜์–ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. libopenrct2 ObservationTower.cpp 38

void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
  if ((imageDirection / 8) && (imageDirection / 8) != 3)
  {
    ....
  }
  ....
}

์ข€ ๋” ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ‘œํ˜„ ์ด๋ฏธ์ง€๋ฐฉํ–ฅ/8 ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ ๊ฑฐ์ง“์ด ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€๋ฐฉํ–ฅ ๋ฒ”์œ„๋Š” -7์—์„œ 7 ์‚ฌ์ด์ž…๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ๋ถ€๋ถ„: (์ด๋ฏธ์ง€ ๋ฐฉํ–ฅ / 8) != 3 ์ฒดํฌ ๋ฌด๋Šฌ ์ด๋ฏธ์ง€๋ฐฉํ–ฅ ๋ฒ”์œ„ ๋ฐ–์— ์žˆ๋Š” ๊ฒฝ์šฐ: ๊ฐ๊ฐ -31์—์„œ -24 ๋ฐ 24์—์„œ 31์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์‹์œผ๋กœ ํŠน์ • ๋ฒ”์œ„์— ํฌํ•จ๋œ ์ˆซ์ž๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ๋‚˜์—๊ฒŒ๋Š” ๋งค์šฐ ์ด์ƒํ•ด ๋ณด์ด๋ฉฐ, ์ด ์ฝ”๋“œ ์กฐ๊ฐ์— ์˜ค๋ฅ˜๊ฐ€ ์—†๋”๋ผ๋„ ์ด๋Ÿฌํ•œ ์กฐ๊ฑด์„ ๋ณด๋‹ค ๋ช…ํ™•ํ•˜๊ฒŒ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ด ์ฝ”๋“œ๋ฅผ ์ฝ๊ณ  ์œ ์ง€ ๊ด€๋ฆฌํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์˜ ์‚ถ์ด ํ›จ์”ฌ ์‰ฌ์›Œ์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฒฝ๊ณ  N5

V587 ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ์ด์ƒํ•œ ํ• ๋‹น ์ˆœ์„œ: A = B; B = A;. ๋ผ์ธ ํ™•์ธ: 1115, 1118. libopenrct2ui MouseInput.cpp 1118

void process_mouse_over(....)
{
  ....
  switch (window->widgets[widgetId].type)
  {
    case WWT_VIEWPORT:
      ebx = 0;
      edi = cursorId;                                 // <=
      // Window event WE_UNKNOWN_0E was called here,
      // but no windows actually implemented a handler and
      // it's not known what it was for
      cursorId = edi;                                 // <=
      if ((ebx & 0xFF) != 0)
      {
        set_cursor(cursorId);
        return;
      }
      break;
      ....
  }
  ....
}

์ด ์ฝ”๋“œ ์กฐ๊ฐ์€ ๋””์ปดํŒŒ์ผ์„ ํ†ตํ•ด ์–ป์€ ๊ฒƒ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์™ผ์ชฝ ์ฃผ์„์œผ๋กœ ํŒ๋‹จํ•˜๋ฉด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ์ฝ”๋“œ์˜ ์ผ๋ถ€๊ฐ€ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์•„์ง ๋ช‡ ๊ฐ€์ง€ ์ž‘์—…์ด ๋‚จ์•˜์Šต๋‹ˆ๋‹ค. ์ปค์„œID, ๊ทธ๊ฒƒ๋„ ๋ณ„๋กœ ์˜๋ฏธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๊ฒฝ๊ณ  N6

V1004 [CWE-476] 'ํ”Œ๋ ˆ์ด์–ด' ํฌ์ธํ„ฐ๊ฐ€ nullptr์— ๋Œ€ํ•ด ๊ฒ€์ฆ๋œ ํ›„ ์•ˆ์ „ํ•˜์ง€ ์•Š๊ฒŒ ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋ผ์ธ ํ™•์ธ: 2085, 2094. libopenrct2 Network.cpp 2094

void Network::ProcessPlayerList()
{
  ....
  auto* player = GetPlayerByID(pendingPlayer.Id);
  if (player == nullptr)
  {
    // Add new player.
    player = AddPlayer("", "");
    if (player)                                          // <=
    {
      *player = pendingPlayer;
       if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
       {
         _serverConnection->Player = player;
       }
    }
    newPlayers.push_back(player->Id);                    // <=
  }
  ....
}

์ด ์ฝ”๋“œ๋Š” ์ˆ˜์ •ํ•˜๊ธฐ๊ฐ€ ๋งค์šฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์„ธ ๋ฒˆ๋งŒ ํ™•์ธํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ํ”Œ๋ ˆ์ด์–ด ๋„ ํฌ์ธํ„ฐ์— ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์กฐ๊ฑด๋ฌธ ๋ณธ๋ฌธ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‘ ๋ฒˆ์งธ ์˜ต์…˜์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค:

void Network::ProcessPlayerList()
{
  ....
  auto* player = GetPlayerByID(pendingPlayer.Id);
  if (player == nullptr)
  {
    // Add new player.
    player = AddPlayer("", "");
    if (player)
    {
      *player = pendingPlayer;
      if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
      {
        _serverConnection->Player = player;
      }
      newPlayers.push_back(player->Id);
    }
  }
  ....
}

๊ฒฝ๊ณ  N7

V547 [CWE-570] 'name == nullptr' ํ‘œํ˜„์‹์€ ํ•ญ์ƒ false์ž…๋‹ˆ๋‹ค. libopenrct2 ServerList.cpp 102

std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
  auto name = json_object_get(server, "name");
  .....
  if (name == nullptr || version == nullptr)
  {
    ....
  }
  else
  {
    ....
    entry.name = (name == nullptr ? "" : json_string_value(name));
    ....
  }
  ....
}

์ฝ๊ธฐ ์–ด๋ ค์šด ์ฝ”๋“œ ์ค„์„ ๋‹จ๋ฒˆ์— ์ œ๊ฑฐํ•˜๊ณ  ๋‹ค์Œ ์‚ฌํ•ญ์„ ํ™•์ธํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. nullptr. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
  auto name = json_object_get(server, "name");
  .....
  if (name == nullptr || version == nullptr)
  {
    name = ""
    ....
  }
  else
  {
    ....
    entry.name = json_string_value(name);
    ....
  }
  ....
}

๊ฒฝ๊ณ  N8

V1048 [CWE-1164] 'ColumnHeaderPressedCurrentState' ๋ณ€์ˆ˜์— ๋™์ผํ•œ ๊ฐ’์ด ํ• ๋‹น๋˜์—ˆ์Šต๋‹ˆ๋‹ค. libopenrct2ui CustomListView.cpp 510

void CustomListView::MouseUp(....)
{
  ....
  if (!ColumnHeaderPressedCurrentState)
  {
    ColumnHeaderPressed = std::nullopt;
    ColumnHeaderPressedCurrentState = false;
    Invalidate();
  }
}

์ฝ”๋“œ๊ฐ€ ์ƒ๋‹นํžˆ ์ด์ƒํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ์กฐ๊ฑด์ด๋‚˜ ๋ณ€์ˆ˜๋ฅผ ๋‹ค์‹œ ํ• ๋‹นํ•  ๋•Œ ์˜คํƒ€๊ฐ€ ์žˆ์—ˆ๋˜ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ColumnHeaderPressedCurrentState ๊ฐ€์น˜ ๊ทธ๋ฆ‡๋œ.

์ถœ๋ ฅ

๋ณด์‹œ๋‹ค์‹œํ”ผ PVS-Studio ์ •์  ๋ถ„์„๊ธฐ๋ฅผ TeamCity ํ”„๋กœ์ ํŠธ์— ํ†ตํ•ฉํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ ค๋ฉด ์ž‘์€ ๊ตฌ์„ฑ ํŒŒ์ผ ํ•˜๋‚˜๋งŒ ์ž‘์„ฑํ•˜๋ฉด ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•˜๋ฉด ์กฐ๋ฆฝ ์งํ›„ ๋ฌธ์ œ๋ฅผ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ณต์žก์„ฑ๊ณผ ๋ณ€๊ฒฝ ๋น„์šฉ์ด ์—ฌ์ „ํžˆ ๋‚ฎ์„ ๋•Œ ๋ฌธ์ œ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„
์ด ๊ธฐ์‚ฌ๋ฅผ ์˜์–ด๊ถŒ ์ฒญ์ค‘๊ณผ ๊ณต์œ ํ•˜๋ ค๋ฉด ๋ฒˆ์—ญ ๋งํฌ์ธ Vladislav Stolyarov๋ฅผ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค. PVS-Studio ๋ฐ ์ง€์†์ ์ธ ํ†ตํ•ฉ: TeamCity. Open RollerCoaster Tycoon 2 ํ”„๋กœ์ ํŠธ ๋ถ„์„.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€