Karena tema yang gelap, Thunderbird harus menjalankan penganalisa kode

Gambar 3
"Petualangan" dengan klien email Mozilla Thunderbird dimulai dengan peningkatan otomatis ke versi 68.0. Fitur utama dari versi ini adalah ini: lebih banyak teks ditambahkan ke pemberitahuan pop-up dan tema gelap secara default. Ada kesalahan yang ingin saya coba deteksi menggunakan analisis statis. Ini adalah kesempatan untuk sekali lagi memeriksa kode sumber proyek menggunakan PVS-Studio. Ternyata pada saat analisis kesalahan sudah diperbaiki. Tetapi karena kami menarik perhatian pada proyek ini, kami dapat menulis tentang cacat lain yang ditemukan di dalamnya.

Pendahuluan


Tema gelap versi baru Thunderbird terlihat cukup cantik. Saya suka tema gelap. Sudah beralih ke mereka dalam pesan instan, Windows, macOS. Segera, iPhone akan ditingkatkan ke iOS 13, di mana tema gelap telah muncul. Untuk ini, saya bahkan harus mengubah iPhone 5S saya ke model yang lebih baru. Dalam praktiknya, ternyata tema gelap membutuhkan lebih banyak upaya bagi pengembang untuk memilih warna antarmuka. Tidak semua orang mengatasi ini pertama kali. Jadi tag standar saya di Thunderbird mulai terlihat seperti:

Gambar 1


Saya menggunakan enam tag (5 standar + 1 custom) untuk menandai email. Menjadi mustahil untuk menonton setengah dari mereka setelah pembaruan, dan saya memutuskan untuk mengubah warna menjadi lebih terang di pengaturan. Tapi di sini saya menemukan bug:

Gambar 2


Anda tidak dapat mengubah warna tag !!! Lebih tepatnya, itu mungkin, tetapi editor tidak akan membiarkannya disimpan, merujuk pada nama yang ada (WTF ???).

Manifestasi lain dari bug adalah tidak adanya tombol OK, jika Anda mencoba mengubah nama, karena Anda tidak dapat menyimpan dengan nama ini. Anda tidak dapat mengganti nama juga.

Akhirnya, Anda mungkin memperhatikan bahwa tema gelap tidak menyentuh pengaturan, yang juga tidak terlalu indah.

Setelah perjuangan panjang dengan sistem build di Windows, masih mungkin untuk merakit Thunderbird dari source. Versi terbaru dari klien surat ternyata jauh lebih baik daripada rilis terbaru. Di dalamnya, tema gelap sampai ke pengaturan, dan bug ini dengan editor tag juga menghilang. Tetapi agar pekerjaan perakitan proyek tidak sia-sia, penganalisa kode statis PVS-Studio diluncurkan.

Catatan Kode sumber Thunderbird entah bagaimana tumpang tindih dengan basis kode Firefox. Oleh karena itu, analisis mencakup kesalahan dari komponen yang berbeda, yang patut dicermati pengembang tim yang berbeda.

Catatan 2 Sementara artikel sedang ditulis, pembaruan Thunderbird 68.1 keluar dengan perbaikan untuk bug ini:

Gambar 5


comm


comm-central adalah repositori Mercurial dari kode ekstensi Thunderbird, SeaMonkey, dan Lightning.

V501 Ada sub-ekspresi identik '(! Strcmp (header, "Balas-Ke"))' di sebelah kiri dan di sebelah kanan '||' operator. 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; .... } 

Baris tajuk dibandingkan dengan HEADER_REPLY_TO konstan dua kali. Mungkin di tempatnya seharusnya ada konstanta lain.

V501 Ada sub-ekspresi identik 'obj-> options-> header! = MimeHeadersCitation' di sebelah kiri dan di sebelah kanan operator '&&'. 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) { .... } .... } 

Perbandingan aneh lain dari variabel dengan nama yang mirip adalah header . Seperti biasa, ada dua penjelasan yang memungkinkan: pemeriksaan tambahan atau salah ketik.

V517 Penggunaan pola 'jika (A) {...} else jika (A) {...}' terdeteksi. Ada kemungkinan kehadiran kesalahan logis. Periksa baris: 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); } 

Rangkaian ekspresi kondisional dipercepat dengan menekan Ctrl + C dan Ctrl + V. Akibatnya, salah satu cabang tidak pernah dieksekusi.

V517 Penggunaan pola 'jika (A) {...} else jika (A) {...}' terdeteksi. Ada kemungkinan kehadiran kesalahan logis. Periksa baris: 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())); } .... } 

Kondisi pertama dan terakhir adalah sama. Kode tersebut menunjukkan bahwa kode tersebut sedang dalam proses penulisan. Aman untuk mengatakan bahwa dengan probabilitas tinggi kesalahan akan muncul dengan sendirinya setelah kode diselesaikan. Seorang programmer dapat mengubah kode yang dikomentari, tetapi ia tidak akan pernah mendapatkan kontrol. Hati-hati dan berhati-hati dengan kode ini.

V522 Dereferencing dari 'baris' penunjuk nol mungkin terjadi. 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; } 

Dereferencing dari penunjuk baris nol dimungkinkan pada baris berikut:

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

Kemungkinan besar, inisialisasi pointer dilewati sebelum baris ini, misalnya, menggunakan metode GetRow , dll.

V543 Aneh bahwa nilai '-1' ditugaskan ke variabel 'm_lastError' tipe 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; } .... } 

Tipe HRESULT adalah tipe data yang kompleks. Bit variabel yang berbeda dari tipe ini mewakili bidang deskripsi kesalahan yang berbeda. Kode kesalahan harus ditetapkan menggunakan konstanta khusus dari file header sistem.

Beberapa tempat lagi:

  • V543 Aneh bahwa nilai '-1' ditugaskan ke variabel 'm_lastError' tipe HRESULT. MapiApi.cpp 817
  • V543 Aneh bahwa nilai '-1' ditugaskan ke variabel 'm_lastError' tipe HRESULT. MapiApi.cpp 1749

V579 Fungsi memset menerima pointer dan ukurannya sebagai argumen. Itu mungkin sebuah kesalahan. Periksa argumen ketiga. 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 */); .... } 

Variabel bagian adalah penunjuk ke array struktur. Untuk mereset nilai struktur, mereka menggunakan fungsi memset , tetapi mereka mentransfer ukuran pointer ke ukuran area memori.

Tempat mencurigakan lainnya:

  • V579 Fungsi memset menerima pointer dan ukurannya sebagai argumen. Itu mungkin sebuah kesalahan. Periksa argumen ketiga. icalmime.c 385
  • V579 Fungsi memset menerima pointer dan ukurannya sebagai argumen. Itu mungkin sebuah kesalahan. Periksa argumen ketiga. icalparameter.c 114
  • V579 Fungsi snprintf menerima pointer dan ukurannya sebagai argumen. Itu mungkin sebuah kesalahan. Periksa argumen kedua. icaltimezone.c 1908
  • V579 Fungsi snprintf menerima pointer dan ukurannya sebagai argumen. Itu mungkin sebuah kesalahan. Periksa argumen kedua. icaltimezone.c 1910
  • V579 Fungsi strncmp menerima pointer dan ukurannya sebagai argumen. Itu mungkin sebuah kesalahan. Periksa argumen ketiga. sspm.c 707
  • V579 Fungsi strncmp menerima pointer dan ukurannya sebagai argumen. Itu mungkin sebuah kesalahan. Periksa argumen ketiga. sspm.c 813

V595 Pointer 'aValues' digunakan sebelum diverifikasi terhadap nullptr. Periksa baris: 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; } .... } 

Diagnostik V595 biasanya menemukan kesalahan khas penunjuk null pointer. Tetapi ada ditemukan kasus yang sangat menarik, layak mendapat perhatian khusus.

Secara teknis, penganalisa benar bahwa pointer aValues pertama kali direferensikan , kemudian diperiksa, tetapi kesalahannya berbeda. Ini adalah penunjuk ganda, jadi kode yang benar akan terlihat seperti ini:

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

Tempat lain yang sangat mirip:

  • V595 Pointer '_retval' digunakan sebelum diverifikasi terhadap nullptr. Periksa baris: 357, 358. nsLDAPSyncQuery.cpp 357

V1044 Kondisi break loop tidak tergantung pada jumlah iterasi. 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); } .... } 

Kesalahan ini ditemukan menggunakan diagnostik baru, yang akan tersedia di rilis selanjutnya dari penganalisa. Semua variabel yang digunakan dalam kondisi untuk menghentikan loop sementara tidak dimodifikasi, karena variabel ptr2 dan cSet tercampur dalam tubuh fungsi.

netwerk


netwerk berisi antarmuka C dan kode untuk akses tingkat rendah ke jaringan (menggunakan soket dan cache file dan memori) serta akses tingkat lebih tinggi (menggunakan berbagai protokol seperti http, ftp, gopher, castanet). Kode ini juga dikenal dengan nama, "netlib" dan "Necko."

V501 Ada sub-ekspresi identik 'connectStarted' ke kiri dan ke kanan operator '&&'. 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); } .... } 

Pada awalnya, saya berpikir bahwa menduplikasi variabel connectStarted hanya kode berlebihan sampai saya melihat melalui seluruh fungsi yang cukup panjang dan menemukan sebuah fragmen yang serupa. Kemungkinan besar, alih-alih variabel tunggal connectStarted di sini juga harus menjadi variabel connectCalled .

V611 Memori dialokasikan menggunakan operator 'T baru] tetapi dirilis menggunakan operator' hapus '. Pertimbangkan untuk memeriksa kode ini. Mungkin lebih baik menggunakan 'delete [] mData;'. Periksa baris: 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; } 

Pointer mData menunjuk ke array, bukan objek tunggal. Mereka membuat kesalahan di destruktor kelas, lupa menambahkan tanda kurung untuk operator hapus .

V1044 Kondisi break loop tidak tergantung pada jumlah iterasi. 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'; .... } 

Nilai pos ditimpa dalam loop dengan jumlah yang sama. Tampaknya diagnostik baru menemukan kesalahan lain.

gfx


gfx berisi antarmuka C dan kode untuk platform independent drawing and imaging. Dapat digunakan untuk menggambar persegi panjang, garis, gambar, dll. Pada dasarnya, ini adalah satu set antarmuka untuk konteks perangkat (platform) independen platform. Itu tidak menangani widget atau rutinitas menggambar tertentu; itu hanya memberikan operasi primitif untuk menggambar.

V501 Ada sub-ekspresi identik ke kiri dan ke kanan '||' operator: mVRSistem || mVRKomposisi || mVRSystem OpenVRSession.cpp 876

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

Dalam kondisi tersebut, variabel mVRSystem hadir dua kali. Jelas, salah satunya harus diganti dengan mVRChaperone .

dom


dom berisi antarmuka C dan kode untuk mengimplementasikan dan melacak objek DOM (Document Object Model) dalam Javascript. Ini membentuk substruktur C yang menciptakan, menghancurkan dan memanipulasi objek bawaan dan yang ditentukan pengguna sesuai dengan skrip Javascript.

V570 Variabel 'clonedDoc-> mPreloadReferrerInfo' ditugaskan untuk dirinya sendiri. Document.cpp 12049

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

Analyzer mendeteksi penugasan variabel untuk dirinya sendiri.

xpcom


xpcom berisi antarmuka C tingkat rendah, kode C, kode C, sedikit kode rakitan dan alat baris perintah untuk mengimplementasikan mesin dasar komponen XPCOM (yang merupakan singkatan dari "Cross Platform Component Object Model"). XPCOM adalah mekanisme yang memungkinkan Mozilla untuk mengekspor antarmuka dan membuatnya tersedia secara otomatis untuk skrip JavaScript, Microsoft COM dan kode Mozilla C biasa.

V611 Memori dialokasikan menggunakan fungsi 'malloc / realloc' tetapi dirilis menggunakan operator 'hapus'. Pertimbangkan untuk memeriksa logika operasi di belakang variabel 'kunci'. Periksa baris: 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; }; 

Setelah memanggil fungsi strdup , Anda perlu membebaskan memori menggunakan fungsi bebas , bukan operator hapus .

V716 Konversi tipe mencurigakan dalam inisialisasi: '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; } .... } 

Fungsi WinGI SHGetSpecialFolderPathW mengembalikan nilai tipe BOOL , bukan HRESULT . Memeriksa hasil fungsi harus ditulis ulang ke yang benar.

nsprpub


nsprpub berisi kode C untuk lintas platform "C" Runtime Library. Perpustakaan Runtime ā€œCā€ berisi fungsi-fungsi C non-visual dasar untuk mengalokasikan dan membatalkan alokasi memori, mendapatkan waktu dan tanggal, membaca dan menulis file, menangani utas dan menangani serta membandingkan string di semua platform

V647 Nilai tipe 'int' ditugaskan ke pointer tipe 'pendek'. Pertimbangkan untuk memeriksa tugas: '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 */ 

Analyzer mendeteksi penetapan konstanta numerik ke pointer out_flags . Kemungkinan besar, mereka hanya lupa dereferensi padanya:

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

Kesimpulan


Ini bukan akhirnya. Jadilah ulasan kode baru. Kode Thunderbird dan Firefox mencakup dua perpustakaan utama: Layanan Keamanan Jaringan (NSS) dan WebRTC (Web Real Time Communications). Ada beberapa kesalahan yang sangat menarik. Dalam ulasan ini, saya akan tunjukkan satu per satu.

Nss

V597 Kompiler dapat menghapus pemanggilan fungsi 'memset', yang digunakan untuk membersihkan buffer 'newdeskey'. Fungsi RtlSecureZeroMemory () harus digunakan untuk menghapus data pribadi. 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 adalah perpustakaan untuk mengembangkan aplikasi klien dan server yang aman, dan di sini DES Key tidak dibersihkan. Kompiler akan menghapus panggilan memset dari kode, sebagai array newdeskey tidak lagi digunakan dalam kode di luar lokasi ini.

WebRTC

V519 Variabel 'state [state_length - x_length + i]' diberi nilai dua kali berturut-turut. Mungkin ini sebuah kesalahan. Periksa baris: 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]; // <= } .... } 

Pada siklus kedua, data ditulis ke array yang salah, karena penulis menyalin kode dan lupa untuk mengubah nama array dari state ke state_low .

Mungkin ada bug yang lebih menarik dalam proyek-proyek ini yang layak disebut. Dan kami akan melakukannya dalam waktu dekat. Sementara itu, cobalah PVS-Studio di proyek Anda.



Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan ke terjemahan: Svyatoslav Razmyslov. Tema gelap Thunderbird sebagai alasan untuk menjalankan penganalisis kode .

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


All Articles