PVS-Studio analyzer استعمال ڪرڻ لاءِ سڀ کان وڌيڪ موجوده منظرنامن مان هڪ آهي ان جو انضمام CI سسٽم سان. ۽ جيتوڻيڪ PVS-اسٽوڊيو پروجيڪٽ جو تجزيو تقريبن ڪنهن به مسلسل انٽيگريشن سسٽم مان صرف چند حڪمن ۾ ٺاهي سگهجي ٿو، اسان انهي عمل کي اڃا به وڌيڪ آسان بڻائڻ جاري رکون ٿا. PVS-اسٽوڊيو هاڻي ٽيم سٽي - ٽيم سٽي انسپيڪشن ٽائپ لاءِ هڪ فارميٽ ۾ تجزيي جي پيداوار کي تبديل ڪرڻ جي حمايت ڪئي آهي. اچو ته ڏسو ته اهو ڪيئن ڪم ڪري ٿو.
استعمال ٿيل سافٽ ويئر بابت ڄاڻ
مطالعي هيٺ پروجيڪٽ بابت ڄاڻ
اچو ته هن ڪارڪردگي کي عملي مثال تي آزمائي - اچو ته تجزيو ڪريون OpenRCT2 پروجيڪٽ.
adjustment
وقت بچائڻ لاءِ، مان شايد انسٽاليشن جي عمل کي ڇڏي ڏيندس ۽ ان وقت کان شروع ڪندس جڏهن مون وٽ ٽيم سٽي سرور آهي منهنجي ڪمپيوٽر تي. اسان کي وڃڻو پوندو: localhost:{انسٽاليشن جي عمل دوران بيان ڪيل پورٽ} (منهنجي صورت ۾، localhost:9090) ۽ اختيار ڪرڻ واري ڊيٽا داخل ڪريو. داخل ٿيڻ کان پوءِ اسان کي سلام ڪيو ويندو:
ڪلڪ ڪريو پروجيڪٽ ٺاهيو بٽڻ. اڳيون، دستي طور تي چونڊيو ۽ فيلڊ ۾ ڀريو.
بٽڻ دٻائڻ کان پوء ٺاهيو، اسان کي سيٽنگن سان گڏ ونڊو طرفان سلام ڪيو ويندو.
اچو ته ڪلڪ ڪريو ٺاھيو ٺاھ جوڙ.
فيلڊ ۾ ڀريو ۽ ڪلڪ ڪريو ٺاهيو. اسان هڪ ونڊو ڏسون ٿا جيڪو توهان کي ورزن ڪنٽرول سسٽم چونڊڻ لاءِ پڇي ٿو. جيئن ته ذريعن اڳ ۾ ئي مقامي طور تي واقع آهن، ڪلڪ ڪريو ڇڏي ڏيو.
آخرڪار، اسان پروجيڪٽ سيٽنگون ڏانهن وڃو.
اچو ته اسيمبليءَ جا مرحلا شامل ڪريون، ھي ڪرڻ لاءِ ڪلڪ ڪريو: تعمير قدم -> تعمير قدم شامل ڪريو.
هتي اسان چونڊيو ٿا:
- رنر جو قسم -> ڪمانڊ لائن
- رن -> ڪسٽم اسڪرپٽ
جيئن ته اسان پروجيڪٽ جي تاليف دوران تجزيو انجام ڏينداسين، اسيمبلي ۽ تجزيو هڪ قدم هجڻ گهرجي، تنهنڪري فيلڊ ڀريو رواج اسڪرپٽ:
اسان بعد ۾ انفرادي قدمن تي نظر ڪنداسين. اهو ضروري آهي ته تجزيي کي لوڊ ڪرڻ، پروجيڪٽ کي گڏ ڪرڻ، ان جو تجزيو ڪرڻ، رپورٽ کي ڪڍڻ ۽ ان کي فارميٽ ڪرڻ لاء صرف ڪوڊ جون يارنهن لائينون لڳن ٿيون.
آخري شيء جيڪا اسان کي ڪرڻ جي ضرورت آهي ماحول جي متغيرن کي ترتيب ڏيو، جن کي مون انهن جي پڙهڻ جي صلاحيت کي بهتر ڪرڻ لاء ڪجهه طريقا بيان ڪيا آهن. هن کي ڪرڻ لاء، اچو ته اڳتي وڌو: پيٽرولر -> نئون پيٽرولر شامل ڪريو ۽ ٽي متغير شامل ڪريو:
توهان سڀني کي ڪرڻو آهي بٽڻ کي دٻايو هل مٿي ساڄي ڪنڊ ۾. جڏهن پروجيڪٽ گڏ ڪيو پيو وڃي ۽ تجزيو ڪيو پيو وڃي، مان توهان کي اسڪرپٽ بابت ٻڌائيندس.
سڌي طرح اسڪرپٽ
پهرين، اسان کي ڊائون لوڊ ڪرڻ جي ضرورت آهي جديد PVS-اسٽوڊيو تقسيم. ان لاءِ اسان استعمال ڪريون ٿا چاڪليٽ پيڪيج مينيجر. انھن لاء جيڪي ھن بابت وڌيڪ ڄاڻڻ چاھيو ٿا، ھڪڙو لاڳاپيل آھي
choco install pvs-studio -y
اڳيون، اچو ته لانچ ڪريون CLMonitor پروجيڪٽ بلڊ ٽريڪنگ يوٽيلٽي.
%CLmon% monitor –-attach
ان کان پوء اسان منصوبي کي ماحولياتي متغير جي طور تي تعمير ڪنداسين ايم ايس بي MSBuild جي نسخي جو رستو آھي مون کي تعمير ڪرڻ جي ضرورت آھي
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
اچو ته PVS-اسٽوڊيو لاءِ لاگ ان ۽ لائسنس ڪيچ داخل ڪريون:
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
تعمير مڪمل ٿيڻ کان پوء، اڳ ۾ پروسيس ٿيل فائلون ۽ جامد تجزيو پيدا ڪرڻ لاء ٻيهر CLMonitor کي هلائڻ:
%CLmon% analyze -l "c:ptest.plog"
ان کان پوء اسان اسان جي تقسيم مان هڪ ٻيو استعمال ڪنداسين. PlogConverter ھڪڙي رپورٽ کي ھڪڙي معياري شڪل مان ھڪڙي ٽيم سٽي-مخصوص فارميٽ ۾ تبديل ڪري ٿو. انهي جي مهرباني، اسان ان کي سڌو سنئون تعمير ونڊو ۾ ڏسي سگهنداسين.
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
آخري قدم ۾ فارميٽ ٿيل رپورٽ ڊسپلي ڪرڻ آهي اسٽوريج، جتي ان کي ورتو ويندو ٽيم سٽي پارسر طرفان.
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"
ساڳئي وقت ۾، منصوبي جي اسيمبلي ۽ تجزيو ڪاميابي سان مڪمل ڪيو ويو آهي، اسان ٽيب ڏانهن وڃو پروجيڪٽ ۽ پڪ ڪريو.
هاڻي اچو ته ڪلڪ ڪريو مجموعي چڪاسanalyzer رپورٽ ڏسڻ لاءِ:
ڊيڄاريندڙن کي تشخيصي ضابطن جي انگن اکرن سان گڏ ڪيو ويو آهي. ڪوڊ ذريعي نيويگيٽ ڪرڻ لاء، توهان کي ڊيڄاريندڙ سان لائن نمبر تي ڪلڪ ڪرڻ جي ضرورت آهي. مٿي ساڄي ڪنڊ ۾ سوال جي نشان تي ڪلڪ ڪندي توهان کي دستاويزن سان گڏ هڪ نئون ٽيب کوليندو. توھان پڻ ڪري سگھوٿا ڪوڊ ذريعي نيويگيٽ ڪري سگھوٿا لائن نمبر تي ڪلڪ ڪري تجزيي وارن وارننگ سان. ريموٽ ڪمپيوٽر کان نيويگيشن ممڪن آهي جڏهن استعمال ڪندي SourceTreeRoot مارڪر ڪو به ماڻهو جيڪو تجزيي جي آپريشن جي هن موڊ ۾ دلچسپي رکي ٿو پاڻ کي لاڳاپيل سيڪشن سان واقف ڪري سگهي ٿو
تجزيي جي نتيجن کي ڏسڻ
ھاڻي ته اسان ٺاھڻ ۽ ٺاھڻ جو ڪم ڪيو آھي، اچو ته ھڪڙي نظر رکون ڪجھ دلچسپ ڊيڄاريندڙن تي مليا آھن پروجيڪٽ ۾ جيڪي اسان ڏسي رھيا آھيون.
خبردار N1
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
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
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};
يقينن، بنيادي طبقي ۽ اولاد ۾ ساڳئي نالي سان متغير استعمال ڪرڻ هميشه غلطي ناهي. بهرحال، وراثت ٽيڪنالاجي پاڻ کي فرض ڪري ٿو ته والدين طبقي جا سڀئي شعبا ٻار جي طبقي ۾ موجود آهن. ورثي ۾ ساڳئي نالي سان شعرن کي بيان ڪندي، اسان مونجهارو متعارف ڪرايو.
خبردار N4
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
اچو ته هڪ ويجهي نظر وٺو. اظهار تصوير جي هدايت/8 غلط ٿيندو جيڪڏهن تصوير جي هدايت -7 کان 7 تائين جي حد ۾ آهي. ٻيو حصو: (تصوير جي هدايت / 8) != 3 چيڪ تصوير جي هدايت حد کان ٻاهر هجڻ لاءِ: -31 کان -24 تائين ۽ 24 کان 31 تائين. اهو مون لاءِ ڪافي عجيب لڳي ٿو انگن کي چيڪ ڪرڻ لاءِ هڪ خاص حد ۾ شامل ڪرڻ لاءِ هن طريقي سان ۽، جيتوڻيڪ ڪوڊ جي هن ٽڪڙي ۾ ڪا به غلطي نه آهي، مان انهن شرطن کي ٻيهر لکڻ جي صلاح ڏيندس وڌيڪ واضح ٿيڻ لاءِ. اهو انهن ماڻهن لاءِ زندگي تمام گهڻو آسان بڻائيندو جيڪي هن ڪوڊ کي پڙهندا ۽ برقرار رکندا.
خبردار N5
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
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 پوائنٽر ڏانهن، يا ان کي مشروط بيان جي جسم ۾ شامل ڪريو. مان ٻيو اختيار ڏيندس:
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
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
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
ڪوڊ بلڪل عجيب لڳي ٿو. اهو مون کي لڳي ٿو ته اتي هڪ ٽائپو هو يا ته حالت ۾ يا جڏهن متغير کي ٻيهر تفويض ڪيو ويو ڪالم هيڊر پريس ٿيل ڪرنٽ اسٽيٽ مطلب ڪوڙي.
ٿڪل
جئين اسان ڏسي سگهون ٿا، PVS-Studio جامد تجزيه ڪندڙ کي توهان جي ٽيم سٽي پروجيڪٽ ۾ ضم ڪرڻ بلڪل سادو آهي. هن کي ڪرڻ لاء، اهو ڪافي آهي صرف هڪ ننڍڙي ترتيب واري فائيل لکڻ لاء. ڪوڊ چيڪ ڪرڻ توهان کي اسيمبلي کان فوري طور تي مسئلن جي نشاندهي ڪرڻ جي اجازت ڏيندو، جيڪا انهن کي ختم ڪرڻ ۾ مدد ڪندي جڏهن تبديلين جي پيچيدگي ۽ قيمت اڃا به گهٽ آهي.
جيڪڏهن توهان هن مضمون کي انگريزي ڳالهائيندڙ سامعين سان حصيداري ڪرڻ چاهيو ٿا، مهرباني ڪري ترجمو لنڪ استعمال ڪريو: Vladislav Stolyarov.
جو ذريعو: www.habr.com