Статический анализ кода презентация

Содержание

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

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



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

путей выполенения
Динамический анализ
Статический анализ
Ручное тестирование
Нагрузочное тестирование



Слайд 3Чем раньше – тем лучше


Слайд 4Что такое статический анализ кода
Статический анализ можно рассматривать как более дешевый

и автоматизированный способ выполнить обзор кода (code-review).

Преимущества:

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






Слайд 5Инструменты статического анализа
Cppcheck — бесплатный;
Статический анализ входящий в Visual Studio;
Статический анализ

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


Слайд 6Дорого… Почему не только TDD?
в тестах тоже можно ошибиться;
проверка мест, редко

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


Слайд 7В тестах тоже можно ошибиться
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.


Слайд 8Проверка мест, редко получающих управление
V595 The 'node' pointer was utilized before

it was verified against nullptr. Check lines: 1421, 1424.

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");
}
...
}


Слайд 9Обнаружение плавающих ошибок (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


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

моделирование
Статический анализ кода



Слайд 11Не на все варианты кода можно написать юнит-тест: большой объем потребляемой

памяти

#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]);
}


Слайд 12присутствует объявление функции 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 (1400011A6h)
cdqe
mov rcx,qword ptr [i]
mov qword ptr Pointers[rcx*8],rax


Слайд 13Не на все варианты кода можно написать юнит-тест: пользовательский интерфейс
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.


Слайд 14Не на все варианты кода можно написать юнит-тест: другое
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‘.


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


Слайд 16Попробуйте найти ошибку. Задача 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



Слайд 17Попробуйте найти ошибку. Задача 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.


Слайд 18Попробуйте найти ошибку. Задача N2.
bool ots_gdef_parse(...) {
...
const unsigned gdef_header_end

=
static_cast(8) +
gdef->version_2 ? static_cast(2) :
static_cast(0);
...
}

Слайд 19Попробуйте найти ошибку. Задача 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);
...
}


Слайд 20Попробуйте найти ошибку. Задача N3.
int EditStreamPadSilence(....)
{
...
if (hr = AVIFileGetStream(pfileSilence,

&paviSilence, streamtypeAUDIO , 0)
!= AVIERR_OK)
{
ErrMsg("Unable to load silence stream");
return hr;
}
...
}

vscap


Слайд 21Попробуйте найти ошибку. Задача 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)'.


Слайд 22Попробуйте найти ошибку. Задача N4.
void Sys_GetCurrentMemoryStatus(
sysMemoryStats_t &stats ) {

...
memset( &statex, sizeof( statex ), 0 );
...
}

Слайд 23Попробуйте найти ошибку. Задача N4.
void Sys_GetCurrentMemoryStatus(
sysMemoryStats_t &stats ) {

...
memset( &statex, sizeof( statex ), 0 );
...
}

V575 The 'memset' function processes '0' elements. Inspect the third argument.


Слайд 24Попробуйте найти ошибку. Задача N5.
void CAST256::Base::UncheckedSetKey(const byte *userKey,
unsigned int keylength,

const NameValuePairs &)
{
AssertValidKeyLength(keylength);
word32 kappa[8];
...
memset(kappa, 0, sizeof(kappa));
}

Слайд 25Попробуйте найти ошибку. Задача 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.


Слайд 26Попробуйте найти ошибку. Задача N6.
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010

bool GetPlatformFileInfo(PlatformFile file,

PlatformFileInfo* info) {
...
info->is_directory =
file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0;
...
}

Слайд 27Попробуйте найти ошибку. Задача 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 0x00000010

bool GetPlatformFileInfo(PlatformFile file,
PlatformFileInfo* info) {
...
info->is_directory =
file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0;
...
}


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

if(!original_space_accelerators)return;
...
}

BCmenu


Слайд 29Попробуйте найти ошибку. Задача 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


Слайд 30Попробуйте найти ошибку. Задача N8.
BOOL TortoiseBlame::OpenFile(const TCHAR *fileName)
{
...
char *

utf8CheckBuf = lineptr;
while ((bUTF8)&&(*utf8CheckBuf))
{
if ((*utf8CheckBuf == 0xC0)||
(*utf8CheckBuf == 0xC1)||
(*utf8CheckBuf >= 0xF5))
{
bUTF8 = false;
break;
}
...
}

Слайд 31Попробуйте найти ошибку. Задача 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].


Слайд 32Попробуйте найти ошибку. Задача N9.
inline
void elxLuminocity(const PixelRGBi& iPixel,

LuminanceCell< PixelRGBi >& oCell)
{
oCell._luminance = 2220 * iPixel._red +
7067 * iPixel._blue +
0713 * iPixel._green;
oCell._pixel = iPixel;
}

eLynxSDK


Слайд 33Попробуйте найти ошибку. Задача N9.
inline
void elxLuminocity(const PixelRGBi& iPixel,

LuminanceCell< PixelRGBi >& oCell)
{
oCell._luminance = 2220 * iPixel._red +
7067 * iPixel._blue +
0713 * iPixel._green;
oCell._pixel = iPixel;
}

eLynxSDK

V536 Be advised that the utilized constant value is represented by an octal form. Oct: 0713, Dec: 459.


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

p {
if (props.GetItemName(p).compare(SVN_PROP_IGNORE)==0)
{
std::string st = props.GetItemValue(p);
ignoredprops = UTF8ToWide(st.c_str());
// remove all escape chars ('\\')
std::remove(ignoredprops.begin(),
ignoredprops.end(), '\\');
break;
}
}
...
}

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

p {
if (props.GetItemName(p).compare(SVN_PROP_IGNORE)==0)
{
std::string st = props.GetItemValue(p);
ignoredprops = UTF8ToWide(st.c_str());
// remove all escape chars ('\\')
std::remove(ignoredprops.begin(),
ignoredprops.end(), '\\');
break;
}
}
...
}

V530 The return value of function 'empty/remove' is required to be utilized.


Слайд 36Мифы о статическом анализе
статический анализатор это продукт разового применения;
профессиональные разработчики не

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

Слайд 37Миф: статический анализатор это продукт разового применения
«я проверил и нашел мало

ошибок»;
аналогия с предупреждениями компилятора;
ROI;


Слайд 38Миф: профессиональные разработчики не допускают глупых ошибок
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.


Слайд 39Миф: динамический анализ лучше чем статический (или 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.


Слайд 40Миф: можно составить маленькую программу, чтобы оценить инструмент
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

Почему никто не составляет такие примеры?


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

всё актуальнее, так как размеры программ растут.



Слайд 42Дополнительная информация
Анализатор PVS-Studio: http://www.viva64.com/ru/pvs-studio/

Twitter: https://twitter.com/Code_Analysis
E-Mail: karpov@viva64.com
Тел.: +7 (4872) 38-59-95 (GMT +

03:00)


Обратная связь

Если не удалось найти и скачать презентацию, Вы можете заказать его на нашем сайте. Мы постараемся найти нужный Вам материал и отправим по электронной почте. Не стесняйтесь обращаться к нам, если у вас возникли вопросы или пожелания:

Email: Нажмите что бы посмотреть 

Что такое ThePresentation.ru?

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


Для правообладателей

Яндекс.Метрика