Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Автоматизация процесса тестирования при помощи методологии и инструментальных средств IBM Rational / Автоматизация процесса тестирования при помощи методологии и инструментальных средств IBM Rational.doc
Скачиваний:
55
Добавлен:
01.05.2014
Размер:
1.06 Mб
Скачать

Сообщения об ошибках и предупреждениях || к оглавлению данной статьи || к новостям || к услугам || в библиотеку

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

Отметим разницу между ошибкой и потенциальной ошибкой и опишем:

  • Ошибка — свершившийся факт нестабильной или некорректной работы приложения, проводящий к неадекватным действиям приложения или системы. Примером подобной ошибки можно считать выход за пределы массива или попытка записи данных по 0 адресу;

  • Потенциальная ошибка — в приложении имеется фрагмент кода, который при нормальном исполнении не приводит к ошибкам. Ошибка возникает только в случае стечения обстоятельств, либо не проявляет себя никогда. К данной категории можно отнести такие особенности, как инициализация массива с ненулевого адреса, скажем, имеется массив на 100 байт, но каждый раз обращение к нему производится с 10 элемента. В этом случае Purify считает, что имеется потенциальная утечка памяти размером в 10 байт.

Естественно, что подобное поведение может быть вызвано спецификой приложения, например, так вести себя может текстовый редактор. Поэтому в Purify применятся деление информации на ошибки и потенциальные ошибки (которые можно воспринимать как специфику).

Список ошибок и потенциальных ошибок достаточно объемен и постоянно пополняется. Кратко опишем основные сообщения, выводимые после тестирования:

  • Array Bounds Read Выход за пределы массива при чтении;

  • Array Bounds Write Выход за пределы массива при записи;

  • Late Detect Array Bounds Write Cообщение указывает, что программа записала значение перед началом или после конца распределенного блока памяти;

  • Beyond Stack Read Сообщение указывает, что функция в программе собирается читать вне текущего указателя вершины стека;

  • Freeing Freed Memory Попытка освобождения свободного блока памяти;

  • Freeing Invalid Memory Попытка освобождения некорректного блока памяти;

  • Freeing Mismatched Memory Сообщение указывает, что программа пробует;

  • Free Memory Read Попытка чтения уже освобожденного блока памяти;

  • Free Memory Write Попытка записи уже освобожденного блока памяти;

  • Invalid Handle Операции над неправильным дескриптором; Handle In Use Индикация утечки ресурсов. Неправильная индикация дескриптора;

  • Invalid Pointer Read\Write Ошибка при чтении\записи из недоступного блока памяти;

  • Memory Allocation Failure Ошибка в запросе на распределение памяти;

  • Memory Leak Утечка памяти;

  • Potential Memory Leak Потенциальная утечка памяти;

  • Null Pointer Read Попытка чтения с нулевого адреса;

  • Null Pointer Write Попытка записи в нулевой адрес;

  • Uninitialized Memory Copy Попытка копирования непроинициализированного блока;

  • UMR: Uninitialized Memory Read Попытка чтения непроинициализированного блока.

Предупреждения и ошибки удобно группировать по определенным признакам, чтобы легче можно было отыскать нужное предупреждение и отбросить ненужные.

Отметим категории и принадлежность к ним различных сообщений:

  • Allocation and deallocation. Работа с памятью;

  • DLL messages. Информационные сообщения по внешним библиотекам;

  • Invalid handles. Неправильный дескриптор;

  • Invalid pointers. Неправильный указатель;

  • Memory leaks. Утечка памяти;

  • Parameter errors. Ошибка параметра;

  • Stack errors. Ошибка при работе со стеком;

  • Unhandled exception. Исключение;

  • Uninitialized memory. Использование непроинициализированного блока памяти.

Многие статические ошибки могут вылавливать компиляторы на этапе разработки программного модуля или приложения. На этом этапе преимущества Purify не очень видны.

Все механизмы анализа ошибок открываются при исполнении приложения, при динамически меняющихся условиях.

Рассмотрим более подробно список отлавливаемых ошибок, определив их принадлежность к категориям с примерами на C++/C:

ABR: Array Bounds Read. Выход за пределы массива при чтении. Известная болезнь всех разработчиков — неправильно поставленное условие в цикле. Соответственно, ошибка, которая имеет место быть в программе, связанная с чтением лишней информации, может проявить себя, а может и не проявить. Но она является потенциальной ошибкой.

#include <iostream.h> #include <windows.h> int main(int, char **) { char *ptr = new char[5];//Выделяем память под массив из 5 символов

ptr[0] = ‘e’; ptr[1] = ‘r’; ptr[2] = ‘r’; ptr[3] = ‘o’; ptr[4] = ‘r’; for (int i=0; i <= 5; i++) { //Ошибка, при i=5 – выход за пределы массива cerr << "ptr[" << i << "] == " << ptr[i] << '\n'; } delete[] ptr; return(0); }

ABW: Array Bounds Write. Выход за пределы массива при записи Вероятность того, что приложение может неадекватно вести себя из-за данной ошибки более высоко, так как запись по адресу, превышающим размер блока, вызывает исключение.

Отметим, что память можно определить статически, массовом, как показано в примере. А можно динамически (например, выделив блок памяти по ходу исполнения приложения).

По умолчанию, Purify успешно справляется только с динамическим распределением, четко выводя сообщение об ошибке. В случае статического распределения, все зависит от размеров «кучи» и настроек компилятора.

#include <iostream.h> #include <windows.h> int main(int, char **) { char * ptr = new char[5];//Выделяем память под массив из 5символов for (int i=0; i <= 5; i++) { //Ошибка, при i=5 - выход за пределы массива ptr[i] = ‘!’; cerr << "ptr[" << i << "] == " << ptr[i] << '\n'; //ABW + ABR when i is 5 } delete[] ptr; return(0); }

ABWL: Late Detect Array Bounds Write. Cообщение указывает, что программа записала значение перед началом или после конца распределенного блока памяти

#include <iostream.h> #include <windows.h> int main(int, char **) { char * ptr = new char[5];//Выделяем память под массив из 5 символов for (int i=0; i <= 5; i++) { //Ошибка – попытка записи после блока выделенной памяти ptr[i] = ‘!’; cerr << "ptr[" << i << "] == " << ptr[i] << '\n'; } delete[] ptr; //ABWL: ОШИБКА return(0); }

BSR: Beyond Stack Read. Сообщение указывает, что функция в программе собирается читать вне текущего указателя вершины стека

Категория: Stack Error

#include <windows.h> #include <iostream.h> #define A_NUM 100 char * create_block(void) { char block[A_NUM];//Ошибка: массив должен быть статическим for (int i=0; i < A_NUM; i++) { block[i] = ‘!’; } return(block);//Ошибка: неизвестно, что возвращать }

int main(int, char **) { char * block; block = create_block(); for (int i=0; i < A_NUM; i++) { //BSR: нет гарантии, что элементы из "create_block" до сих пор находятся в стеке

cerr << "element #" << i << " is " << block[i] << '\n'; } return(0); }

FFM: Freeing Freed Memory. Попытка освобождения свободного блока памяти.

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

Категория: Allocations and deallocations

#include <iostream.h> #include <windows.h> int main(int, char **) { char *ptr1 = new char; char *ptr2 = ptr1;//Ошибка: должен дублировать объект, а не копировать указатель *ptr1 = ‘a’; *ptr2 = ‘b’; cerr << "ptr1" << " is " << *ptr1 << '\n'; cerr << "ptr2" << " is " << *ptr2 << '\n'; delete ptr1; delete ptr2;//Ошибка – освобождение незанятой памяти return(0); }

FIM: Freeing Invalid Memory. Попытка освобождения некорректного блока памяти.

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

Категория: Allocations and deallocations

#include <iostream.h>

int main(int, char **) { char a; delete[] &a;//FIM: в динамической памяти нет объектов для уничтожения return(0); }

FMM: Freeing Mismatched Memory. Сообщение указывает, что программа пробует освобождать память с неправильным ВЫЗОВОМ API для того типа памяти

Категория: Allocations and deallocations

#include <windows.h>

int main(int, char **) { HANDLE heap_first, heap_second; heap_first = HeapCreate(0, 1000, 0); heap_second = HeapCreate(0, 1000, 0); char *pointer = (char *) HeapAlloc(heap_first, 0, sizeof(int)); HeapFree(heap_second, 0, pointer); //Ошибкаво второй куче не выделялась память

HeapDestroy(heap_first); HeapDestroy(heap_second); return(0); }

FMR: Free Memory Read. Попытка чтения уже освобожденного блока памяти

Все та же проблема с указателем. Блок распределен, освобожден, а потом, в ответ на событие, по указателю начинают записываться (или читаться) данные.

Категория: Invalid pointers

#include <iostream.h> #include <windows.h> int main(int, char **) { char *ptr = new char[2]; ptr[0] = ‘!’; ptr[1] = ‘!’; delete[] ptr;//Ошибка – освобождение выделенной памяти for (int i=0; i < 2; i++) { //FMR: Ошибка- попытка чтения освобождённой памяти cerr << "element #" << i << " is " << ptr[i] << '\n'; } return(0); }

FMW: Free Memory Write. Попытка записи уже освобожденного блока памяти

Категория: Invalid pointers

#include <iostream.h> #include <windows.h> int main(int, char **) { char *ptr = new char[2]; ptr[0] = ‘!’; ptr[1] = ‘!’; delete[] ptr;//специально освобождаем выделенную память for (int i=0; i < 2; i++) { ptr[i] *= ‘A’; //FMR + FMW: память для *ptr уже освобождена cerr << "element #" << i << " is " << ptr[i] << '\n'; //FMR } return(0); }

HAN: Invalid Handle. Операции над неправильным дескриптором

Категория: Invalid handles

#include <iostream.h> #include <windows.h> #include <malloc.h> int main(int, char **) { int i=8; (void) LocalUnlock((HLOCAL)i);//HAN: i – не является описателем объекта памяти return(0); }

HIU: Handle In Use. Индикация утечки ресурсов. Неправильная индикация дескриптора.

#include <iostream.h> #include <windows.h> static long GetAlignment(void) { SYSTEM_INFO desc; GetSystemInfo(&desc); return(desc.dwAllocationGranularity); } int main(int, char **) { const long alignment = GetAlignment(); HANDLE handleToFile = CreateFile("file.txt", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (handleToFile == INVALID_HANDLE_VALUE) {

cerr << "Ошибка открытия, создания файла\n"; return(1); } HANDLE handleToMap = CreateFileMapping(handleToFile, NULL, PAGE_READWRITE, 0, alignment, "mapping_file"); if (handleToMap == INVALID_HANDLE_VALUE) { cerr << "Unable to create actual mapping\n"; return(1); } char * ptr = (char *) MapViewOfFile(handleToMap, FILE_MAP_WRITE, 0, 0, alignment);

if (ptr == NULL) { cerr << "Unable to map into address space\n"; return(1); } strcpy(ptr, "hello\n"); //HIU: handleToMap до сих пор доступен и описывает существующий объект return(0); }

IPR: Invalid Pointer Read. Ошибка обращения к памяти, когда программа пытается произвести чтение из недоступной области

Категория: Invalid pointers

#include <iostream.h>

#include <windows.h> int main(int, char **) { char * pointer = (char *) 0xFFFFFFFF; //Ошибка - указатель на зарезервированную область памяти

for (int i=0; i < 2; i++) { //IPR: обращение к зарезервированной части адресного пространства cerr << "pointer[" << i << "] == " << pointer[i] << '\n'; } return(0); }

IPW: Invalid Pointer Write. Ошибка обращения к памяти, когда программа пытается произвести запись из недоступной области

Категория: Invalid pointers

#include <iostream.h> #include <windows.h> int main(int, char **) { char *pointer = (char *) 0xFFFFFFFF; //Ошибка - указатель на зарезервированную область памяти

for (int i=0; i < 2; i++) { //IPW + IPR: обращение к зарезервированной части адресного пространства pointer[i] = ‘!’; cerr << "ptr[" << i << "] == " << ptr[i] << '\n'; } return(0); }

MAF: Memory Allocation Failure. Ошибка в запросе на распределение памяти. Возникает в случаях, когда производится попытка распределить слишком большой блок памяти, например, когда исчерпан файл подкачки.

Категория: Allocations and deallocations

#include <iostream.h> #include <windows.h> #define BIG_BLOCK 3000000000 //размер блока int main(int, char **) { char *ptr = new char[BIG_BLOCK / sizeof(char)]; //MAF: слишком большой размер для распределения if (ptr == 0) { cerr << "Failed to allocating, as expected\n"; return (1); } else { cerr << "Got " << BIG_BLOCK << " bytes @" << (unsigned long)ptr << '\n'; delete[] ptr; return(0); } }

MLK: Memory Leak. Утечка памяти

Распространенный вариант ошибки. Многие современные приложения грешат тем, что не отдают системе распределенные ресурсы по окончании своей работы.

Категория: Memory leaks

#include <windows.h> #include <iostream.h> int main(int, char **) { (void) new int[1000]; (void) new int[1000]; //результат потери памяти return(0); }

MPK: Potential Memory Leak. Потенциальная утечка памяти Иногда возникает ситуация, в которой необходимо провести инициализацию массива не с нулевого элемента. Purify считает это ошибкой. Но разработчик, пишущий пресловутый текстовый редактор может инициализировать блок памяти не с нулевого элемента.

Категория: Memory leaks

#include <iostream.h> #include <windows.h> int main(int, char **) { static int *pointer = new int[100000]; pointer += 100;//MPK: потеряли начало массива return(0); }

NPR: Null Pointer Read. Попытка чтения с нулевого адреса Бич всех программ на С\С++. Очень часто себя ошибка проявляет при динамическом распределении памяти приложением, так как не все разработчики ставят условие на получение блока памяти, и возникает ситуация, когда система не может выдать блок указанного размера и возвращает ноль. По причине отсутствия условия разработчик как не в чем не бывало начинает проводить операции над блоком, адрес в памяти которого 0.

Категория: Invalid pointers

#include <iostream.h> #include <windows.h> int main(int, char **) { char * pointer = (char *) 0x0; //указатель на нулевой адрес for (int i=0; i < 2; i++) { //NPR: попытка чтения с нулевого адреса cerr << "pointer[" << i << "] == " << pointer[i] << '\n'; } return(0); }

NPW: Null Pointer Write. Попытка записи в нулевой адрес

Категория: Invalid pointers

#include <iostream.h> #include <windows.h> int main(int, char **) { char * pointer = (char *) 0x0; //указатель на нулевой адрес for (int i=0; i < 2; i++) { //NPW: ошибка доступа pointer[i]=’!’; cerr << "pointer[" << i << "] == " << pointer[i] << '\n'; } return(0); }

UMC: Uninitialized Memory Copy. Попытка копирования непроинициализированного блока памяти

Категория: Unitialized memory

#include <iostream.h> #include <windows.h> #include <string.h>

int main(int, char **) { int * pointer = new int[10]; int block[10]; for (int i=0; i<10;i++) { pointer[i]=block[i]; //UMC предупреждение cerr<<block[i]<<”\n”;

} delete[] pointer; return(0); }

UMR: Uninitialized Memory Read. Попытка чтения непроинициализированного блока памяти

Категория: Unitialized memory

#include <iostream.h> #include <windows.h> int main(int, char **) { char *pointer = new char; cerr << "*pointer is " << *pointer << '\n'; //UMR: pointer указывает на непроинициализированный элемент delete[] pointer; return(0); }