PVS-Studioã¢ãã©ã€ã¶ãŒã䜿çšããããã®æãé¢é£æ§ã®ããã·ããªãªã®1ã€ã¯ãCIã·ã¹ãã ãšã®çµ±åã§ãããŸããã»ãŒãã¹ãŠã®ç¶ç¶çãªçµ±åã·ã¹ãã ããã®PVS-Studioãããžã§ã¯ãã®åæã¯ãã»ãã®æ°åã®ã³ãã³ãã«çµã¿èŸŒãããšãã§ããŸããããã®ããã»ã¹ãããã«äŸ¿å©ã«ãç¶ããŠããŸããPVS-Studioã¯ãã¢ãã©ã€ã¶ãŒåºåãTeamCity-TeamCity InspectionsTypeã®åœ¢åŒã«å€æããããšããµããŒãããããã«ãªããŸããããããã©ã®ããã«æ©èœãããèŠãŠã¿ãŸãããã
䜿çšãããœãããŠã§ã¢ã«é¢ããæ å ±
PVS-Studioã¯ãããŸããŸãªçš®é¡ã®ãšã©ãŒãèŠã€ããŠä¿®æ£ããã¿ã¹ã¯ã容æã«ããããã«èšèšããããã++ãCïŒãããã³Javaã³ãŒãã®éçã¢ãã©ã€ã¶ãŒã§ããã¢ãã©ã€ã¶ãŒã¯ãWindowsãLinuxãããã³macOSã§äœ¿çšã§ããŸãããã®èšäºã§ã¯ãã¢ãã©ã€ã¶ãŒèªäœã ãã§ãªãããã£ã¹ããªãã¥ãŒã·ã§ã³ãããã®ããã€ãã®ãŠãŒãã£ãªãã£ãç©æ¥µçã«äœ¿çšããŸãã
CLMonitorã¯ãã³ã³ãã€ã©ã®èµ·åãç£èŠããç£èŠãµãŒããŒã§ãããããžã§ã¯ãã®ãã«ããéå§ããçŽåã«å®è¡ããå¿ èŠããããŸããç£èŠã¢ãŒãã§ã¯ããµãŒããŒã¯ãµããŒããããŠãããã¹ãŠã®ã³ã³ãã€ã©ã®å®è¡ãååããŸãããã®ãŠãŒãã£ãªãã£ã¯ãC / C ++ãããžã§ã¯ãã®åæã«ã®ã¿äœ¿çšã§ããããšã«æ³šæããŠãã ããã
PlogConverterã¯ãã¢ãã©ã€ã¶ãŒã¬ããŒããããŸããŸãªåœ¢åŒã«å€æããããã®ãŠãŒãã£ãªãã£ã§ãã
調æ»å¯Ÿè±¡ãããžã§ã¯ãã«é¢ããæ å ±
ãã®æ©èœãå®éã®äŸã§è©ŠããŠã¿ãŸããããOpenRCT2ãããžã§ã¯ããåæããŠã¿ãŸãããã
OpenRCT2ã¯ãRollerCoaster Tycoon 2ïŒRCT2ïŒã®ãªãŒãã³ãœãŒã¹å®è£ ã§ãããæ°æ©èœãšãã°ä¿®æ£ã§æ¡åŒµãããŠããŸããã²ãŒã ãã¬ã€ã¯ãã¢ãã©ã¯ã·ã§ã³ãã·ã§ãããæœèšãå容ããã¢ãã¥ãŒãºã¡ã³ãããŒã¯ã®å»ºèšãšã¡ã³ããã³ã¹ãäžå¿ã«å±éãããŸãããã¬ã€ã€ãŒã¯ãã²ã¹ããæºè¶³ãããªãããå©çãäžããå ¬åã®è©å€ãç¶æããããã«åªããå¿ èŠããããŸããOpenRCT2ã䜿çšãããšãã·ããªãªãšãµã³ãããã¯ã¹ã®äž¡æ¹ã§ãã¬ã€ã§ããŸããã·ããªãªã§ã¯ããã¬ãŒã€ãŒã¯èšå®ãããæéã«ç¹å®ã®ã¿ã¹ã¯ãå®äºããå¿ èŠããããŸããããµã³ãããã¯ã¹ã䜿çšãããšããã¬ãŒã€ãŒã¯å¶éãè³éããããã«ãããæè»ãªå ¬åãæ§ç¯ã§ããŸãã
ã«ã¹ã¿ãã€ãº
æéãç¯çŽããããã«ãããããã€ã³ã¹ããŒã«ããã»ã¹ãã¹ãããããŠãTeamCityãµãŒããŒãã³ã³ãã¥ãŒã¿ãŒã§å®è¡ãããŠããç¬éããéå§ããŸããlocalhostïŒ{ã€ã³ã¹ããŒã«äžã«æå®ãããããŒã}ïŒç§ã®å Žåã¯localhostïŒ9090ïŒã«ç§»åããèªèšŒããŒã¿ãå ¥åããå¿ èŠããããŸããå ¥ã£ãåŸãç§ãã¡ã¯æ¬¡ã®äººã«äŒããŸãïŒ
[ãããžã§ã¯ãã®äœæ]ãã¿ã³ãã¯ãªãã¯ããŸãã次ã«ã[æå]ãéžæãããã£ãŒã«ãã«å ¥åããŸãã
[äœæ]ãã¿ã³ãã¯ãªãã¯ãããšãèšå®ã衚瀺ããããŠã£ã³ããŠã衚瀺ãããŸãã
[ãã«ãæ§æã®äœæ]ãã¯ãªãã¯ããŸãã
ãã£ãŒã«ãã«å ¥åãã[äœæ]ãã¯ãªãã¯ããŸããããŒãžã§ã³å¶åŸ¡ã·ã¹ãã ãéžæããããã®ãŠã£ã³ããŠã衚瀺ãããŸãããœãŒã¹ã¯ãã§ã«ããŒã«ã«ã«ããããã[ã¹ããã]ãã¯ãªãã¯ããŸãã
æåŸã«ããããžã§ã¯ãã®èšå®ã«ç§»ããŸãã
[ãã«ãã¹ããã]-> [ãã«ãã¹ãããã®è¿œå ]ãã¯ãªãã¯ããŠããã«ãã¹ããããè¿œå ããŸãã
ããã§éžæããŸãïŒ
- ã©ã³ããŒã¿ã€ã->ã³ãã³ãã©ã€ã³
- å®è¡->ã«ã¹ã¿ã ã¹ã¯ãªãã
ãããžã§ã¯ãã®ã³ã³ãã€ã«äžã«åæãããããã¢ã»ã³ããªãšåæã¯1ã€ã®ã¹ãããã§ããå¿ èŠããããŸãããããã£ãŠã[ã«ã¹ã¿ã ã¹ã¯ãªãã]ãã£ãŒã«ãã«å ¥åããŸãã
åŸã§åã ã®ã¹ãããã«ã€ããŠè©³ãã説æããŸããã¢ãã©ã€ã¶ãŒã®ããŒãããããžã§ã¯ãã®æ§ç¯ãåæãã¬ããŒãã®åºåãããã³ãã©ãŒãããã®ãã¹ãŠã«ã11è¡ã®ã³ãŒãããå¿ èŠãªãããšãéèŠã§ãã
æåŸã«è¡ãå¿ èŠãããã®ã¯ãç°å¢å€æ°ãèšå®ããããšã§ããããã¯ãèªã¿ããããåäžãããããã€ãã®æ¹æ³ã瀺ããŠããŸãããããè¡ãã«ã¯ã[ãã©ã¡ãŒã¿]-> [æ°ãããã©ã¡ãŒã¿ã®è¿œå ]ã«ç§»åãã次ã®3ã€ã®å€æ°ãè¿œå ããŸãã
å³äžé ã«ãã[å®è¡]ãã¿ã³ãã¯ãªãã¯ããã ãã§ãããããžã§ã¯ãã®çµã¿ç«ãŠãšåæäžã«ãã¹ã¯ãªããã«ã€ããŠèª¬æããŸãã
çŽæ¥ã¹ã¯ãªãã
ãŸããææ°ã®PVS-Studioãã£ã¹ããªãã¥ãŒã·ã§ã³ãããŠã³ããŒãããå¿ èŠããããŸãããã®ããã«ãhocolateyããã±ãŒãžãããŒãžã£ãŒã䜿çšããŸããããã«ã€ããŠãã£ãšç¥ããã人ã®ããã«ãé¢é£èšäºããããŸãïŒ
choco install pvs-studio -y
次ã«ãCLMonitorãããžã§ã¯ãã¢ã»ã³ããªè¿œè·¡ãŠãŒãã£ãªãã£ãèµ·åããŸãããã
%CLmon% monitor â-attach
次ã«ããããžã§ã¯ãããã«ãããŸãããã«ãããå¿ èŠã®ããããŒãžã§ã³ã®MSBuildãžã®ãã¹ããMSBç°å¢å€æ°ãšããŠäœ¿çšãããŸãã
%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"
次ã«ãé åžãããã®ãã1ã€ã®ãŠãŒãã£ãªãã£ã䜿çšããŸããPlogConverterã¯ãã¬ããŒããæšæºåœ¢åŒããTeamCityåºæã®åœ¢åŒã«å€æããŸããããã«ãããçµã¿ç«ãŠãŠã£ã³ããŠã§çŽæ¥ç¢ºèªã§ããããã«ãªããŸãã
%PlogConverter% "c:\ptest.plog" --renderTypes=TeamCity -o "C:\temp"
æåŸã®ã¹ãããã¯ããã©ãŒããããããã¬ããŒããstdoutã«åºåããããšã§ããããã§ãTeamCityããŒãµãŒã«ãã£ãŠååŸãããŸãã
type "C:\temp\ptest.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:\temp\ptest.plog_TeamCity.txt"
ãããŸã§ã®éããããžã§ã¯ãã®çµã¿ç«ãŠãšåæã¯æ£åžžã«å®äºããŸããã[ãããžã§ã¯ã]ã¿ãã«ç§»åããŠãããã確èªã§ããŸãã
次ã«ã[æ€æ»ã®åèš]ãã¯ãªãã¯ããŠãã¢ãã©ã€ã¶ãŒã¬ããŒãã衚瀺ããŸãã
èŠåã¯ã蚺æã«ãŒã«çªå·ããšã«ã°ã«ãŒãåãããŠããŸããã³ãŒãå ã移åããã«ã¯ãèŠåã®ããè¡çªå·ãã¯ãªãã¯ããå¿ èŠããããŸããå³äžé ã®è³ªåããŒã¯ãã¯ãªãã¯ãããšãæ°ããããã¥ã¡ã³ãã¿ããéããŸããããŒãµãŒã®èŠåè¡çªå·ãã¯ãªãã¯ããŠãã³ãŒãå ã移åããããšãã§ããŸããSourceTreeRootããŒã«ãŒã䜿çšãããšããªã¢ãŒãã³ã³ãã¥ãŒã¿ãŒããã®ããã²ãŒã·ã§ã³ãå¯èœã§ãããã®ã¢ãã©ã€ã¶ãŒã®æäœã¢ãŒãã«é¢å¿ã®ããæ¹ã¯ãããã¥ã¡ã³ãã®å¯Ÿå¿ããã»ã¯ã·ã§ã³ãããç解ããŠãã ããã
ã¢ãã©ã€ã¶ãŒã®çµæã®è¡šç€º
ãã«ãã®ãããã€ãšæ§æãå®äºãããã調æ»äžã®ãããžã§ã¯ãã§èŠã€ãã£ãããã€ãã®èå³æ·±ãèŠåã確èªããããšããå§ãããŸãã
èŠå
N1V773 [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),
....
};
éçã¢ãã©ã€ã¶ãŒä»¥å€ã«ããã®æ³šæåãã¹ãã«åæ Œã§ãããã®ã¯ã»ãšãã©ãããŸããããã®ã³ããŒïŒããŒã¹ãã®äŸã¯ããŸãã«ãã®ããã«é©ããŠããŸãã
ã¢ã©ãŒã
N3V703掟çã¯ã©ã¹ãRCT12BannerElementãã®ãflagsããã£ãŒã«ããåºæ¬ã¯ã©ã¹ã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ãã¹ããŒãã¡ã³ãã®çµæã¯ãæ¡ä»¶ã®äžéšã§ããããšå¥åŠã§ããããããããã®ã¹ããŒãã¡ã³ãã¯ä»ã®ãã®ãšæ¯èŒãããã¹ãã§ããã libopenrct2ObservationTower.cpp 38
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
ããèŠãŠã¿ãŸããããimageDirectionã-7ãã7ã®ç¯å²ã«ããå ŽåãimageDirection / 8åŒã¯falseã«ãªããŸãã2çªç®ã®éšåïŒïŒimageDirection / 8ïŒïŒ= 3ã¯ãimageDirectionãç¯å²å€ã§ããããšã確èªããŸãïŒ-31ãã-24ããã³24ãã31ããããããã®æ¹æ³ã§ç¹å®ã®ç¯å²ãå ¥åããããã®çªå·ã確èªããã®ã¯ããªãå¥åŠã«æããŸãããã®ã³ãŒããã©ã°ã¡ã³ãã«ãšã©ãŒããªãå Žåã§ãããããã®æ¡ä»¶ãããæ確ã«æžãçŽãããšããå§ãããŸããããã«ããããã®ã³ãŒããèªãã§ä¿å®ãã人ã ã®ç掻ãã¯ããã«æ¥œã«ãªããŸãã
èŠå
N5V587ãã®çš®ã®å²ãåœãŠã®å¥åŠãªã·ãŒã±ã³ã¹ïŒ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;
....
}
....
}
ãã®ã³ãŒãã¯ãããããéã³ã³ãã€ã«ã«ãã£ãŠååŸããããã®ã§ãã次ã«ãæ®ãããã³ã¡ã³ãããå€æãããšãæ©èœããŠããªãã³ãŒãã®äžéšãåé€ãããŸããããã ããcursorIdã«å¯Ÿããããã€ãã®æäœãæ®ã£ãŠããããããããŸãæå³ããããŸããã
N6èŠå
V1004 [CWE-476] nullptrã«å¯ŸããŠæ€èšŒãããåŸããplayerããã€ã³ã¿ãŒãå®å šã«äœ¿çšãããŸããã§ããããã§ãã¯ã©ã€ã³ïŒ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); // <=
}
....
}
ãã®ã³ãŒãã®ä¿®æ£ã¯éåžžã«ç°¡åã§ãããã¬ãŒã€ãŒã§nullãã€ã³ã¿ãŒã3åãã§ãã¯ããããæ¡ä»¶æŒç®åã®æ¬äœã«è¿œå ããå¿ èŠããããŸããç§ã¯2çªç®ã®ãªãã·ã§ã³ãææ¡ããŸãïŒ
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);
}
}
....
}
èŠå
N7V547 [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);
....
}
....
}
èŠå
N8V1048 [CWE-1164] ' ColumnHeaderPressedCurrentState 'å€æ°ã«åãå€ãå²ãåœãŠãããŸãããlibopenrct2ui CustomListView.cpp 510
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
ã³ãŒãã¯ããªãå¥åŠã«èŠããŸããå€æ°ColumnHeaderPressedCurrentStateå€ãfalseã«åå²ãåœãŠãããšãã«ãã¿ã€ããã¹ããã£ããã圱é¿ãåããå¯èœæ§ããããšæããŸãã
åºå
ã芧ã®ãšãããPVS-Studioéçã¢ãã©ã€ã¶ãŒãTeamCityãããžã§ã¯ãã«çµ±åããã®ã¯éåžžã«ç°¡åã§ããããªããããå¿ èŠãããã®ã¯1ã€ã®å°ããæ§æãã¡ã€ã«ãæžãããšã§ããã³ãŒãã¬ãã¥ãŒã䜿çšãããšããã«ãã®çŽåŸã«åé¡ãç¹å®ã§ããŸããããã«ãããç·šéã®è€éããšã³ã¹ãããŸã å°ããå Žåã«åé¡ãæé€ã§ããŸãã
ãã®èšäºãè±èªã話ãèŽè¡ãšå ±æãããå Žåã¯ã翻蚳ãªã³ã¯ã䜿çšããŠãã ããïŒVladislavStolyarovãPVS-Studioãšç¶ç¶çãªçµ±åïŒTeamCityãOpen RollerCoaster Tycoon2ãããžã§ã¯ãã®åæã