Статический анализ кода Карпов Андрей Николаевич к.ф.-м.н., MVP, технический директор ООО «СиПроВер» Сайт: www.viva64.comwww.viva64.com E-Mail: karpov@viva64.comkarpov@viva64.com.

Презентация:



Advertisements
Похожие презентации
Unit II Constructor Cont… Destructor Default constructor.
Advertisements

Data Types in C. A Data Type A data type is –A set of values AND –A set of operations on those values A data type is used to –Identify the type of a variable.
1/27 Chapter 9: Template Functions And Template Classes.
Data Variable and Pointer Variable Pass by Reference Pointer Arithmetic Passing Array Using Pointers Dynamic Allocation.
Operator Overloading Customised behaviour of operators Chapter: 08 Lecture: 26 & 27 Date:
1/30 Chapter 8: Dynamic Binding And Abstract classes.
HPC Pipelining Parallelism is achieved by starting to execute one instruction before the previous one is finished. The simplest kind overlaps the execution.
Inner Classes. 2 Simple Uses of Inner Classes Inner classes are classes defined within other classes The class that includes the inner class is called.
Преобразование типов Макаревич Л. Г.. Операция приведения типов Тип ( выражение ) Тип ( выражение ) (тип) выражение (тип) выражение int a = 5; float b.
Operators and Arithmetic Operations. Operators An operator is a symbol that instructs the code to perform some operations or actions on one or more operands.
SPLAY TREE The basic idea of the splay tree is that every time a node is accessed, it is pushed to the root by a series of tree rotations. This series.
© Luxoft Training 2013 Using Reflection API in Java.
Statistics for Business and Economics, 6e © 2007 Pearson Education, Inc. Chap 1-1 Chapter 1 Why Study Statistics? Statistics for Business and Economics.
Arrays Dr. Ramzi Saifan Slides adapted from Prof. Steven Roehrig.
Welcome to…. YOUR FIRST PART – START TO FINISH 2.
A Short Review Arrays, Pointers and Structures. What is an Array? An array is a collection of variables of the same type and placed in memory contiguously.
Статический анализ кода: современный взгляд Карпов Андрей Николаевич к.ф.-м.н., технический директор ООО «Системы программной верификации»
AVL-Trees COMP171 Fall AVL Trees / Slide 2 Balanced binary tree * The disadvantage of a binary search tree is that its height can be as large as.
MADE BY Darshan Singh Roll No. RD3801A32 downloaded from maintained by sudarshan kumar.
© 2006 Cisco Systems, Inc. All rights reserved. HIPS v Configuring Rules Rule Basics.
Транксрипт:

Статический анализ кода Карпов Андрей Николаевич к.ф.-м.н., MVP, технический директор ООО «СиПроВер» Сайт:

Методы повышения качества кода Доказательство корректности программы Обзоры кода Юнит-тесты (TDD) Регрессионное тестирование Анализ покрытия различных путей выполенения Динамический анализ Статический анализ Ручное тестирование Нагрузочное тестирование …

Чем раньше – тем лучше

Что такое статический анализ кода Статический анализ можно рассматривать как более дешевый и автоматизированный способ выполнить обзор кода (code-review). Преимущества: раннее выявление дефектов; статический анализатор не устаёт; анализ всех ветвей программы; хорошее распараллеливание анализа; выявление ошибок такого типа, о которых программист даже не подозревает.

Инструменты статического анализа Cppcheck бесплатный; Статический анализ входящий в Visual Studio; Статический анализ входящий в Intel Parallel Studio; PC-Lint $389 за одну лицензию или $3500 – за 10, неограниченно по времени; PVS-Studio 3500 за 5 лицензий, год использования; Klocwork за пакет «сервер + 20 клиентов» за год использования; Coverity дорого.

Дорого… Почему не только TDD? в тестах тоже можно ошибиться; проверка мест, редко получающих управление; обнаружение плавающих ошибок (undefined behavior, гейзенбаги); не на все варианты кода можно написать юнит-тест: – сложные счетные алгоритмы; – большой объем потребляемой памяти; – пользовательский интерфейс; – другое.

В тестах тоже можно ошибиться void checkFormatConversion::Test(...) {... static struct { bool _b1, _b2; } ms_2boolean[] = { { false, false }, { false, true }, { true, false }, { true, true } }; const int b2size = sizeof(ms_2boolean) / sizeof(ms_2boolean);... } eLynxSDK V501 There are identical sub-expressions 'sizeof (ms_2boolean)' to the left and to the right of the '/' operator.

Проверка мест, редко получающих управление V595 The 'node' pointer was utilized before it was verified against nullptr. Check lines: 1421, void idBrushBSP::FloodThroughPortals_r( idBrushBSPNode *node,....) {... if ( node->occupied ) { common->Error( "FloodThroughPortals_r: node already occupied\n"); } if ( !node ) { common->Error("FloodThroughPortals_r: NULL node\n"); }... }

Обнаружение плавающих ошибок (undefined behavior, гейзенбаги) bool CLine_Simplification::Simplify( CSG_Shape *pLine, int iPart, bool *Keep) {... Keep[iFloater--] = iAnchor == 0 && iFloater == pLine->Get_Point_Count(iPart) - 1;... } V567 Undefined behavior. The 'iFloater' variable is modified while being used twice between sequence points. saga

Не на все варианты кода можно написать юнит-тест: сложные счетные алгоритмы Примеры: Численное моделирование Статический анализ кода

Не на все варианты кода можно написать юнит-тест: большой объем потребляемой памяти #include void test() { const size_t Gbyte = 1024 * 1024 * 1024; size_t i; char *Pointers[3]; // Allocate for (i = 0; i != 3; ++i) Pointers[i] = (char *)malloc(Gbyte); // Use for (i = 0; i != 3; ++i) Pointers[i][0] = 1; // Free for (i = 0; i != 3; ++i) free(Pointers[i]); }

присутствует объявление функции malloc Pointers[i] = (char *)malloc(Gbyte); mov rcx,qword ptr [Gbyte] call qword ptr [__imp_malloc (14000A518h)] mov rcx,qword ptr [i] mov qword ptr Pointers[rcx*8],rax отсутствует объявление функции malloc Pointers[i] = (char *)malloc(Gbyte); mov rcx,qword ptr [Gbyte] call malloc ( A6h) cdqe mov rcx,qword ptr [i] mov qword ptr Pointers[rcx*8],rax

Не на все варианты кода можно написать юнит-тест: пользовательский интерфейс Fennec Media Project int JoiningProc(HWND hwnd,UINT uMsg, WPARAM wParam,LPARAM lParam) {... OPENFILENAME lofn; memset(&lofn, 0, sizeof(lofn));... lofn.lpstrFilter = uni("All Files (*.*)\0*.*");... } V540 Member 'lpstrFilter' should point to string terminated by two 0 characters.

Не на все варианты кода можно написать юнит-тест: другое void AccessibleContainsAccessible(...) {... auto_ptr child_array(new VARIANT[child_count]);... } V554 Incorrect use of auto_ptr. The memory allocated with 'new []' will be cleaned using 'delete.

Игра – найди ошибку!

Попробуйте найти ошибку. Задача N1. (Пока вы ещё не устали. А анализатор не устаёт!) void drawShadedTexSubQuad(..., const MathUtil::Rectangle * rDest,...) {... if (stsq_observer || memcmp(rDest, &tex_sub_quad_data.rdest, sizeof(rDest))!=0 || tex_sub_quad_data.u1!=u1 || tex_sub_quad_data.v1!=v1 || tex_sub_quad_data.u2!=u2 || tex_sub_quad_data.v2!=v2 || tex_sub_quad_data.G != G)... } Dolphin

Попробуйте найти ошибку. Задача N1. (Пока вы ещё не устали. А анализатор не устаёт!) void drawShadedTexSubQuad(..., const MathUtil::Rectangle * rDest,...) {... if (stsq_observer || memcmp(rDest, &tex_sub_quad_data.rdest, sizeof(rDest))!=0 || tex_sub_quad_data.u1!=u1 || tex_sub_quad_data.v1!=v1 || tex_sub_quad_data.u2!=u2 || tex_sub_quad_data.v2!=v2 || tex_sub_quad_data.G != G)... } Dolphin V579 The memcmp function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the third argument.

Попробуйте найти ошибку. Задача N2. bool ots_gdef_parse(...) {... const unsigned gdef_header_end = static_cast (8) + gdef->version_2 ? static_cast (2) : static_cast (0);... }

Попробуйте найти ошибку. Задача N2. V502 Perhaps the '?:' operator works in a different way than it was expected. The '?:' operator has a lower priority than the '+' operator. bool ots_gdef_parse(...) {... const unsigned gdef_header_end = static_cast (8) + gdef->version_2 ? static_cast (2) : static_cast (0);... }

Попробуйте найти ошибку. Задача N3. int EditStreamPadSilence(....) {... if (hr = AVIFileGetStream(pfileSilence, &paviSilence, streamtypeAUDIO, 0) != AVIERR_OK) { ErrMsg("Unable to load silence stream"); return hr; }... } vscap

Попробуйте найти ошибку. Задача N3. int EditStreamPadSilence(....) {... if (hr = AVIFileGetStream(pfileSilence, &paviSilence, streamtypeAUDIO, 0) != AVIERR_OK) { ErrMsg("Unable to load silence stream"); return hr; }... } vscap V593 Consider reviewing the expression of the 'A = B != C' kind. The expression is calculated as following: 'A = (B != C)'.

Попробуйте найти ошибку. Задача N4. void Sys_GetCurrentMemoryStatus( sysMemoryStats_t &stats ) {... memset( &statex, sizeof( statex ), 0 );... }

Попробуйте найти ошибку. Задача N4. void Sys_GetCurrentMemoryStatus( sysMemoryStats_t &stats ) {... memset( &statex, sizeof( statex ), 0 );... } V575 The 'memset' function processes '0' elements. Inspect the third argument.

Попробуйте найти ошибку. Задача N5. void CAST256::Base::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs &) { AssertValidKeyLength(keylength); word32 kappa[8];... memset(kappa, 0, sizeof(kappa)); }

Попробуйте найти ошибку. Задача N5. void CAST256::Base::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs &) { AssertValidKeyLength(keylength); word32 kappa[8];... memset(kappa, 0, sizeof(kappa)); } V597 The compiler could delete the 'memset' function call, which is used to flush 'kappa' buffer. The RtlSecureZeroMemory() function should be used to erase the private data.

Попробуйте найти ошибку. Задача N6. #define FILE_ATTRIBUTE_DIRECTORY 0x bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {... info->is_directory = file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0;... }

Попробуйте найти ошибку. Задача N6. V564 The '&' operator is applied to bool type value. You've probably forgotten to include parentheses or intended to use the '&&' operator. #define FILE_ATTRIBUTE_DIRECTORY 0x bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {... info->is_directory = file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0;... }

Попробуйте найти ошибку. Задача N7. void BCMenu::InsertSpaces(void) { if(IsLunaMenuStyle()) if(!xp_space_accelerators)return; else if(!original_space_accelerators)return;... } BCmenu

Попробуйте найти ошибку. Задача N7. V563 It is possible that this 'else' branch must apply to the previous 'if' statement. void BCMenu::InsertSpaces(void) { if(IsLunaMenuStyle()) if(!xp_space_accelerators) return; else if(!original_space_accelerators) return;... } BCmenu

Попробуйте найти ошибку. Задача N8. BOOL TortoiseBlame::OpenFile(const TCHAR *fileName) {... char * utf8CheckBuf = lineptr; while ((bUTF8)&&(*utf8CheckBuf)) { if ((*utf8CheckBuf == 0xC0)|| (*utf8CheckBuf == 0xC1)|| (*utf8CheckBuf >= 0xF5)) { bUTF8 = false; break; }... }

Попробуйте найти ошибку. Задача N8. BOOL TortoiseBlame::OpenFile(const TCHAR *fileName) {... char * utf8CheckBuf = lineptr; while ((bUTF8)&&(*utf8CheckBuf)) { if ((*utf8CheckBuf == 0xC0)|| (*utf8CheckBuf == 0xC1)|| (*utf8CheckBuf >= 0xF5)) { bUTF8 = false; break; }... } V547 Expression '* utf8CheckBuf == 0xC0' is always false. The value range of signed char type: [-128, 127].

Попробуйте найти ошибку. Задача N9. inline void elxLuminocity(const PixelRGBi& iPixel, LuminanceCell & oCell) { oCell._luminance = 2220 * iPixel._red * iPixel._blue * iPixel._green; oCell._pixel = iPixel; } eLynxSDK

Попробуйте найти ошибку. Задача N9. inline void elxLuminocity(const PixelRGBi& iPixel, LuminanceCell & oCell) { oCell._luminance = 2220 * iPixel._red * iPixel._blue * iPixel._green; oCell._pixel = iPixel; } eLynxSDK V536 Be advised that the utilized constant value is represented by an octal form. Oct: 0713, Dec: 459.

Попробуйте найти ошибку. Задача N10. STDMETHODIMP CShellExt::Initialize(....) {... ignoredprops.empty(); for (int p=0; p

Попробуйте найти ошибку. Задача N10. STDMETHODIMP CShellExt::Initialize(....) {... ignoredprops.empty(); for (int p=0; p

Мифы о статическом анализе статический анализатор это продукт разового применения; профессиональные разработчики не допускают глупых ошибок; динамический анализ лучше чем статический; можно составить маленькую программу, чтобы оценить инструмент.

Миф: статический анализатор это продукт разового применения «я проверил и нашел мало ошибок»; аналогия с предупреждениями компилятора; ROI;

Миф: профессиональные разработчики не допускают глупых ошибок IdleState CalculateIdleState( unsigned int idle_threshold) {... DWORD current_idle_time = 0;... // Will go -ve if we have been idle for a // long time (2gb seconds). if (current_idle_time < 0) current_idle_time = INT_MAX;... } V547 Expression 'current_idle_time < 0' is always false. Unsigned type value is never < 0.

Миф: динамический анализ лучше чем статический (или valgrind спасёт мир) int Notepad_plus::getHtmlXmlEncoding(....) const {... if (langT != L_XML && langT != L_HTML && langT == L_PHP) return -1;... } V590 Consider inspecting this expression. The expression is excessive or contains a misprint.

Миф: можно составить маленькую программу, чтобы оценить инструмент nsresult PresShell::SetResolution(float aXResolution, float aYResolution) { if (!(aXResolution > 0.0 && aXResolution > 0.0)) { return NS_ERROR_ILLEGAL_VALUE; }... } V501 There are identical sub-expressions to the left and to the right of the '&&' operator: aXResolution > 0.0 && aXResolution > 0.0 Почему никто не составляет такие примеры?

Выводы Си++ живее всех живых и надо как-то справляться с проектами; Статический анализ всё актуальнее, так как размеры программ растут.

Дополнительная информация Анализатор PVS-Studio: Twitter: Тел.: +7 (4872) (GMT + 03:00)