PVS-Studio تجزیہ کار کے استعمال کے لیے موجودہ حالات میں سے ایک CI سسٹمز کے ساتھ اس کا انضمام ہے۔ اور اگرچہ تقریباً کسی بھی مسلسل انضمام کے نظام سے PVS-Studio پروجیکٹ کا تجزیہ صرف چند کمانڈز میں بنایا جا سکتا ہے، ہم اس عمل کو مزید آسان بناتے رہتے ہیں۔ PVS-Studio کو اب ٹیم سٹی - ٹیم سٹی معائنہ کی قسم کے لیے تجزیہ کار آؤٹ پٹ کو فارمیٹ میں تبدیل کرنے کے لیے تعاون حاصل ہے۔ آئیے دیکھتے ہیں کہ یہ کیسے کام کرتا ہے۔
استعمال شدہ سافٹ ویئر کے بارے میں معلومات
زیر مطالعہ منصوبے کے بارے میں معلومات
آئیے ایک عملی مثال پر اس فعالیت کو آزماتے ہیں - آئیے OpenRCT2 پروجیکٹ کا تجزیہ کرتے ہیں۔
ایڈجسٹمنٹ
وقت بچانے کے لیے، میں شاید انسٹالیشن کے عمل کو چھوڑ دوں گا اور اس لمحے سے شروع کروں گا جب میرے کمپیوٹر پر TeamCity سرور چل رہا ہے۔ ہمیں اس پر جانے کی ضرورت ہے: لوکل ہوسٹ:{انسٹالیشن کے عمل کے دوران مخصوص کردہ پورٹ} (میرے معاملے میں، لوکل ہوسٹ:9090) اور اجازت کا ڈیٹا درج کریں۔ داخل ہونے کے بعد ہمارا استقبال کیا جائے گا:
پروجیکٹ بنائیں بٹن پر کلک کریں۔ اگلا، دستی طور پر منتخب کریں اور کھیتوں کو پُر کریں۔
بٹن دبانے کے بعد تخلیق کریں، ترتیبات کے ساتھ ایک ونڈو کے ذریعہ ہمارا استقبال کیا جاتا ہے۔
آئیے کلک کریں۔ تعمیر کنفیگریشن بنائیں.
کھیتوں کو بھریں اور کلک کریں۔ تخلیق کریں. ہم ایک ونڈو دیکھتے ہیں جو آپ سے ورژن کنٹرول سسٹم کو منتخب کرنے کے لیے کہتی ہے۔ چونکہ ذرائع پہلے ہی مقامی طور پر موجود ہیں، کلک کریں۔ جائیے.
آخر میں، ہم پروجیکٹ کی ترتیبات کی طرف بڑھتے ہیں۔
آئیے اسمبلی کے مراحل شامل کریں، ایسا کرنے کے لیے کلک کریں: تعمیراتی مراحل -> تعمیراتی قدم شامل کریں۔.
یہاں ہم منتخب کرتے ہیں:
- رنر کی قسم -> کمانڈ لائن
- چلائیں -> کسٹم اسکرپٹ
چونکہ ہم پروجیکٹ کی تالیف کے دوران تجزیہ کریں گے، اس لیے اسمبلی اور تجزیہ ایک قدم ہونا چاہیے، اس لیے فیلڈ کو پُر کریں۔ اپنی مرضی کے اسکرپٹ:
ہم انفرادی اقدامات کو بعد میں دیکھیں گے۔ یہ ضروری ہے کہ تجزیہ کار کو لوڈ کرنے، پراجیکٹ کو جمع کرنے، اس کا تجزیہ کرنے، رپورٹ کو آؤٹ پٹ کرنے اور اسے فارمیٹ کرنے کے لیے کوڈ کی صرف گیارہ لائنیں لگتی ہیں۔
آخری چیز جو ہمیں کرنے کی ضرورت ہے وہ ہے ماحولیات کے متغیرات کو ترتیب دینا، جس کی میں نے ان کی پڑھنے کی اہلیت کو بہتر بنانے کے کچھ طریقے بتائے ہیں۔ ایسا کرنے کے لیے، آئیے آگے بڑھتے ہیں: پیرامیٹرز -> نیا پیرامیٹر شامل کریں۔ اور تین متغیرات شامل کریں:
آپ کو بس بٹن دبانا ہے۔ رن اوپری دائیں کونے میں۔ جب پروجیکٹ کو جمع اور تجزیہ کیا جا رہا ہے، میں آپ کو اسکرپٹ کے بارے میں بتاؤں گا۔
براہ راست اسکرپٹ
سب سے پہلے، ہمیں تازہ ترین PVS-Studio ڈسٹری بیوشن ڈاؤن لوڈ کرنے کی ضرورت ہے۔ اس کے لیے ہم چاکلیٹی پیکیج مینیجر استعمال کرتے ہیں۔ ان لوگوں کے لیے جو اس کے بارے میں مزید جاننا چاہتے ہیں، اس سے متعلق ہے۔
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"
آخری مرحلہ فارمیٹ شدہ رپورٹ کو ظاہر کرنا ہے۔ stdout، جہاں اسے 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"
اس دوران، پروجیکٹ کی اسمبلی اور تجزیہ کامیابی سے مکمل ہو گیا ہے، ہم ٹیب پر جا سکتے ہیں منصوبوں کی تفصیل اور убедиться в этом.
اب آئیے پر کلک کریں۔ معائنہ کلتجزیہ کار کی رپورٹ دیکھنے کے لیے:
انتباہات کو تشخیصی اصول نمبروں کے مطابق گروپ کیا گیا ہے۔ کوڈ کے ذریعے نیویگیٹ کرنے کے لیے، آپ کو وارننگ کے ساتھ لائن نمبر پر کلک کرنے کی ضرورت ہے۔ اوپری دائیں کونے میں سوالیہ نشان پر کلک کرنے سے آپ کو دستاویزات کے ساتھ ایک نیا ٹیب کھل جائے گا۔ آپ تجزیہ کار کی وارننگ کے ساتھ لائن نمبر پر کلک کر کے کوڈ کے ذریعے بھی جا سکتے ہیں۔ استعمال کرتے وقت ریموٹ کمپیوٹر سے نیویگیشن ممکن ہے۔ 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;
}
تجزیہ کار نے ایک غلطی دیکھی جو متحرک طور پر میموری کو مختص کرنے کے بعد تخلیق آبجیکٹ، جب کوئی استثناء واقع ہوتا ہے، میموری کو صاف نہیں کیا جاتا ہے، اور میموری کا اخراج ہوتا ہے۔
وارننگ 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 تک کی حد میں ہے۔ دوسرا حصہ: (imageDirection/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 جامد تجزیہ کار کو آپ کے TeamCity پروجیکٹ میں ضم کرنا بہت آسان ہے۔ ایسا کرنے کے لیے، صرف ایک چھوٹی کنفیگریشن فائل لکھنا کافی ہے۔ کوڈ کو چیک کرنے سے آپ اسمبلی کے فوراً بعد مسائل کی نشاندہی کر سکیں گے، جو تبدیلیوں کی پیچیدگی اور لاگت کم ہونے پر انہیں ختم کرنے میں مدد کرے گا۔
اگر آپ انگریزی بولنے والے سامعین کے ساتھ اس مضمون کا اشتراک کرنا چاہتے ہیں، تو براہ کرم ترجمہ کا لنک استعمال کریں: Vladislav Stolyarov۔
ماخذ: www.habr.com