بسبب السمة المظلمة ، كان على ثندربيرد تشغيل محلل الكود

الصورة 3
بدأت "المغامرة" مع عميل البريد الإلكتروني Mozilla Thunderbird بترقية تلقائية إلى الإصدار 68.0. كانت الميزات البارزة لهذا الإصدار هي: يتم إضافة المزيد من النص إلى الإعلامات المنبثقة وسمة داكنة بشكل افتراضي. كان هناك خطأ أردت أن أحاول اكتشافه باستخدام التحليل الثابت. كانت هذه مناسبة للتحقق مرة أخرى من شفرة المصدر للمشروع باستخدام PVS-Studio. اتضح أنه بحلول وقت التحليل كان الخطأ قد تم إصلاحه بالفعل. لكن بما أننا لفتنا الانتباه إلى هذا المشروع ، يمكننا الكتابة عن العيوب الأخرى الموجودة فيه.

مقدمة


المظهر المظلم للإصدار الجديد من Thunderbird يبدو جميلًا. أنا أحب الموضوعات الظلام. تحولت بالفعل لهم في الرسائل الفورية ، ويندوز ، ماك. قريباً ، سيقوم iPhone بالترقية إلى iOS 13 ، حيث ظهر مظهر مظلم. لهذا ، اضطررت إلى تغيير جهاز iPhone 5S إلى طراز أحدث. في الممارسة العملية ، اتضح أن السمة الداكنة تتطلب المزيد من الجهد للمطورين لاختيار ألوان الواجهة. ليس الجميع يتكيف مع هذا في المرة الأولى. لذلك بدأت علاماتي القياسية في ثندربيرد تبدو وكأنها:

الصورة 1


يمكنني استخدام ستة علامات (5 قياسي + 1 مخصص) للاحتفال برسائل البريد الإلكتروني. أصبح من المستحيل مشاهدة نصفهم بعد التحديث ، وقررت تغيير اللون إلى أكثر إشراقًا في الإعدادات. ولكن هنا واجهت خلل:

الصورة 2


لا يمكنك تغيير لون العلامة !!! بتعبير أدق ، هذا ممكن ، لكن المحرر لن يسمح بحفظه ، في إشارة إلى اسم موجود (WTF ؟؟؟).

من مظاهر الشوائب الأخرى تقاعس الزر "موافق" ، إذا حاولت تغيير الاسم ، حيث لا يمكنك الحفظ بهذا الاسم. لا يمكنك إعادة تسمية إما.

أخيرًا ، قد تلاحظ أن السمة الداكنة لم تلمس الإعدادات ، وهي أيضًا ليست جميلة جدًا.

بعد صراع طويل مع نظام الإنشاء في Windows ، كان لا يزال من الممكن تجميع Thunderbird من المصدر. تبين أن أحدث إصدار من عميل البريد أفضل بكثير من الإصدار الأخير. في ذلك ، وصل موضوع مظلم إلى الإعدادات ، واختفى هذا الخطأ مع محرر العلامات أيضا. ولكن حتى لا تضيع أعمال التجميع الخاصة بالمشروع ، تم إطلاق محلل الكود الثابت PVS-Studio .

المذكرة. شفرة مصدر ثندربيرد تتداخل بطريقة أو بأخرى مع قاعدة كود فايرفوكس. لذلك ، تضمن التحليل أخطاء من مكونات مختلفة ، والتي تستحق نظرة فاحصة على مطوري الفرق المختلفة.

ملاحظة 2 أثناء كتابة المقالة ، جاء تحديث Thunderbird 68.1 مع إصلاح لهذا الخطأ:

الصورة 5


بالاتصالات


comm-central هو مستودع للزئبق لرمز امتداد Thunderbird و SeaMonkey و Lightning.

V501 هناك تعبيرات فرعية متطابقة '(! Strcmp (الرأس ، "Reply-To"))' إلى اليسار وإلى يمين '||' المشغل. nsEmitterUtils.cpp 28

extern "C" bool EmitThisHeaderForPrefSetting(int32_t dispType, const char *header) { .... if (nsMimeHeaderDisplayTypes::NormalHeaders == dispType) { if ((!strcmp(header, HEADER_DATE)) || (!strcmp(header, HEADER_TO)) || (!strcmp(header, HEADER_SUBJECT)) || (!strcmp(header, HEADER_SENDER)) || (!strcmp(header, HEADER_RESENT_TO)) || (!strcmp(header, HEADER_RESENT_SENDER)) || (!strcmp(header, HEADER_RESENT_FROM)) || (!strcmp(header, HEADER_RESENT_CC)) || (!strcmp(header, HEADER_REPLY_TO)) || (!strcmp(header, HEADER_REFERENCES)) || (!strcmp(header, HEADER_NEWSGROUPS)) || (!strcmp(header, HEADER_MESSAGE_ID)) || (!strcmp(header, HEADER_FROM)) || (!strcmp(header, HEADER_FOLLOWUP_TO)) || (!strcmp(header, HEADER_CC)) || (!strcmp(header, HEADER_ORGANIZATION)) || (!strcmp(header, HEADER_REPLY_TO)) || (!strcmp(header, HEADER_BCC))) return true; else return false; .... } 

تمت مقارنة سطر الرأس مع HEADER_REPLY_TO الثابت مرتين. ربما في مكانها كان ينبغي أن يكون هناك ثابت آخر.

V501 هناك تعبيرات فرعية متطابقة "obj-> options-> headers! = MimeHeadersCitation" إلى اليسار وإلى يمين عامل التشغيل &&. mimemsig.cpp 536

 static int MimeMultipartSigned_emit_child(MimeObject *obj) { .... if (obj->options && obj->options->headers != MimeHeadersCitation && obj->options->write_html_p && obj->options->output_fn && obj->options->headers != MimeHeadersCitation && sig->crypto_closure) { .... } .... } 

مقارنة أخرى غريبة من متغير باسم مشابه هي رؤوس . كما هو الحال دائمًا ، هناك تفسيران محتملان: فحص إضافي أو خطأ مطبعي.

V517 استخدام نمط "if (A) {...} آخر إذا تم اكتشاف (A) {...}". هناك احتمال لوجود خطأ منطقي. خطوط الفحص: 1306 ، 1308. MapiApi.cpp 1306

 void CMapiApi::ReportLongProp(const char *pTag, LPSPropValue pVal) { if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_LONG)) { nsCString num; nsCString num2; num.AppendInt((int32_t)pVal->Value.l); num2.AppendInt((int32_t)pVal->Value.l, 16); MAPI_TRACE3("%s %s, 0x%s\n", pTag, num, num2); } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_NULL)) { MAPI_TRACE1("%s {NULL}\n", pTag); } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_ERROR)) { // <= MAPI_TRACE1("%s {Error retrieving property}\n", pTag); } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_ERROR)) { // <= MAPI_TRACE1("%s {Error retrieving property}\n", pTag); } else { MAPI_TRACE1("%s invalid value, expecting long\n", pTag); } if (pVal) MAPIFreeBuffer(pVal); } 

تم تسريع سلسلة التعبيرات الشرطية بوضوح عن طريق الضغط على Ctrl + C و Ctrl + V. نتيجة لذلك ، لا يتم تنفيذ أحد الفروع مطلقًا.

V517 استخدام نمط "if (A) {...} آخر إذا تم اكتشاف (A) {...}". هناك احتمال لوجود خطأ منطقي. خطوط التحقق: 777 ، 816. nsRDFContentSink.cpp 777

 nsresult RDFContentSinkImpl::GetIdAboutAttribute(const char16_t** aAttributes, nsIRDFResource** aResource, bool* aIsAnonymous) { .... if (localName == nsGkAtoms::about) { .... } else if (localName == nsGkAtoms::ID) { .... } else if (localName == nsGkAtoms::nodeID) { nodeID.Assign(aAttributes[1]); } else if (localName == nsGkAtoms::about) { // XXX we don't deal with aboutEach... //MOZ_LOG(gLog, LogLevel::Warning, // ("rdfxml: ignoring aboutEach at line %d", // aNode.GetSourceLineNumber())); } .... } 

الشرط الأول والأخير هي نفسها. يظهر الرمز أن الكود في طور الكتابة. من الآمن أن نقول إنه مع وجود احتمال كبير ، فإن الخطأ سيظهر نفسه بعد الانتهاء من الكود. يمكن للمبرمج تغيير الكود المعلق ، لكنه لن يتحكم أبدًا. كن حذرا ودقيقا مع هذا الرمز.

V522 قد يتم إلغاء تحديد "صف" المؤشر الخالي. morkRowCellCursor.cpp 175

 NS_IMETHODIMP morkRowCellCursor::MakeCell( // get cell at current pos in the row nsIMdbEnv* mev, // context mdb_column* outColumn, // column for this particular cell mdb_pos* outPos, // position of cell in row sequence nsIMdbCell** acqCell) { nsresult outErr = NS_OK; nsIMdbCell* outCell = 0; mdb_pos pos = 0; mdb_column col = 0; morkRow* row = 0; morkEnv* ev = morkEnv::FromMdbEnv(mev); if (ev) { pos = mCursor_Pos; morkCell* cell = row->CellAt(ev, pos); if (cell) { col = cell->GetColumn(); outCell = row->AcquireCellHandle(ev, cell, col, pos); } outErr = ev->AsErr(); } if (acqCell) *acqCell = outCell; if (outPos) *outPos = pos; if (outColumn) *outColumn = col; return outErr; } 

التراجع عن مؤشر فارغة الصف ممكن على السطر التالي:

 morkCell* cell = row->CellAt(ev, pos); 

على الأرجح ، تم تخطي تهيئة المؤشر قبل هذا السطر ، على سبيل المثال ، باستخدام أسلوب GetRow ، إلخ.

V543 من الغريب أن يتم تعيين القيمة "-1" للمتغير "m_lastError" من نوع HRESULT. MapiApi.cpp 1050

 class CMapiApi { .... private: static HRESULT m_lastError; .... }; CMsgStore *CMapiApi::FindMessageStore(ULONG cbEid, LPENTRYID lpEid) { if (!m_lpSession) { MAPI_TRACE0("FindMessageStore called before session is open\n"); m_lastError = -1; return NULL; } .... } 

نوع HRESULT هو نوع بيانات معقد. تمثل البتات المختلفة لمتغير من هذا النوع حقول وصف خطأ مختلفة. يجب تعيين رمز الخطأ باستخدام ثوابت خاصة من ملفات رأس النظام.

زوجان أكثر من هذه الأماكن:

  • V543 من الغريب أن يتم تعيين القيمة "-1" للمتغير "m_lastError" من نوع HRESULT. MapiApi.cpp 817
  • V543 من الغريب أن يتم تعيين القيمة "-1" للمتغير "m_lastError" من نوع HRESULT. MapiApi.cpp 1749

V579 تتلقى الدالة memset المؤشر وحجمها كوسائط. ربما يكون خطأ. تفقد الحجة الثالثة. icalmime.c 195

 icalcomponent* icalmime_parse(....) { struct sspm_part *parts; int i, last_level=0; icalcomponent *root=0, *parent=0, *comp=0, *last = 0; if ( (parts = (struct sspm_part *) malloc(NUM_PARTS*sizeof(struct sspm_part)))==0) { icalerror_set_errno(ICAL_NEWFAILED_ERROR); return 0; } memset(parts,0,sizeof(parts)); sspm_parse_mime(parts, NUM_PARTS, /* Max parts */ icalmime_local_action_map, /* Actions */ get_string, data, /* data for get_string*/ 0 /* First header */); .... } 

متغير أجزاء مؤشر إلى مجموعة من الهياكل. لإعادة ضبط قيم الهياكل ، استخدموا الدالة memset ، لكنهم نقلوا حجم المؤشر إليها بحجم قطعة من الذاكرة.

أماكن مشبوهة أخرى:

  • V579 تتلقى الدالة memset المؤشر وحجمها كوسائط. ربما يكون خطأ. تفقد الحجة الثالثة. icalmime.c 385
  • V579 تتلقى الدالة memset المؤشر وحجمها كوسائط. ربما يكون خطأ. تفقد الحجة الثالثة. icalparameter.c 114
  • V579 تتلقى الدالة snprintf المؤشر وحجمها كوسائط. ربما يكون خطأ. تفقد الحجة الثانية. icaltimezone.c 1908
  • V579 تتلقى الدالة snprintf المؤشر وحجمها كوسائط. ربما يكون خطأ. تفقد الحجة الثانية. icaltimezone.c 1910
  • V579 تتلقى الدالة strncmp المؤشر وحجمها كوسائط. ربما يكون خطأ. تفقد الحجة الثالثة. sspm.c 707
  • V579 تتلقى الدالة strncmp المؤشر وحجمها كوسائط. ربما يكون خطأ. تفقد الحجة الثالثة. sspm.c 813

V595 تم استخدام مؤشر "aValues" قبل أن يتم التحقق منه ضد nullptr. خطوط التحقق: 553 ، 555. nsLDAPMessage.cpp 553

 NS_IMETHODIMP nsLDAPMessage::GetBinaryValues(const char *aAttr, uint32_t *aCount, nsILDAPBERValue ***aValues) { .... *aValues = static_cast<nsILDAPBERValue **>( moz_xmalloc(numVals * sizeof(nsILDAPBERValue))); if (!aValues) { ldap_value_free_len(values); return NS_ERROR_OUT_OF_MEMORY; } .... } 

التشخيص V595 عادةً ما يجد أخطاء dereferencing مؤشر فارغة نموذجي. ولكن كان هناك قضية مثيرة للاهتمام للغاية ، تستحق اهتماما خاصا.

من الناحية الفنية ، يكون المحلل على حق في أن مؤشر aValues ​​يتم إلغاء ترجمته أولاً ، ثم يتم التحقق منه ، لكن الخطأ مختلف. هذا مؤشر مزدوج ، لذلك يجب أن يبدو الرمز الصحيح كما يلي:

 *aValues = static_cast<nsILDAPBERValue **>( moz_xmalloc(numVals * sizeof(nsILDAPBERValue))); if (!*aValues) { ldap_value_free_len(values); return NS_ERROR_OUT_OF_MEMORY; } 

مكان آخر مشابه جدا:

  • V595 تم استخدام المؤشر '_retval' قبل أن يتم التحقق منه مقابل nullptr. خطوط التحقق: 357 ، 358. nsLDAPSyncQuery.cpp 357

لا تعتمد شروط فاصل الحلقة V1044 على عدد التكرارات. mimemoz2.cpp 1795

 void ResetChannelCharset(MimeObject *obj) { .... if (cSet) { char *ptr2 = cSet; while ((*cSet) && (*cSet != ' ') && (*cSet != ';') && (*cSet != '\r') && (*cSet != '\n') && (*cSet != '"')) ptr2++; if (*cSet) { PR_FREEIF(obj->options->default_charset); obj->options->default_charset = strdup(cSet); obj->options->override_charset = true; } PR_FREEIF(cSet); } .... } 

تم العثور على هذا الخطأ باستخدام تشخيص جديد ، والذي سيكون متاحًا في الإصدار التالي من المحلل. لا يتم تعديل جميع المتغيرات المستخدمة في الشرط لإيقاف حلقة التكرار ، لأنه يتم خلط متغيرات ptr2 و cSet في جسم الوظيفة.

netwerk


يحتوي netwerk على واجهات ورمز C للوصول المنخفض إلى الشبكة (باستخدام مآخذ وذاكرة التخزين المؤقت للملفات والذاكرة) بالإضافة إلى الوصول إلى المستوى الأعلى (باستخدام بروتوكولات مختلفة مثل http ، ftp ، gopher ، castanet). يُعرف هذا الرمز أيضًا باسم "netlib" و "Necko".

V501 هناك تعبيرات فرعية مماثلة "connectStarted" إلى اليسار وإلى يمين المشغل "&&". nsSocketTransport2.cpp 1693

 nsresult nsSocketTransport::InitiateSocket() { .... if (gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase() && connectStarted && connectCalled) { // <= good, line 1630 SendPRBlockingTelemetry( connectStarted, Telemetry::PRCONNECT_BLOCKING_TIME_NORMAL, Telemetry::PRCONNECT_BLOCKING_TIME_SHUTDOWN, Telemetry::PRCONNECT_BLOCKING_TIME_CONNECTIVITY_CHANGE, Telemetry::PRCONNECT_BLOCKING_TIME_LINK_CHANGE, Telemetry::PRCONNECT_BLOCKING_TIME_OFFLINE); } .... if (gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase() && connectStarted && connectStarted) { // <= fail, line 1694 SendPRBlockingTelemetry( connectStarted, Telemetry::PRCONNECT_FAIL_BLOCKING_TIME_NORMAL, Telemetry::PRCONNECT_FAIL_BLOCKING_TIME_SHUTDOWN, Telemetry::PRCONNECT_FAIL_BLOCKING_TIME_CONNECTIVITY_CHANGE, Telemetry::PRCONNECT_FAIL_BLOCKING_TIME_LINK_CHANGE, Telemetry::PRCONNECT_FAIL_BLOCKING_TIME_OFFLINE); } .... } 

في البداية ، اعتقدت أن تكرار متغير connectStarted هو مجرد رمز لا لزوم له حتى نظرت إلى كامل الوظيفة الطويلة بما فيه الكفاية وعثرت على جزء مماثل. على الأرجح ، بدلا من متغير واحد connectStarted هنا يجب أن يكون أيضا connectCalled متغير.

V611 تم تخصيص الذاكرة باستخدام عامل التشغيل "T []" الجديد ولكن تم إصدارها باستخدام عامل التشغيل "delete". النظر في فحص هذا الرمز. من الأفضل استخدام "delete [] mData؛". خطوط التحقق: 233 ، 222. DataChannel.cpp 233

 BufferedOutgoingMsg::BufferedOutgoingMsg(OutgoingMsg& msg) { size_t length = msg.GetLeft(); auto* tmp = new uint8_t[length]; // infallible malloc! memcpy(tmp, msg.GetData(), length); mLength = length; mData = tmp; mInfo = new sctp_sendv_spa; *mInfo = msg.GetInfo(); mPos = 0; } BufferedOutgoingMsg::~BufferedOutgoingMsg() { delete mInfo; delete mData; } 

يشير مؤشر mData إلى صفيف ، وليس كائن واحد. لقد ارتكبوا خطأ في destructor الفئة ، متناسين إضافة الأقواس المربعة لمشغل الحذف .

لا تعتمد شروط فاصل الحلقة V1044 على عدد التكرارات. ParseFTPList.cpp 691

 int ParseFTPList(....) { .... pos = toklen[2]; while (pos > (sizeof(result->fe_size) - 1)) pos = (sizeof(result->fe_size) - 1); memcpy(result->fe_size, tokens[2], pos); result->fe_size[pos] = '\0'; .... } 

يتم استبدال قيمة pos في الحلقة بنفس المقدار. يبدو أن التشخيص الجديد وجد خطأ آخر.

GFX


يحتوي gfx على واجهات C ورمز للرسم والتصوير المستقل للمنصة. يمكن استخدامه لرسم المستطيلات والخطوط والصور بشكل أساسي ، هي مجموعة من الواجهات لسياق (رسم) جهاز مستقل عن النظام الأساسي. لا يتعامل مع الحاجيات أو إجراءات الرسم المحددة ؛ يوفر فقط العمليات البدائية للرسم.

V501 هناك تعبيرات فرعية مماثلة إلى اليسار وإلى يمين "||" المشغل: mVRSystem || mVRCompositor || mVRSystem OpenVRSession.cpp 876

 void OpenVRSession::Shutdown() { StopHapticTimer(); StopHapticThread(); if (mVRSystem || mVRCompositor || mVRSystem) { ::vr::VR_Shutdown(); mVRCompositor = nullptr; mVRChaperone = nullptr; mVRSystem = nullptr; } } 

في الحالة ، يوجد mVRSystem المتغير مرتين. من الواضح ، يجب استبدال واحد منهم بـ mVRChaperone .

دوم


يحتوي dom على واجهات ورمز C لتطبيق وتتبع كائنات DOM (طراز كائن المستند) في Javascript. إنه يشكل البنية التحتية C التي تقوم بإنشاء وتدمير ومعالجة الكائنات المضمنة والمعرّفة من قِبل المستخدم وفقًا للبرنامج النصي Javascript.

V570 يتم تعيين المتغير 'clonedDoc-> mPreloadReferrerInfo' لنفسه. Document.cpp 12049

 already_AddRefed<Document> Document::CreateStaticClone( nsIDocShell* aCloneContainer) { .... clonedDoc->mReferrerInfo = static_cast<dom::ReferrerInfo*>(mReferrerInfo.get())->Clone(); clonedDoc->mPreloadReferrerInfo = clonedDoc->mPreloadReferrerInfo; .... } 

اكتشف المحلل مهمة المتغير لنفسه.

XPCOM


يحتوي xpcom على واجهات C منخفضة المستوى ، C رمز ، C رمز ، قليلا من رمز التجميع وأدوات سطر الأوامر لتنفيذ الآلية الأساسية لمكونات XPCOM (التي تقف على "طراز كائن النظام الأساسي للمكونات"). XPCOM هي الآلية التي تسمح لـ Mozilla بتصدير الواجهات وجعلها متوفرة تلقائيًا لنصوص JavaScript ، ول Microsoft COM ولرمز Mozilla C العادي.

V611 تم تخصيص الذاكرة باستخدام وظيفة "malloc / realloc" ولكن تم إصدارها باستخدام عامل التشغيل "delete". النظر في فحص منطق العملية وراء المتغير "مفتاح". خطوط التحقق: 143 ، 140. nsINIParser.h 143

 struct INIValue { INIValue(const char* aKey, const char* aValue) : key(strdup(aKey)), value(strdup(aValue)) {} ~INIValue() { delete key; delete value; } void SetValue(const char* aValue) { delete value; value = strdup(aValue); } const char* key; const char* value; mozilla::UniquePtr<INIValue> next; }; 

بعد استدعاء وظيفة strdup ، تحتاج إلى تحرير الذاكرة باستخدام الوظيفة المجانية ، وليس مشغل الحذف .

V716 تحويل النوع المشبوه في التهيئة: 'HRESULT var = BOOL'. SpecialSystemDirectory.cpp 73

 BOOL SHGetSpecialFolderPathW( HWND hwnd, LPWSTR pszPath, int csidl, BOOL fCreate ); static nsresult GetWindowsFolder(int aFolder, nsIFile** aFile) { WCHAR path_orig[MAX_PATH + 3]; WCHAR* path = path_orig + 1; HRESULT result = SHGetSpecialFolderPathW(nullptr, path, aFolder, true); if (!SUCCEEDED(result)) { return NS_ERROR_FAILURE; } .... } 

ترجع الدالة WinGI SHGetSpecialFolderPathW قيمة نوع BOOL ، وليس HRESULT . يجب إعادة كتابة التحقق من نتائج الوظيفة إلى الوظيفة الصحيحة.

nsprpub


يحتوي nsprpub على رمز C لـ Runtime Library "C" عبر النظام الأساسي. تحتوي مكتبة وقت تشغيل "C" على وظائف C غير مرئية أساسية لتخصيص الذاكرة وإلغاء تخصيصها ، والحصول على الوقت والتاريخ ، وقراءة الملفات وكتابتها ، والتعامل مع مؤشرات الترابط ، والتعامل مع السلاسل ومقارنتها عبر جميع الأنظمة الأساسية

V647 يتم تعيين قيمة النوع "int" إلى مؤشر النوع "short". ضع في اعتبارك فحص المهمة: 'out_flags = 0x2'. prsocket.c 1220

 #define PR_POLL_WRITE 0x2 static PRInt16 PR_CALLBACK SocketPoll( PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) { *out_flags = 0; #if defined(_WIN64) if (in_flags & PR_POLL_WRITE) { if (fd->secret->alreadyConnected) { out_flags = PR_POLL_WRITE; return PR_POLL_WRITE; } } #endif return in_flags; } /* SocketPoll */ 

اكتشف المحلل تعيين ثابت رقمي لمؤشر out_flags . على الأرجح ، لقد نسوا ببساطة التراجع عنه:

 if (fd->secret->alreadyConnected) { *out_flags = PR_POLL_WRITE; return PR_POLL_WRITE; } 

استنتاج


هذه ليست النهاية. كن مراجعات رمز جديد. يشتمل كود Thunderbird و Firefox على مكتبتين رئيسيتين: خدمات أمان الشبكات (NSS) و WebRTC (اتصالات الويب في الوقت الفعلي). كانت هناك بعض الأخطاء المثيرة للاهتمام للغاية. في هذا الاستعراض ، سوف تظهر واحدة في وقت واحد.

NSS

V597 يمكن للمترجم حذف استدعاء دالة "memset" ، والذي يستخدم لمسح المخزن المؤقت "newdeskey". يجب استخدام الدالة RtlSecureZeroMemory () لمسح البيانات الخاصة. pkcs11c.c 1033

 static CK_RV sftk_CryptInit(....) { .... unsigned char newdeskey[24]; .... context->cipherInfo = DES_CreateContext( useNewKey ? newdeskey : (unsigned char *)att->attrib.pValue, (unsigned char *)pMechanism->pParameter, t, isEncrypt); if (useNewKey) memset(newdeskey, 0, sizeof newdeskey); sftk_FreeAttribute(att); .... } 

NSS هي مكتبة لتطوير تطبيقات العميل والخادم الآمنة ، وهنا لم يتم تنظيف DES Key. سيقوم المترجم بإزالة استدعاء memset من الكود ، كما لم يعد يتم استخدام مجموعة newdeskey في التعليمات البرمجية خارج هذا الموقع.

يتطلب WebRTC

V519 يتم تعيين القيم "state [state_length - x_length + i]" لقيمتين متتاليتين. ربما هذا خطأ. خطوط التحقق: 83 ، 84. filter_ar.c 84

 size_t WebRtcSpl_FilterAR(....) { .... for (i = 0; i < state_length - x_length; i++) { state[i] = state[i + x_length]; state_low[i] = state_low[i + x_length]; } for (i = 0; i < x_length; i++) { state[state_length - x_length + i] = filtered[i]; state[state_length - x_length + i] = filtered_low[i]; // <= } .... } 

في الدورة الثانية ، تتم كتابة البيانات إلى المصفوفة الخطأ ، لأن المؤلف قام بنسخ الكود ونسى تغيير اسم المصفوفة من حالة إلى ولاية .

ربما هناك أخطاء أكثر إثارة للاهتمام في هذه المشاريع التي تستحق الذكر. وسوف نفعل ذلك في المستقبل القريب. في غضون ذلك ، جرب PVS-Studio في مشروعك.



إذا كنت ترغب في مشاركة هذه المقالة مع جمهور يتحدث الإنجليزية ، فالرجاء استخدام الرابط الخاص بالترجمة: Svyatoslav Razmyslov. موضوع الظلام ثندربيرد كسبب لتشغيل محلل التعليمات البرمجية .

Source: https://habr.com/ru/post/ar469129/


All Articles