यह क्लाउड CI सिस्टम के साथ पीवीएस-स्टूडियो स्टैटिक विश्लेषक का उपयोग करने के बारे में लेखों की हमारी श्रृंखला का एक नया टुकड़ा है। आज हम एक और सेवा, सर्कलसीआई को देखने जा रहे हैं। हम कोडी मीडिया प्लेयर एप्लिकेशन को एक परीक्षण परियोजना के रूप में लेंगे और देखेंगे कि क्या हमें इसके स्रोत कोड में कोई दिलचस्प बग मिल सकता है।
नोट। क्लाउड CI सिस्टम के साथ पीवीएस-स्टूडियो को एकीकृत करने पर पिछले लेख:
काम के माहौल को स्थापित करने और विश्लेषण रिपोर्ट की जांच करने से पहले, मैं उस सॉफ्टवेयर के बारे में कुछ शब्द कहना चाहूंगा जो हम उपयोग और जांच करने जा रहे हैं।
CircleCI स्वचालित सॉफ्टवेयर निर्माण, परीक्षण और तैनाती के लिए क्लाउड CI सेवा है। यह कंटेनर में और वर्चुअल मशीनों पर विंडोज, लिनक्स और मैकओएस दोनों पर प्रोजेक्ट बिल्डिंग का समर्थन करता है।
कोडी एक स्वतंत्र और ओपन-सोर्स क्रॉस-प्लेटफॉर्म मीडिया प्लेयर एप्लीकेशन है। यह उपयोगकर्ताओं को अधिकांश स्ट्रीमिंग मीडिया, जैसे वीडियो, संगीत, पॉडकास्ट और इंटरनेट से वीडियो और साथ ही स्थानीय और नेटवर्क भंडारण मीडिया से सभी आम डिजिटल मीडिया फ़ाइलों को खेलने और देखने की अनुमति देता है। यह प्लगइन्स के माध्यम से थीम और खाल और कार्यक्षमता एक्सटेंशन के उपयोग का समर्थन करता है। कोडी विंडोज, लिनक्स, मैकओएस और एंड्रॉइड के लिए उपलब्ध है।
पीवीएस-स्टूडियो सी, सी ++, सी #, और जावा में लिखे गए अनुप्रयोगों के स्रोत कोड में बग और संभावित कमजोरियों का पता लगाने के लिए एक स्थिर विश्लेषक है। विश्लेषक विंडोज, लिनक्स और मैकओएस पर चलता है।
स्थापित करना
पहले हमें
CircleCI मुख्य पृष्ठ पर जाने और "साइन अप" पर क्लिक करने की आवश्यकता है
अगले पृष्ठ पर, हमें GitHub या Bitbucket खाते के साथ अधिकृत करने की पेशकश की जाती है। हम GitHub चुनते हैं और CircleCI प्राधिकरण पृष्ठ पर जाते हैं।
आवेदन को अधिकृत करने के बाद (हरे रंग के बटन "अधिकृत मंडली" पर क्लिक करके), हम "CircleCI में आपका स्वागत है!" पेज:
यहां हम यह निर्दिष्ट कर सकते हैं कि हम कौन-सी परियोजनाएं बनाना चाहते हैं जो सर्किलसीआई का निर्माण करें। हम अपने भंडार पर टिक करते हैं और "अनुसरण करें" पर क्लिक करते हैं।
रिपॉजिटरी को जोड़ने के बाद, सर्कलसीआई स्वचालित रूप से बिल्ड प्रक्रिया शुरू कर देगा, लेकिन चूंकि हमारे पास अभी रिपॉजिटरी में एक कॉन्फ़िगरेशन फ़ाइल नहीं है, इसलिए बिल्ड कार्य को त्रुटि संदेश के साथ रद्द कर दिया जाएगा।
कॉन्फ़िगरेशन फ़ाइल को जोड़ने से पहले, हमें विश्लेषक लाइसेंस डेटा वाले कुछ वेरिएबल्स को जोड़ना होगा। ऐसा करने के लिए, हम बाएं साइडबार पर "सेटिंग" पर क्लिक करते हैं, "ऑर्गनाइज़ेशन" सेक्शन में "प्रोजेक्ट्स" का चयन करते हैं, और हमारे प्रोजेक्ट के नाम के दाईं ओर cogwheel बटन पर क्लिक करते हैं। एक सेटिंग विंडो दिखाई देगी।
हम "पर्यावरण चर" पृष्ठ पर जाते हैं। यहां हम दो चर,
PVS_USERNAME और
PVS_KEY बनाते हैं , जिसमें उपयोगकर्ता नाम और विश्लेषक लाइसेंस कुंजी होती है।
बिल्ड शुरू करते समय, सर्किलसी ने .circleci / config.yml पर रिपॉजिटरी में संग्रहीत फ़ाइल से जॉब कॉन्फ़िगरेशन को पढ़ा। इसे जोड़ते हैं।
पहले हमें वर्चुअल मशीन की छवि को निर्दिष्ट करने की आवश्यकता है जिसे विश्लेषक चालू करेगा। छवियों की पूरी सूची
यहां उपलब्ध
है ।
version: 2 jobs: build: machine: image: ubuntu-1604:201903-01
अगला, हम प्रोजेक्ट के निर्भरता को स्थापित करने और स्थापित करने के लिए आवश्यक रिपॉजिटरी जोड़ते हैं:
steps: - checkout - run: sudo -- sh -c " add-apt-repository -y ppa:team-xbmc/xbmc-ppa-build-depends && add-apt-repository -y ppa:wsnipex/vaapi && add-apt-repository -y ppa:pulse-eight/libcec && apt-get update" - run: sudo apt-get install -y automake autopoint build-essential cmake curl default-jre gawk gdb gdc gettext git-core gperf libasound2-dev libass-dev libbluray-dev libbz2-dev libcap-dev libcdio-dev libcec4-dev libcrossguid-dev libcurl3 libcurl4-openssl-dev libdbus-1-dev libegl1-mesa-dev libfmt3-dev libfontconfig-dev libfreetype6-dev libfribidi-dev libfstrcmp-dev libgif-dev libgl1-mesa-dev libglu1-mesa-dev libiso9660-dev libjpeg-dev liblcms2-dev libltdl-dev liblzo2-dev libmicrohttpd-dev libmysqlclient-dev libnfs-dev libpcre3-dev libplist-dev libpng-dev libpulse-dev libsmbclient-dev libsqlite3-dev libssl-dev libtag1-dev libtinyxml-dev libtool libudev-dev libusb-dev libva-dev libvdpau-dev libxml2-dev libxmu-dev libxrandr-dev libxrender-dev libxslt1-dev libxt-dev mesa-utils nasm pmount python-dev python-imaging python-sqlite rapidjson-dev swig unzip uuid-dev yasm zip zlib1g-dev wget
पीवीएस-स्टूडियो रिपॉजिटरी को जोड़ना और विश्लेषक स्थापित करना:
- run: wget -q -O - https:
तब हम निर्भरता का निर्माण कर रहे हैं:
- run: sudo make -C tools/depends/target/flatbuffers PREFIX=/usr/local
उसके बाद, हम निर्माण निर्देशिका में Makefiles उत्पन्न करते हैं:
- run: mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Debug ..
अगला चरण परियोजना का विश्लेषण शुरू कर रहा है।
पहले हम एक विश्लेषक लाइसेंस फ़ाइल बनाते हैं। एक अन्य कमांड कंपाइलर द्वारा प्रोजेक्ट बिल्ड को ट्रेस करना शुरू कर देगा।
ट्रेसिंग के बाद का अगला कमांड इस तरह से विश्लेषण चलाता है। यदि आप पीवीएस-स्टूडियो के डेमो संस्करण का उपयोग करते हैं, तो इसे पैरामीटर के साथ लॉन्च करें:
--disableLicenseExpirationCheck ।
अंतिम कमांड विश्लेषक की रिपोर्ट फ़ाइल को HTML रिपोर्ट में परिवर्तित करता है:
- run: pvs-studio-analyzer credentials -o PVS.lic ${PVS_USER} ${PVS_KEY} - run: pvs-studio-analyzer trace -- make -j2 -C build/ - run: pvs-studio-analyzer analyze -j2 -l PVS.lic -o PVS-Studio.log --disableLicenseExpirationCheck - run: plog-converter -t html -o PVS-Studio.html PVS-Studio.log
परीक्षण समाप्त होने के बाद, हम रिपोर्ट सहेजते हैं:
- run: mkdir PVS_Result && cp PVS-Studio.* ./PVS_Result/ - store_artifacts: path: ./PVS_Result
यहाँ .circleci / config.yml फ़ाइल का पूरा पाठ है:
version: 2.1 jobs: build: machine: image: ubuntu-1604:201903-01 steps: - checkout - run: sudo -- sh -c " add-apt-repository -y ppa:team-xbmc/xbmc-ppa-build-depends && add-apt-repository -y ppa:wsnipex/vaapi && add-apt-repository -y ppa:pulse-eight/libcec && apt-get update" - run: sudo apt-get install -y automake autopoint build-essential cmake curl default-jre gawk gdb gdc gettext git-core gperf libasound2-dev libass-dev libbluray-dev libbz2-dev libcap-dev libcdio-dev libcec4-dev libcrossguid-dev libcurl3 libcurl4-openssl-dev libdbus-1-dev libegl1-mesa-dev libfmt3-dev libfontconfig-dev libfreetype6-dev libfribidi-dev libfstrcmp-dev libgif-dev libgl1-mesa-dev libglu1-mesa-dev libiso9660-dev libjpeg-dev liblcms2-dev libltdl-dev liblzo2-dev libmicrohttpd-dev libmysqlclient-dev libnfs-dev libpcre3-dev libplist-dev libpng-dev libpulse-dev libsmbclient-dev libsqlite3-dev libssl-dev libtag1-dev libtinyxml-dev libtool libudev-dev libusb-dev libva-dev libvdpau-dev libxml2-dev libxmu-dev libxrandr-dev libxrender-dev libxslt1-dev libxt-dev mesa-utils nasm pmount python-dev python-imaging python-sqlite rapidjson-dev swig unzip uuid-dev yasm zip zlib1g-dev wget - run: wget -q -O - https:
एक बार जब यह फ़ाइल रिपॉजिटरी में अपलोड हो जाती है, तो सर्किलसी स्वतः निर्माण शुरू कर देगी।
एक बार नौकरी समाप्त होने के बाद, विश्लेषण परिणामों वाली फाइलें "कलाकृतियों" टैब पर डाउनलोड की जा सकती हैं।
विश्लेषण के परिणाम
ठीक है, अब आइए विश्लेषक द्वारा चेतावनी के कुछ आउटपुट देखें।
पीवीएस-स्टूडियो चेतावनी: वी 504 यह अत्यधिक संभावना है कि अर्धविराम ';' 'वापसी' कीवर्ड के बाद गायब है। एडवांस्डसेटिंग। सीपीपी: 1476
void CAdvancedSettings::SetExtraArtwork(const TiXmlElement* arttypes, std::vector<std::string>& artworkMap) { if (!arttypes) return artworkMap.clear(); const TiXmlNode* arttype = arttypes->FirstChild("arttype"); .... }
कोड स्वरूपण निम्नलिखित निष्पादन तर्क का सुझाव देता है:
- यदि आर्टटाइप्स एक शून्य सूचक है, तो विधि वापस आ जाती है;
- यदि आर्टटाइप्स नॉन- नेल पॉइंटर है, तो आर्टवर्क मैप वेक्टर क्लियर हो जाता है और फिर कुछ एक्शन किए जाते हैं।
लेकिन लापता '?' चरित्र यह सब तोड़ता है, और वास्तविक निष्पादन तर्क निम्नानुसार है:
- अगर आर्टटाइप्स एक शून्य सूचक है, तो आर्टवर्क मैप वेक्टर साफ हो जाता है और विधि वापस आ जाती है;
- अगर आर्टटाइप्स नॉन- नेल पॉइंटर है, तो प्रोग्राम जो भी एक्शन आगे आता है, उस पर अमल करता है, लेकिन आर्टवर्क मैप वेक्टर क्लियर नहीं होता है।
एक लंबी कहानी को छोटा करने के लिए, यह स्थिति बग की तरह दिखती है। सब के बाद, आप शायद ही किसी से अपेक्षा करते हैं कि
रिटर्न आर्टवर्क मैप.क्लेयर () जैसे भाव लिखें
; :)।
पीवीएस-स्टूडियो चेतावनी:- V547 अभिव्यक्ति 'lastsector' हमेशा गलत है। udf25.cpp: 636
- V547 अभिव्यक्ति 'lastsector' हमेशा गलत है। udf25.cpp: 644
- V571 आवर्ती जाँच। 'If (lastsector)' स्थिति पहले से ही लाइन 636 में सत्यापित थी। udf25.cpp: 644
int udf25::UDFGetAVDP( struct avdp_t *avdp) { .... uint32_t lastsector; .... lastsector = 0;
// <= के साथ चिह्नित स्पॉट पर ध्यान दें।
Lastsector वैरिएबल को मान 0 असाइन किया गया है और फिर स्टेटमेंट में दो में एक सशर्त अभिव्यक्ति के रूप में उपयोग किया जाता है। चूंकि मान लूप में या असाइनमेंट के बीच नहीं बदलता है, इसलिए स्टेटमेंट्स पर नियंत्रण कभी भी दोनों की
अन्य शाखाओं में नहीं जाएगा।
हालांकि, इसका मतलब यह भी हो सकता है कि डेवलपर्स ने अभी तक अभी तक कार्यशीलता को लागू नहीं किया है (नोट टिप्पणी पर ध्यान दें)।
वैसे, जैसा कि आपने शायद देखा, इस स्निपेट ने एक बार में तीन चेतावनियाँ शुरू कर दीं। लेकिन यहां तक कि कोड के एक टुकड़े के लिए कई चेतावनियां कुछ उपयोगकर्ताओं को पर्याप्त रूप से आश्वस्त नहीं करती हैं, और वे विश्वास करते रहेंगे कि विश्लेषक गलत है ... इस पहलू पर मेरे एक साथी ने एक पोस्ट में विस्तार से चर्चा की है: "
एक दिन से पीवीएस-स्टूडियो यूजर सपोर्ट ":)।
पीवीएस-स्टूडियो चेतावनी: V547 एक्सप्रेशन 'मान। आकार ()! = 2' हमेशा गलत होता है। GUIControlSettings.cpp: 1174
bool CGUIControlRangeSetting::OnClick() { .... std::vector<CVariant> values; SettingConstPtr listDefintion = settingList->GetDefinition(); switch (listDefintion->GetType()) { case SettingType::Integer: values.push_back(m_pSlider-> GetIntValue(CGUISliderControl::RangeSelectorLower)); values.push_back(m_pSlider-> GetIntValue(CGUISliderControl::RangeSelectorUpper)); break; case SettingType::Number: values.push_back(m_pSlider-> GetFloatValue(CGUISliderControl::RangeSelectorLower)); values.push_back(m_pSlider-> GetFloatValue(CGUISliderControl::RangeSelectorUpper)); break; default: return false; } if (values.size() != 2) return false; SetValid(CSettingUtils::SetList(settingList, values)); return IsValid(); }
मान.साइज़ ()! = 2 चेक बेमानी है क्योंकि यह सशर्त अभिव्यक्ति हमेशा
झूठ का मूल्यांकन करेगी। वास्तव में, यदि निष्पादन
स्विच स्टेटमेंट की
केस शाखाओं में से एक में प्रवेश करता है, तो दो तत्व वेक्टर में जोड़े जाएंगे, और चूंकि यह शुरू में खाली था, इसलिए इसका आकार स्वाभाविक रूप से 2 के बराबर हो जाएगा; अन्यथा (यानी यदि
डिफ़ॉल्ट शाखा निष्पादित की जाती है), तो विधि वापस आ जाएगी।
PVS-Studio चेतावनी: V547 एक्सप्रेशन 'prio == 0x7fffffff' हमेशा सच होता है। DBusReserve.cpp: 57
bool CDBusReserve::AcquireDevice(const std::string& device) { .... int prio = INT_MAX; .... res = dbus_bus_request_name( m_conn, service.c_str(), DBUS_NAME_FLAG_DO_NOT_QUEUE | (prio == INT_MAX ? 0 : DBUS_NAME_FLAG_ALLOW_REPLACEMENT),
Prio वैरिएबल को
INT_MAX मान से आरंभीकृत किया जाता है और फिर इसका उपयोग
प्रोनो में ternary ऑपरेटर के एक ऑपरेंड के रूप में किया
जाता है == INT_MAX तुलना, हालांकि इसका मूल्य आरंभीकरण के बाद नहीं बदलता है। इसका मतलब है कि
पुजारी == INT_MAX अभिव्यक्ति
सत्य है और टर्नरी ऑपरेटर हमेशा 0 लौटाएगा।
पीवीएस-स्टूडियो चेतावनी:- V575 संभावित नल पॉइंटर को 'मेमसीपी' फंक्शन में पास किया जाता है। पहले तर्क का निरीक्षण करें। चेक लाइनें: 39, 38. DVDOverlayImage.h: 39
- V575 संभावित नल पॉइंटर को 'मेमसीपी' फंक्शन में पास किया जाता है। पहले तर्क का निरीक्षण करें। चेक लाइनें: 44, 43. DVDOverlayImage.h: 44
CDVDOverlayImage(const CDVDOverlayImage& src) : CDVDOverlay(src) { Data = (uint8_t*)malloc(src.linesize * src.height); memcpy(data, src.data, src.linesize * src.height);
दोनों चेतावनियों का एक ही पैटर्न होता है:
माल्को फंक्शन द्वारा लौटाए गए एक पॉइंटर का उपयोग
मेम्पी फंक्शन में आगे
फुल के लिए चेक किए बिना किया जाता है।
कुछ लोग यह तर्क दे सकते हैं कि
मॉलॉक कभी भी अशक्त सूचक नहीं लौटाएगा, और यदि ऐसा होता है, तो आवेदन के दुर्घटनाग्रस्त होने के लिए बेहतर होगा। यह एक अलग चर्चा का विषय है, लेकिन आपकी राय जो भी हो, मैं अपने साथी द्वारा इस पोस्ट को पढ़ने की सलाह देता हूं: "
यह जांचना महत्वपूर्ण है कि मॉलोक फ़ंक्शन क्या लौटा है "।
यदि आप चाहें, तो आप विश्लेषक को अनुकूलित कर सकते हैं ताकि यह मान न सके कि
मॉलॉक एक अशक्त सूचक लौटा सकता है - यह इस प्रकार की चेतावनियों को आउटपुट करने से रखेगा। अधिक विवरण
यहां पाया जा सकता
है ।
PVS-Studio चेतावनी: V522 एक संभावित नल पॉइंटर 'प्रविष्टि' की dereferencing हो सकती है। चेक लाइनें: 985, 981. emu_msvcrt.cpp: 985
struct dirent *dll_readdir(DIR *dirp) { .... struct dirent *entry = NULL; entry = (dirent*) malloc(sizeof(*entry)); if (dirData->curr_index < dirData->items.Size() + 2) { if (dirData->curr_index == 0) strncpy(entry->d_name, ".\0", 2); .... }
यह उदाहरण पिछले एक के समान है।
मॉलॉक फ़ंक्शन द्वारा लौटाए गए पॉइंटर को
एंट्री वेरिएबल में स्टोर किया जाता है, और फिर इस वेरिएबल का उपयोग बिना पूर्व चेक (
प्रविष्टि-> d_name ) के बिना किया जाता है।
पीवीएस-स्टूडियो चेतावनी: V773 'प्रोग्रेसहैंडलर ’पॉइंटर की दृश्यता का दायरा मेमोरी जारी किए बिना बाहर निकल गया था। एक स्मृति रिसाव संभव है। PVRGUIChannelIconUpdater.cpp: 94
void CPVRGUIChannelIconUpdater::SearchAndUpdateMissingChannelIcons() const { .... CPVRGUIProgressHandler* progressHandler = new CPVRGUIProgressHandler(g_localizeStrings.Get(19286)); for (const auto& group : m_groups) { const std::vector<PVRChannelGroupMember> members = group->GetMembers(); int channelIndex = 0; for (const auto& member : members) { progressHandler->UpdateProgress(member.channel->ChannelName(), channelIndex++, members.size()); .... } progressHandler->DestroyProgress(); }
प्रगति के मूल्यहैंडलर पॉइंटर को
नए ऑपरेटर द्वारा वापस कर दिया गया था। लेकिन इस पॉइंटर के लिए कोई
डिलीट ऑपरेटर नहीं है। इसका मतलब स्मृति रिसाव है।
पीवीएस-स्टूडियो चेतावनी: V557 ऐरे ओवररन संभव है। 'Idx' इंडेक्स सरणी बाउंड से परे इंगित कर रहा है। PlayerCoreFactory.cpp: 240
std::vector<CPlayerCoreConfig *> m_vecPlayerConfigs; bool CPlayerCoreFactory::PlaysVideo(const std::string& player) const { CSingleLock lock(m_section); size_t idx = GetPlayerIndex(player); if (m_vecPlayerConfigs.empty() || idx > m_vecPlayerConfigs.size()) return false; return m_vecPlayerConfigs[idx]->m_bPlaysVideo; }
यदि स्टेटमेंट
m_vecPlayerConfigs वेक्टर के साइज़ को एक निश्चित सीमा तक
रीस्ट्रक्ट करता है, तो साइज़-चेकिंग कंडीशन सही होने पर मेथड रिटर्न। परिणामस्वरूप, जब निष्पादन अंतिम
रिटर्न स्टेटमेंट तक पहुंचता है, तो
m_vecPlayerConfigs वेक्टर का आकार निर्दिष्ट सीमा के भीतर होगा, [1]; IDX]। लेकिन बाद में कुछ पंक्तियाँ, प्रोग्राम
idx पर वेक्टर को अनुक्रमित कर रहा है:
m_vecPlayerConfigs [idx] -> m_bPlaysVideo । इसका मतलब है कि अगर
आईडी वेक्टर के आकार के बराबर है, तो हम वैध सीमा से परे अनुक्रमण करेंगे।
प्लेटिनम पुस्तकालय के कोड से कुछ उदाहरणों के साथ इस लेख को हवा देते हैं।
PVS-Studio चेतावनी: V542 एक विषम प्रकार की कास्ट का निरीक्षण करने पर विचार करें: 'bool' को 'char *'। PltCtrlPoint.cpp: 1617
NPT_Result PLT_CtrlPoint::ProcessSubscribeResponse(...) { .... bool subscription = (request.GetMethod().ToUppercase() == "SUBSCRIBE"); .... NPT_String prefix = NPT_String::Format(" PLT_CtrlPoint::ProcessSubscribeResponse %ubscribe for service \"%s\" (result = %d, status code = %d)", (const char*)subscription?"S":"Uns",
डेवलपर्स के ऑपरेशन की पूर्वता के बारे में गलत धारणाएं हैं। कास्ट
चार को क्या मिलता है
* यह टर्नरी ऑपरेटर (
सब्सक्रिप्शन? "S": "Uns" ) द्वारा दिया गया परिणाम नहीं है बल्कि
सब्सक्रिप्शन चर है। यह अजीब लग रहा है, बहुत कम से कम।
पीवीएस-स्टूडियो चेतावनी: V560 सशर्त अभिव्यक्ति का एक हिस्सा हमेशा गलत होता है: c == '\ t'। NptUtils.cpp: 863
NPT_Result NPT_ParseMimeParameters(....) { .... case NPT_MIME_PARAMETER_PARSER_STATE_NEED_EQUALS: if (c < ' ') return NPT_ERROR_INVALID_SYNTAX;
अंतरिक्ष वर्ण का कोड 0x20 है, और टैब वर्ण का कोड 0x09 है। इसलिए,
c == 't' सब डेप्रेप्रेशन हमेशा
असत्य का मूल्यांकन करेगा क्योंकि यह मामला पहले से ही
c <'' चेक द्वारा कवर किया गया है (जो कि, यदि सही है, तो फ़ंक्शन लौटने का कारण बनेगा)।
निष्कर्ष
जैसा कि यह लेख प्रदर्शित करता है, हम पीवीएस-स्टूडियो द्वारा एक और सीआई सिस्टम (सर्किलसीआई) पर सफलतापूर्वक विश्लेषण स्थापित करते हैं। मैं आपको
डाउनलोड करने और अपने स्वयं के प्रोजेक्ट पर विश्लेषक की
कोशिश करने के लिए आमंत्रित करता हूं। यदि आपके पास पीवीएस-स्टूडियो की स्थापना या उपयोग के बारे में कोई प्रश्न हैं, तो
हमसे संपर्क करने में संकोच न
करें - हमें मदद करने में खुशी होगी।
और, ज़ाहिर है, हम आपको बगैर कोड के चाहते हैं। :)