• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
 

Сравнение диагностических возможностей анализаторов при проверке 64-битного кода

on

  • 445 views

В статье производится сравнение специализированного статического анализатора Viva64 со статическими ...

В статье производится сравнение специализированного статического анализатора Viva64 со статическими анализаторами общего назначения Parasoft C++test и Gimpel Software PC-Lint. Сравнение производится в рамках задачи переноса 32-битного Си/Си++ кода на 64-битные системы или разработки нового кода с учетом особенностей 64-битной архитектуры.

Statistics

Views

Total Views
445
Views on SlideShare
445
Embed Views
0

Actions

Likes
0
Downloads
1
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Сравнение диагностических возможностей анализаторов при проверке 64-битного кода Сравнение диагностических возможностей анализаторов при проверке 64-битного кода Document Transcript

    • Сравнение диагностическихвозможностей анализаторов припроверке 64-битного кодаАвтор: Андрей КарповДата: 30.05.2008АннотацияВ статье производится сравнение специализированного статического анализатора Viva64 состатическими анализаторами общего назначения Parasoft C++test и Gimpel Software PC-Lint.Сравнение производится в рамках задачи переноса 32-битного Си/Си++ кода на 64-битныесистемы или разработки нового кода с учетом особенностей 64-битной архитектуры.ВведениеЦель данной статьи - продемонстрировать преимущества анализатора Viva64 по сравнению сдругими продуктами, обладающими схожими функциональными возможностями. Viva64 - этоспециализированный статический анализатор для верификации 64-битного Си/Си++ кода [ 1].Сферой его применения является разработка нового 64-битного кода или перенос старого кода на64-битные системы. На данный момент анализатор реализован для операционной системыWindows и представляет собой подключаемый модуль к среде разработки Visual Studio 2005/2008.Актуальность этой статьи заключается в отсутствии систематизированной информации овозможностях современных статических анализаторов, которые заявлены как средствадиагностики 64-битных ошибок. В рамках этой статьи мы сравним три наиболеераспространенных анализатора, реализующие проверки 64-битного кода: Viva64, Parasoft C++test,Gimpel Software PC-Lint.Произведенные сравнения будут отражены в виде таблицы, после чего мы кратко рассмотримкаждый из критериев оценки. Но вначале объясним некоторые понятия, которые будутиспользоваться в этой статье.1. Термины и определения1.1. Модель данныхПод моделью данных следует понимать соотношения размерностей типов, принятых в рамкахсреды разработки. Для одной операционной системы могут существовать несколько средствразработки, придерживающихся разных моделей данных. Но обычно преобладает только однамодель, наиболее соответствующая аппаратной и программной среде. Примером может служить64-битная операционная система Windows, в которой родной моделью данных является LLP64. Нодля совместимости 64-битная система Windows поддерживает исполнение 32-битных программ,которые работают в режиме модели данных ILP32LL.
    • В таблице N1 приведены наиболее распространенные модели данных. Нас в первую очередь вэтой таблице интересует модель данных LP64 и LLP64. Таблица 1. Наиболее распространенные модели данных.Модели данных LP64 и LLP64 отличаются только размером типа "long". Но в этом различиизаключена существенная разница в рекомендуемых методологиях в разработке программ под 64-битные операционные системы семейства Unix и Windows. Например, для хранения указателей исоздания циклов для обработки большого количества элементов в Unix программахрекомендуется использовать тип long или unsigned long. В тоже время в Windows программах этитипы непригодны и вместо них следует использовать типы ptrdiff_t и size_t. Более подробно сособенностями использования различных моделей данных можно познакомиться в статье"Забытые проблемы разработки 64-битных программ" [2].В данной статье мы говорим о моделях данных по той причине, что различные статическиеанализаторы не всегда одинаково хорошо приспособлены как к модели данных LP64 так и LLP64.Забегая вперед, можно сказать, что анализаторы Parasoft C++test и Gimpel Software PC-Lint лучшеприспособлены к Unix системам, чем к Windows.1.2. Memsize-типыДля упрощения изложения материала мы будем использовать термин memsize-тип. Термин"memsize" возник, как попытка лаконично назвать все типы, которые способны хранить в себеразмер указателей и индексов самых больших массивов. Memsize-тип способен хранить в себеразмер максимального массива, который может быть теоретически выделен в рамках даннойархитектуры.Под memsize-типом мы будем понимать все простые типы данных языка Си/Си++, которые на 32-битой архитектуре имеют размер 32-бита, а на 64-битной архитектуре - 64-бита. Обратитевнимание, что в Windows системах тип long не является memsize-типом, а в Unix системахявляется. Для наглядности представим основные memsize-типы в виде таблицы N2.
    • Таблица 2. Примеры memsize-типов.2. Сравнительная таблицаПриступим непосредственно к сравнению статических анализаторов. Сравнительная информацияпредставлена в таблице N3. Список критериев оценки был составлен на основе документации кстатическим анализаторам, статьям и другим дополнительным ресурсам. Вы можетеознакомиться с основными источниками по следующим адресам: • Статья: Andrey Karpov, Evgeniy Ryzhkov. 20 issues of porting C++ code on the 64-bit platform. • Parasoft C++test: C++Test Users Guide (User Items: 3264bit_xxxxxxx.rule) • Gimpel Software PC-Lint: 64-bit Test (C) Checking programs against the LP64 model. • Program Verification Systems Viva64: On-line help.
    • Таблица N3. Сравнение статических анализаторов с точки зрения поиска специфических для 64- битного кода ошибок.3. Критерии оценкиУказанные в таблице названия критериев оценки мало о чем говорят сами по себе. Поэтомукратко рассмотрим каждый из них. Первому критерию будет соответствовать пункт 3.1, второму -3.2 и так далее.Более подробную информацию о типичных ошибках при переносе программ на 64-битныесистемы Вы можете получить из следующих статей: 20 ловушек переноса Си++ - кода на 64-битную платформу [3], Проблемы тестирования 64-битных приложений [4], Разработкаресурсоемких приложений в среде Visual C++ [5].3.1. Использование memsize-типов в качестве фактических аргументов вфункциях с переменным количеством аргументовКлассическим примером является некорректное использование функций printf, scanf и ихразновидностей:1) const char *invalidFormat = "%u"; size_t value = SIZE_MAX; printf(invalidFormat, value);2) char buf[9]; sprintf(buf, "%p", pointer);В первом случае не учитывается тот факт, что тип size_t не эквивалентен типу unsigned на 64-битной платформе. Это приведет к выводу на печать некорректного результата, в случае еслиvalue > UINT_MAX.Во втором случае не учитывается, что размер указателя в будущем может составить более 32 бит.В результате на 64-битной архитектуре данный код приведет к переполнению буфера.3.2. Использование магических константВ некачественном коде часто встречаются магические числовые константы, наличие которыхопасно само по себе. При миграции кода на 64-битную платформу эти константы могут сделатькод неработоспособным, если участвуют в операциях вычисления адреса, размера объектов или вбитовых операциях. К основным магическим константам можно отнести: 4, 32, 0x7fffffff,0x80000000, 0xffffffff. Пример:size_t ArraySize = N * 4;intptr_t *Array = (intptr_t *)malloc(ArraySize);
    • 3.3. Хранение в double целочисленных значений, представленныхmemsize-типомТип double, как правило, имеет размер 64-бита, и совместим со стандартом IEEE-754 на 32-битныхи 64-битных системах. Иногда в коде тип double используется для хранения и работы сцелочисленными типами:size_t a = size_t(-1);double b = a;--a;--b;size_t c = b; // x86: a == c // x64: a != cДанный пример еще можно пытаться оправдать на 32-битной системе, где тип double способенбез потерь хранить 32-битное целое значение, так как имеет 52 значащих бита. Но при попыткесохранить в double 64-битное целое число точное значение может быть потеряно.3.4. Некорректная работа с операциями сдвигаОперации сдвига при невнимательном использовании могут принести много неприятностей припереходе от 32-битной к 64-битной системе. Рассмотрим функцию, выставляющую в переменнойтипа memsize, указанный бит в 1:ptrdiff_t SetBitN(ptrdiff_t value, unsigned bitNum) { ptrdiff_t mask = 1 << bitNum; return value | mask;}Приведенный код работоспособен на 32-битной архитектуре и позволяет выставлять биты сномерами от 0 до 31. После переноса программы на 64-битную платформу возникнетнеобходимость выставлять биты от 0 до 63. Но вызов функции SetBitN(0, 32) вернет 0. Следуетучесть, что "1" имеет тип int и при сдвиге на 32 позиции произойдет переполнение и конечныйрезультат будет неверен.3.5. Упаковка указателей не в memsize-типыБольшое количество ошибок при мигрировании на 64-битные системы связано с изменениемразмера указателя по отношению к размеру обычных целых. Многие программисты в своих 32-битных программах хранили указатели в таких типах как int и unsigned. Это конечно не корректно сточки зрения 64-битных моделей данных. Пример:char *p;p = (char *) ((unsigned int)p & PAGEOFFSET);
    • Следует четко помнить, что для целочисленного представления указателей следует использоватьтолько memsize-типы. К счастью этот тип ошибок хорошо диагностируется не только статическимианализаторами, но и компиляторами при включении соответствующих опций.3.6. Использование memsize-типов в объединениях (union)Особенностью объединения (union) в языке Си/Си++ является то, что для всех элементов - членовобъединения - выделяется одна и та же область памяти. Хотя доступ к этой области памятивозможен с использованием любого из элементов, элемент для этой цели должен выбираться так,чтобы полученный результат был осмысленным.Следует внимательно отнестись к объединениям, имеющим в своем составе указатели и другиечлены типа memsize. Разработчик часто ошибочно предполагает, что размер memsize-типа будетвсегда равняться группе других объектов на всех архитектурах. Пример неверной функции,реализующей табличный алгоритм для подсчета количества нулевых битов в переменной "value":union SizetToBytesUnion { size_t value; struct { unsigned char b0, b1, b2, b3; } bytes;} u;SizetToBytesUnion u;u.value = value;size_t zeroBitsN = TranslateTable[u.bytes.b0] + TranslateTable[u.bytes.b1] + TranslateTable[u.bytes.b2] + TranslateTable[u.bytes.b3];3.7. Изменение типа массиваИногда в программах необходимо (или просто удобно) представлять элементы массива в видеэлементов другого типа. Опасное и безопасное приведение типов продемонстрировано вследующем коде:int array[4] = { 1, 2, 3, 4 };enum ENumbers { ZERO, ONE, TWO, THREE, FOUR };//safe cast (for MSVC2005/2008)ENumbers *enumPtr = (ENumbers *)(array);cout << enumPtr[1] << " ";
    • //unsafe castsize_t *sizetPtr = (size_t *)(array);cout << sizetPtr[1] << endl;//Output on 32-bit system: 2 2//Output on 64 bit system: 2 171798691873.8. Ошибки при использовании виртуальных функций с аргументамитипа memsize.Если у Вас в программе имеются большие иерархии наследования классов с виртуальнымифункциями, то существует вероятность использования по невнимательности аргументовразличных типов, но которые фактически совпадают на 32-битной системе. Например, в базовомклассе Вы используете в качестве аргумента виртуальной функции тип size_t, а в наследнике - типunsigned. Соответственно, на 64-битной системе этот код будет некорректен.Такая ошибка не обязательно кроется в сложных иерархиях наследования, и вот один изпримеров:сlass CWinApp { ... virtual void WinHelp(DWORD_PTR dwData, UINT nCmd);};class CSampleApp : public CWinApp { ... virtual void WinHelp(DWORD dwData, UINT nCmd);};Такие ошибки могут возникать не только из-за невнимательности программиста. Приведенная впримере ошибка возникнет, если вы разрабатывали свой код для ранних версий библиотеки MFC,где функция WinHelp в классе CWinApp имела прототип вида:virtual void WinHelp(DWORD dwData, UINT nCmd = HELP_CONTEXT);Естественно, что в своем коде вы также использовали тип DWORD. В Microsoft Visual C++2005/2008 прототип функции изменили. На 32-битной системе программа продолжит корректноработать, так как здесь типы DWORD и DWORD_PTR совпадают. Неприятности проявляют себя в64-битной программе. Получатся две функции с одинаковыми именами, но с различнымипараметрами, в результате чего перестанет вызываться пользовательский код.3.9. Некорректная арифметика с указателямиРассмотрим на следующем примере:unsigned short a16, b16, c16;
    • char *pointer;...pointer += a16 * b16 * c16;Данный пример корректно работает с указателями, если значение выражения "a16 * b16 * c16" непревышает UINT_MAX (4Gb). Такой код мог всегда корректно работать на 32-битной платформе,так как программа все равно никогда бы не смогла выделить массив большего размера. На 64-битной архитектуре размер массива превысил UINT_MAX элементов. Допустим, мы хотимсдвинуть значение указателя на 6.000.000.000 байт, и поэтому переменные a16, b16 и c16 имеютзначения 3000, 2000 и 1000 соответственно. При вычислении выражения "a16 * b16 * c16" всепеременные, согласно правилам языка Си++, будут приведены к типу int, а уже затем будетпроизведено их умножение. В ходе выполнения умножения произойдет переполнение.Некорректный результат выражения будет расширен до типа ptrdiff_t и произойдет некорректноевычисление указателя.Вот еще один пример, который работоспособен в 32-битном варианте и не работоспособен в 64-битном:int A = -2;unsigned B = 1;int array[5] = { 1, 2, 3, 4, 5 };int *ptr = array + 3;ptr = ptr + (A + B); //Invalid pointer value on 64-bit platformprintf("%in", *ptr); //Access violation on 64-bit platformДавайте проследим, как происходит вычисление выражения "ptr + (A + B)": • Согласно правилам языка Си++ переменная A типа int приводится к типу unsigned. • Происходит сложение A и B. В результате мы получаем значение 0xFFFFFFFF типа unsigned.Затем происходит вычисление выражения "ptr + 0xFFFFFFFFu", но что из этого выйдет, будетзависеть от размера указателя на данной архитектуре. Если сложение будет происходить в 32-битной программе, то данное выражение будет эквивалентно "ptr - 1" и мы успешно распечатаемчисло 3.В 64-битной программе к указателю честным образом прибавится значение 0xFFFFFFFFu, врезультате чего указатель окажется далеко за пределами массива.3.10. Некорректная индексация больших массивовВ программировании на языке Си, а затем и Си++, сложилась практика использования в качествеиндексов для работы с массивами переменных типа int и unsigned. Но время идет, и все меняется.И вот теперь пришло время сказать: "Больше так не делайте! Используйте для индексации(больших) массивов только memsize-типы." Пример ошибочного кода, использующего типunsigned:unsigned Index = 0;
    • while (MyBigNumberField[Index] != id) Index++;Приведенный код не сможет обработать в 64-битной программе массив, содержащий болееUINT_MAX элементов. После доступа к элементу с индексом UINT_MAX произойдет переполнениепеременной Index и мы получим вечный цикл.Еще раз обращаем внимание Windows разработчиков, что тип long в 64-битной Windows остался32-битным. Поэтому рекомендации Unix разработчиков использовать для длинных циклов типlong неуместен.3.11. Смешанное использование простых целочисленных типов иmemsize-типовСмешанное использование memsize- и не memsize-типов в выражениях может приводить кнекорректным результатам на 64-битных системах и быть связано с изменением диапазонавходных значений. Рассмотрим ряд примеров:size_t Count = BigValue;for (unsigned Index = 0; Index != Count; ++Index){ ... }Это пример вечного цикла, если Count > UINT_MAX. Предположим, что на 32-битных системах этоткод работал с диапазоном менее UINT_MAX итераций. Но 64-битный вариант программы можетобрабатывать больше данных и ему может потребоваться большее количество итераций.Поскольку значения переменной Index лежат в диапазоне [0..UINT_MAX], то условие "Index !=Count" никогда не выполнится, что и приводит к бесконечному циклу.Приведем небольшой код, показывающий опасность неаккуратных выражений со смешаннымитипами (результаты получены с использованием Microsoft Visual C++ 2005, 64-битный режимкомпиляции):int x = 100000;int y = 100000;int z = 100000;intptr_t size = 1; // Result:intptr_t v1 = x * y * z; // -1530494976intptr_t v2 = intptr_t(x) * y * z; // 1000000000000000intptr_t v3 = x * y * intptr_t(z); // 141006540800000intptr_t v4 = size * x * y * z; // 1000000000000000intptr_t v5 = x * y * z * size; // -1530494976intptr_t v6 = size * (x * y * z); // -1530494976intptr_t v7 = size * (x * y) * z; // 141006540800000
    • intptr_t v8 = ((size * x) * y) * z; // 1000000000000000intptr_t v9 = size * (x * (y * z)); // -1530494976Необходимо, чтобы все операнды в подобных выражениях были заранее приведены к типубольшей разрядности. Помните, что выражение видаintptr_t v2 = intptr_t(x) * y * z;вовсе не гарантирует правильный результат. Оно гарантирует только то, что выражение "intptr_t(x)* y * z" будет иметь тип intptr_t. Правильный результат, показанный этим выражением в примере- не более чем везение.3.12. Опасные неявные приведения типов при вызове функцийОпасность смешанного использования memsize- и не memsize-типов может присутствовать нетолько в выражениях. Рассмотрим пример:void foo(ptrdiff_t delta);int i = -2;unsigned k = 1;foo(i + k);Ранее в статье (см. Некорректная арифметика с указателями) мы уже встречались с подобнойситуацией. Здесь некорректный результат возникает из-за неявного расширения фактического 32-битного аргумента до 64-бит в момент вызова функции.3.13. Опасные неявные приведения типов при возврате значения изфункции.Опасное неявное приведение типов может возникать и при использовании оператора return.Пример:extern int Width, Height, Depth;size_t GetIndex(int x, int y, int z) { return x + y * Width + z * Width * Height;}...MyArray[GetIndex(x, y, z)] = 0.0f;Несмотря на то, что мы возвращаем значение типа size_t, выражение "x + y * Width + z * Width *Height" вычисляется с использованием типа int. В случае работы с большими массивами (болееINT_MAX элементов) данный код будет вести себя некорректно, и мы будем адресоваться не к темэлементам массива MyArray, к которым рассчитываем.3.14. ИсключенияГенерирование и обработка исключений с участием целочисленных типов не является хорошейпрактикой программирования на языке Си++. Для этих целей следует использовать более
    • информативные типы, например классы, производные от классов std::exception. Но иногдаприходится работать с менее качественным кодом, таким как показано ниже:char *ptr1;char *ptr2;try { try { throw ptr2 - ptr1; } catch (int) { std::cout << "catch 1: on x86" << std::endl; }}catch (ptrdiff_t) { std::cout << "catch 2: on x64" << std::endl;}Следует тщательно избегать генерирования или обработку исключений с использованиемmemsize-типов, так как это чревато изменением логики работы программы.3.15. Явные приведения типовБудьте аккуратны с явными приведениями типов. Они могут изменить логику выполненияпрограммы при изменении разрядности типов или спровоцировать потерю значащих битов.Привести типовые примеры ошибок, связанных с явным приведением типов сложно, так как ониочень разнообразны и специфичны для разных программ. С некоторыми из ошибок, связанных сявным приведением типов, Вы уже познакомились ранее. Но в целом бывает полезнопросматривать все явные приведения типов, в которых участвуют memsize-типы.3.16. Перегруженные функцииПри переносе 32-битных программ на 64-битную платформу может наблюдаться изменениелогики ее работы, связанное с использованием перегруженных функций. Если функция перекрытадля 32-битных и 64-битных значений, то обращение к ней с аргументом типа memsize будеттранслироваться в различные вызовы на различных системах.Такое изменение логики хранит в себе опасность. Примером может служить запись и чтение изфайла данных посредством набора функций вида:class CMyFile { ... void Write(__int32 &value);
    • void Write(__int64 &value);};CMyFile object;SSIZE_T value;object.Write(value);Данный код в зависимости от режима компиляции (32 или 64 бит) запишет в файл различноеколичество байт, что может привести к нарушению совместимости форматов файлов.3.17. Битовые поляЕсли Вы используете битовые поля, то необходимо учитывать, что использование memsize-типовповлечет изменение размеров структур и выравнивания. Но это не все. Рассмотрим тонкийпример:struct BitFieldStruct { unsigned short a:15; unsigned short b:13;};BitFieldStruct obj;obj.a = 0x4000;size_t addr = obj.a << 17; //Sign Extensionprintf("addr 0x%Ixn", addr);//Output on 32-bit system: 0x80000000//Output on 64-bit system: 0xffffffff80000000Обратите внимание, если приведенный пример скомпилировать для 64-битной системы, то ввыражении "addr = obj.a << 17;" будет присутствовать знаковое расширение, несмотря на то, чтообе переменные addr и obj.a являются беззнаковыми. Это знаковое расширение обусловленоправилами приведения типов, которые применяются следующим образом:1) Член структуры obj.a преобразуется из битового поля типа unsigned short в тип int. Мы получаемтип int, а не unsigned int из-за того, что 15-битное поле помещается в 32-битное знаковое целое.2) Выражение "obj.a << 17" имеет тип int, но оно преобразуется в ptrdiff_t и затем в size_t, передтем как будет присвоено переменной addr. Знаковое расширение происходит в моментсовершения преобразования из int в ptrdiff_t.
    • 3.18. Использование жестко заданных значений при вычислениисмещений внутри структурОпасными играми является самостоятельное вычисление адресов полей внутри структур.Действия такого рода часто приводят к генерации некорректного кода. Диагностика типовыхошибок такого рода представлена в анализаторе C++Test, но, к сожалению, плохо описана.3.19. Использование типа longИспользование long-типов в кросплатформенном коде теоретически всегда опасно при переносекода с 32-битной на 64-битную систему. Это связано тем, что тип long имеет разный размер в двухнаиболее распространенных моделях данных - LP64 и LLP64. Данный тип проверки реализуетпоиск всех long в коде приложений.3.20. Использование макросов, мешающих компилятору проверять типыДанная проверка реализована в C++Test. В Viva64 и PC-Lint она не реализована, но все макросыраскрывается и все равно происходит полная проверка. Поэтому будем считать, что в Viva64 и PC-Lint данный тип проверки также реализован.3.21. Переполнение массивов с явно заданным размеромИногда можно обнаружить переполнение массива, которое произойдет при переходе на 64-битную архитектуру. Например:struct A { long n, m; };void foo(const struct A *p) { static char buf[ 8 ]; // should have used sizeof memcpy(buf, p, sizeof( struct A )); //Owerflow ...4. Эффективность использования статических анализаторовОб эффективности использования статических анализаторов говорить сложно. Безусловно,методология статического анализа крайне полезна и позволяет обнаруживать большоеколичество ошибок еще на этапе написания кода, что существенно сокращает этап отладки итестирования.Но следует понимать, что статический анализ никогда не позволит выловить все ошибки, даже вконкретной области, которой является анализ 64-битного кода. Перечислим основные причины: 1. Некоторые элементы языка Си++ затруднены для анализа. В первую очередь это касается кода шаблонов, так как они оперируют с различными типами данных одними и теми же конструкциями. 2. Ошибки при переносе 32-битной программы на 64-битную систему могут содержаться не только в коде, но и быть косвенными. Хорошим примером может служить размер стека, который по умолчанию не изменяет в Visual Studio 2005/2008 при сборке 64-битной версии проекта и равняется 1 мегабайту. При работе 64-битный код может значительно больше заполнять стек, чем 32-битный код. Это связано с ростом размеров указателей и
    • других объектов, другим выравниванием. В результате 64-битной сборке программы может неожиданно не хватить стека во время работы. 3. Существуют ошибки алгоритмического характера, возникшие из некоторых предположений относительно размерностей типов, которые изменяются в 64-битной системе. 4. Ошибки могут крыться в сторонних 64-битных библиотеках.Перечисленный список не полон, но позволяет утверждать, что некоторые ошибки могут бытьобнаружены только при запуске программы. Другими словами необходимо нагрузочноетестирование приложений, использование динамических систем анализа (например, CompuwareBoundsChecker), юнит-тестирование, ручное тестирование и так далее.Таким образом, гарантию качества 64-битной программы может дать только комплексный подходк ее проверке, когда используются различные методологии и инструменты.Следует также понимать, что приведенная выше критика не снижает пользу от использованиястатического анализа. Статический анализ является самым эффективным методом обнаруженияошибок при переносе 32-битного кода на 64-битные системы. Он позволяет отловитьбольшинство ошибок за сравнительно короткое время. К преимуществам статического анализакода можно отнести: 1. Возможность проверить все ветви кода, не зависимо от частоты их выполнения в реальных условиях. 2. Возможность выполнить проверку еще на этапе переноса или разработки кода. Тем самым огромное количество ошибок исправляется еще до этапа тестирования и отладки. Это существенно экономит ресурсы и время. Общеизвестно, что чем раньше обнаружена ошибка, тем дешевле обходится ее исправление. 3. Статический анализатор умеет обнаруживать опасные конструкции, которые программист склонен считать корректными, так как они показали свою работоспособность на 32-битных системах. 4. Статический анализ позволяет заранее оценить качество кода с точки зрения его корректности для 64-битных систем и тем самым лучше спланировать ход работ.5. ВыводыВ диагностике 64-битного кода для операционной системы Windows лидируетспециализированный анализатор Viva64. В первую очередь это связано с тем, что онориентирован на модель данных LLP64, а во вторую тем, что в нем реализованы новыеспецифические правила диагностики [1].В диагностике 64-битного кода для операционных систем семейства Unix следует отдатьпредпочтение анализатору общего назначения PC-Lint. По таблице N3 его лидерство не оченьзаметно, но он реализует более важные правила, по сравнению с C++Test.Библиографический список 1. Евгений Рыжков. Viva64: разработка 64-битных приложений. 2. http://www.viva64.com/art-1-1-1888185592.html
    • 3. Андрей Карпов. Забытые проблемы разработки 64-битных программ. http://www.viva64.com/art-1-1-1609701563.html4. Андрей Карпов, Евгений Рыжков. 20 ловушек переноса Си++ - кода на 64-битную платформу. http://www.viva64.com/art-1-1-1958348565.html5. Андрей Карпов. Проблемы тестирования 64-битных приложений.6. http://www.viva64.com/art-1-1-929024801.html7. Андрей Карпов, Евгений Рыжков. Разработка ресурсоемких приложений в среде Visual C++. http://www.viva64.com/art-1-1-640027853.html