ООО «СиПроВер» («Системы программной верификации») www.viva64.com.

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



Advertisements
Похожие презентации
Проблема переноса приложений на 64-битные платформы Процесс миграции кода неизбежен. Миграция C/C++ приложений.
Advertisements

ПРОГРАММИРОВАНИЕ/ ЯЗЫКИ ПРОГРАММИРОВАНИЯ Лекция 4 Работа с бинарными файлами (весенний семестр 2012 г.) Доцент Кафедры вычислительных систем, к.т.н. Поляков.
ООО «Системы программной верификации» Конференция CEE-SECR 2009 Авторы:Карпов Андрей Рыжков Евгений.
Параллельное программирование с использованием технологии OpenMP Аксёнов Сергей Владимирович к.т.н., доцент каф.ОСУ ТПУ Томский политехнический университет.
Лекция 14 Динамические данные. Виды памяти Существует три вида памяти: статическая, стековая и динамическая. Статическая память выделяется еще до начала.
Сложные структуры данных Связные списки. Структуры, ссылающиеся на себя struct node { int x; struct node *next; };
Министерство образования Республики Беларусь Белорусский государственный университет Управляющие структуры языков программирования.
Основы информатики Лекция. Массивы. Указатели. Заикин Олег Сергеевич
Многопоточное программирование в OpenMP Киреев Сергей ИВМиМГ.
Полиморфизм Полиморфизм (polymorphism) - последний из трех "китов", на которых держится объектно-ориентированное программирование Слово это можно перевести.
Разработка параллельных приложений для многоядерных систем С.В. Ковальчук НИИ Наукоемких компьютерных технологий, СПбГУ ИТМО.
МГУ имени Ломоносова, механико-математический факультет, кафедра вычислительной математики Исследование проблемы переполнения буферов в программах Пучков.
Использование языка Си для программирования ЦСП TMS320C67x.
Преобразования типов В языке C/C++ имеется несколько операций преобразования типов. Они используются в случае, если переменная одного типа должна рассматриваться.
С++, ООП Семинар 2 Рябова Анна Сергеевна
Получение контроля над объектом атаки Местонахождение атакующего В разных сегментах с объектом атаки Используемые уязвимости Цель Ошибки реализации Степень.
OpenGL и Direct3D сравнение стандартов Выполнил: Пенкин А. Группа И-204.
О конформности Си-программ Михаил Посыпкин ИСП РАН.
Распределение памяти. Динамическое выделение памяти.
Получение контроля над объектом атаки Местонахождение атакующего В разных сегментах с объектом атаки Используемые уязвимости Цель Ошибки реализации Степень.
Транксрипт:

ООО «СиПроВер» («Системы программной верификации»)

Инструмент PVS-Studio набор правил Viva64 для анализа 64-битных приложений; набор правил VivaMP для анализа параллельных приложений; набор правил для анализа общего назначения. Лицензионная и ценовая политика PVS-Studio Информация о компании ООО «СиПроВер»

Анализ исходного кода приложений на языке Си/Си++

PVS-Studio – статический анализатор кода, который предназначен для разработчиков современных ресурсоемких приложений В состав PVS-Studio входят три набора диагностических правил: 1.Viva64, для выявления ошибок при разработки и миграции 64-битных приложений; 2.VivaMP, для выявления параллельных ошибок в коде программ, разработанных с использованием технологии OpenMP; 3.Для выявления ошибок общего плана, таких как опечатки, переполнение буфера, ошибки в условиях и так далее.

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

разрабатывает новые 64-битные приложения; выполняет миграцию 32-битного кода на 64-битные системы; добавляет в программу поддержку параллельного исполнения с помощью технологии OpenMP; хочет повысить качество и надежность кода; по-возможности выявить как можно больше ошибок на этапе разработки.

Легко скачать: Легко попробовать: PVS-Studio интегрируется в Visual Studio; В дистрибутиве идут примеры программ с ошибками. Легко купить (онлайн или через банк):

интеграция с Visual Studio 2005/2008/2010; поддержка Си и Си++; поддержка C++0x в рамках возможностей Visual Studio 2010; подробная справочная система (в том числе на русском языке; простота использования; удобная система фильтрации и подавления ошибок; анализ файлов в параллельном режиме.

Некоторые наши пользователи

Проблема переноса приложений на 64-битные платформы Процесс миграции кода неизбежен. Миграция C/C++ приложений наиболее затруднена из-за особенностей языка. При миграции возможно появление в программах ошибок, которые не удается диагностировать существующими методиками тестирования. Сложно убедится в корректности современных программ после переноса их на 64-битные системы (в MS-DOS 1.0 было строк кода, а в Windows Vista уже ). Поэтому и нельзя обратиться к опыту прошлых переходов.

По данным Kang Su Gatlin, Visual C++ Program Manager, Microsoft Corporation, 2004

Приведем примеры ошибок, обнаруживаемых Viva64

Базовый класс: class CWinApp { virtual void WinHelp(DWORD_PTR, UINT); }; Код пользователя: class CMyApp : public CWinApp { virtual void WinHelp(DWORD, UINT); }; 32-битная система:64-битная система:

int A = -2; unsigned B = 1; int array[5] = { 1, 2, 3, 4, 5 }; int *ptr = array + 3; ptr = ptr + (A + B); printf("%i\n", *ptr); Переменная A типа int приводится к типу unsigned; Происходит сложение A и B. В результате мы получаем значение 0xFFFFFFFF типа unsigned; Вычисляется выражение "ptr + 0xFFFFFFFFu". Результат зависит от размерности указателя на данной платформе. В 32-битной программе, выражение будет эквивалентно "ptr - 1" и мы успешно распечатаем число 3. В 64-битной программе к указателю прибавится значение 0xFFFFFFFFu, в результате чего указатель окажется далеко за пределами массива.

bool IsPresent(char *array, size_t arraySize, char key) { for (unsigned i = 0; i != arraySize; ++i) if (array[i] == key) return true; return false; } Данный код приведет к возникновению бесконечного цикла, если arraySize превысит значение UINT_MAX. Выявление подобных ошибок с использованием unit-тестов или динамических анализаторов (BoundsChecker) крайне осложнено необходимостью запуска на больших объеме данных. При обработке малого объема данных ошибка выявлена не будет

ptrdiff_t SetBitN(ptrdiff_t value, unsigned bitNum) { ptrdiff_t mask = 1

#define N_COUNT 100 int **pArray = (int**) malloc(N_COUNT * 4); hFileMapping = CreateFileMapping ( (HANDLE) 0xFFFFFFFF, NULL, PAGE_READWRITE, (DWORD) 0, (DWORD) (szBufIm), (LPCTSTR) &FileShareNameMap[0]); size_t n, newexp; n = n >> (32 - newexp); Наиболее распространенные магические значения, опасные при переносе приложений с 32-битной на 64-битную платформу

ptrdiff_t UnsafeCalcIndex(int x, int y, int width) { return x + y * width; }... int domainWidth = 50000; int domainHeght = 50000; for (int x = 0; x != domainWidth; ++x) for (int y = 0; y != domainHeght; ++y) array[UnsafeCalcIndex(x, y, domainWidth)] = 1; Данный код не может корректно заполнить массив, состоящий из 50000*50000 элементов. При вычислении выражения "x + y * width" происходит переполнение и результатом будет выход за границы массива.

size_t __fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp); size_t fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp) { int ret; FLOCKFILE(fp); ret = __fread(buf, size, count, fp); FUNLOCKFILE(fp); return (ret); } Функция __fread возвращает тип size_t, но для хранения количества прочитанных байт используется тип int. В результате при больших объемах читаемых данных функция может вернуть не то количество байт, которое на самом деле будет прочитано.

Были исследованы паттерны 64-битных ошибок в коде по более чем 100 различным статьям в печатных и электронных изданиях. Учтен собственный опыт миграции кода пакетов численного моделирования и визуализации на C++. В ходе исследований создана база из нескольких десятков различных паттернов ошибок, связанных с переносом кода на 64-битные системы. В базу попали как известные (опубликованные) ошибки, так и неизвестные ранее. На основе выявленных паттернов ошибок сформулированы правила их диагностики. И паттерны ошибок, и правила диагностики опубликованы в наших статьях и доступны для ознакомления всем желающим.

В таблице представлено сравнение на конец 2008 года. На данный момент PVS-Studio реализует значительно больше возможностей.

Компания E.G.S. S.r.l. занимается разработкой решений в области моделирования трехмерных объектов на базе триангулированных сеток.

Общий объем исходного кода Leios Studio составляет 13 мегабайт ( строк кода). Миграция кода с использованием Viva64 позволила сэкономить много времени, которое бы пришлось затратить на ручной просмотр кода. Основные проблемные моменты, выявленные в процессе автоматического анализа кода с помощью инструмента Viva64: особенности вычислительных алгоритмов при обработке больших объемов данных; работа с файлами большого размера; обработка 3d-моделей, содержащих большое количество треугольников (чем больше треугольников, тем точнее модели); работа подсистемы лицензирования; Подробности:

Размер проекта: 1.5Mb, 125 файлов Выявлено потенциально-опасных конструкций с помощью Viva64: 89 Из них реальных ошибок: 6 Подробности:

Отсутствие ключевых слов в директивах Неправильная работа с блокировками Зависимость поведения кода от количества выполняющих его потоков Одновременная работа с общим ресурсом Незащищенный доступ к общей памяти Неосторожное использование локальных переменных Ненужная защита памяти от одновременной записи Ошибки производительности

Приведем примеры ошибок, обнаруживаемых VivaMP

#pragma omp parallel for for (size_t i = 0; i != n; ++i) { float *array = new float[10000]; delete [] array; } Пример приведет к некорректному поведению программы и, скорее всего, к ее аварийному завершению, если произойдет ошибка выделения памяти. Ошибка связанна с выбрасыванием исключения из параллельной секции. Согласно спецификации OpenMP, если вы используете исключения внутри параллельной секции, то все эти исключения должны быть обработаны внутри этой секции. Если вы используете внутри параллельной секции оператор new, то вы должны позаботиться о перехвате исключения, которое согласно стандарту языка Си++ будет сгенерировано при ошибке выделения памяти.

void Foo() { #pragma omp for for (int i = 0; I < n; ++i) … } Цикл, вопреки ожиданиям программиста, будет выполняться только одним потоком. #pragma single { … } Забытая директива omp. И хотя компилятор VC++ выдаст сообщение "warning C4068: unknown pragma", это предупреждение может быть проигнорирована в больших сложных проектах, или быть вообще отключено. #pragma omp parallel { omp_set_num_threads(2); … } Количество потоков нельзя переопределять внутри параллельной секции. Это приводит к ошибке во время выполнения программы и ее аварийному завершению.

int a = 0; #pragma omp parallel for num_threads(4) for (int i = 0; i < ; i++) { a++; } Состояние гонки возникает тогда, когда несколько потоков многопоточного приложения пытаются одновременно получить доступ к данным, причем хотя бы один поток выполняет запись. Состояния гонки могут давать непредсказуемые результаты, и зачастую их сложно выявить. Иногда последствия состояния гонки проявляются только через большой промежуток времени и в совсем другой части приложения. Кроме того, ошибки такого рода невероятно сложно воспроизвести повторно. Крайне эффективным является выявление по крайней мере части таких ошибок с помощью статического анализа еще на этапе написания кода.

pragma omp parallel { static int st = Calc();... } Статическая переменная начнет процесс инициализации сразу в нескольких потоках, что может привести к неопределенному результату. Неприятность подобных ошибок заключается в их нестабильном и редком проявлении во время тестирования.

Соотношение стоимость исправления дефектов в зависимости от времени их внесения и обнаружения. Данные для таблицы взяты из книги С. Макконнелла «Совершенный Код».

Не важно, какова сложность ошибки. Простая это опечатка, или ошибка в логике алгоритма. Обнаружение хотя бы части таких ошибок еще на этапе написания кода весьма выгодно. Это существенно сокращает затраты на тестирование и дальнейшее сопровождение кода. Анализатор PVS-Studio диагностирует большое количество разнообразнейших видов ошибок. Перечислить все типы обнаруживаемых ошибок достаточно сложно. Подробно со списком диагностических проверок можно ознакомиться в документации. Документация (онлайн):

Примеры ошибок, обнаруживаемых анализатором общего назначения

int iChilds[2];... bool hasChilds() const { return(iChilds > 0 || iChilds > 0); } В данном случае, хотя код успешно и без предупреждений компилируется, он не имеет смысла. Корректный код должен был выглядеть следующим образом: int iChilds[2];... bool hasChilds() const { return(iChilds[0] > 0 || iChilds[1] > 0); }

struct CVariable { char name[64]; }; void CRendererContext::RiGeometryV(int n, char *tokens[]) { for (i=0; i

MD5Context *ctx;... memset(ctx, 0, sizeof(ctx)); Здесь из-за опечатки очищается не вся структура, а только ее часть. Ошибка в том, что вычисляется размер указателя, а не структуры MD5Context. Корректный вариант кода: MD5Context *ctx;... memset(ctx, 0, sizeof(*ctx));

if (a == 1) Foo1(); else if (a == 2) Foo2(); else if (a == 1) Foo3(); В этом коде функции 'Foo3()' никогда не получит управления.

CSize(POINT pt) { cx = pt.x; cx = pt.y; } Код взят из реального приложения, где был реализован свой собственный класс CSize. Корректный вариант должен был конечно выглядеть так: CSize(POINT pt) { cx = pt.x; cy = pt.y; } for (i = 0; i < n; i++); { Foo(i); }

void unregisterThread() { Guard g(_taskQueue); std::remove(_threads.begin(), _threads.end(), ThreadImpl::current()); } Функция std::remove не удаляет элементы из контейнера. Она только сдвигает элементы и возвращает итератор на начало мусора. Пусть мы имеем контейнер vector, содержащий элементы 1,2,3,1,2,3,1,2,3. Если выполнить код "remove( v.begin(), v.end(), 2 )", то контейнер будет содержать элементы 1,3,1,3,?,?,?, где ? - некий мусор. При этом функция вернет итератор на первый мусорный элемент, и если мы хотим удалить эти мусорные элементы, то должны написать код: "v.erase(remove(v.begin(), v.end(), 2), v.end())".

Тип лицензииЦена PVS-Studio - Single User License1600 PVS-Studio – Team License3500 PVS-Studio – Site Licenseна сайте Страница заказа:

возможность получения новых версий (включая major- версии) в течение 1 года; возможность получения поддержки по электронной почте в течение 1 года; неограниченное по времени право использования программы. После 1 года с момента приобретения лицензии, вы сможете по-прежнему получать новые версии PVS-Studio и обращаться в поддержку. Ограничения будут касаться только новых диагностических возможностей, которые появятся в анализаторе уже после истечения срока действия лицензии.

Свидетельство об официальной регистрации программ для ЭВМ N , «Вива64». Зарегистрировано в Реестре программ для ЭВМ 28 сентября 2007 г. Свидетельство об официальной регистрации программ для ЭВМ N , «Библиотека анализа кода VivaCore». Зарегистрировано в Реестре программ для ЭВМ 25 января 2008 г. Свидетельство об официальной регистрации программ для ЭВМ N , «Вива64 2.0». Зарегистрировано в Реестре программ для ЭВМ 29 мая 2008 г.

Наши статьи опубликованы на крупнейших программистских сайтах

Общие сведения о принципах работы с анализатором PVS-Studio Коллекция примеров 64-битных ошибок в реальных программах 32 подводных камня OpenMP при программировании на Си++ Другие статьи по разработке 64-битных и параллельных программ, а также по технологии анализа кода читайте на

ООО «СиПроВер» , Россия, Тула, Металлургов Web: Телефон: +7 (4872) Рабочее время: 09:00 – 18:00 (GMT +3:00)