Калайда В.Т., Романенко В.В. Технология разработки программного обеспечения (2007) (1095890), страница 16
Текст из файла (страница 16)
6.2).6.3.3 Список вопросов для выявления ошибок приинспекцииВажной частью процесса инспектирования является проверка программы на наличие общих ошибок с помощью списка104вопросов для выявления ошибок. Концентрация внимания впредлагаемом списке на рассмотрении стиля, а не ошибок (вопросы типа «Являются ли комментарии точными и информативными?» и «Располагаются ли операторы THEN/ELSE иDO/END по одной вертикали друг под другом?») представляется неудачной.
Также неудачным представляется и наличиенеопределенности в списке, уменьшающее его полезность (вопросы типа «Соответствует ли текст программы требованиям,выдвигаемым при проектировании?»). Список, приведенный вданном разделе, был составлен после многолетнего изученияошибок программного обеспечения. В значительной мере он является независимым от языка; это означает, что большинствоошибок встречается в любом языке программирования.6.3.3.1 Ошибки обращения к данным1. Существуют ли обращения к переменным, значения которым не присвоены или не инициализированы? Наличие переменных с не установленными значениями — наиболее частовстречающаяся программная ошибка, она возникает при различных обстоятельствах.
Для каждого обращения к единице данных (например, к переменной, элементу массива, полю в структуре) попытайтесь неформально «доказать», что ей присвоенозначение в проверяемой точке.2. Не выходит ли значение каждого из индексов за границы, определенные для соответствующего измерения при всехобращениях к массиву?3. Принимает ли каждый индекс целые значения при всехобращениях к массиву? Нецелые индексы не обязательно являются ошибкой для всех языков программирования, но представляют практическую опасность.4.
Для всех обращений с помощью указателей или переменных-ссылок память, к которой производится обращение,уже распределена? Наличие переменных-ссылок представляетсобой ошибку типа «подвешенного обращения». Она возникаетв ситуациях, когда время жизни указателя больше, чем времяжизни памяти, к которой производится обращение. Например, ктакому результату приводит ситуация, когда указатель задаетлокальную переменную в теле процедуры, значение указателя105присваивается выходному параметру или глобальной переменной, процедура завершается (освобождая адресуемую память), апрограмма затем пытается использовать значение указателя.Как и при поиске ошибок первых трех типов, попытайтесь неформально доказать, что для каждого обращения, использующего переменную-указатель, адресуемая память существует.5.
Если одна и та же область памяти имеет несколькопсевдонимов (имен) с различными атрибутами, то имеют лизначения данных в этой области корректные атрибуты при обращении по одному из этих псевдонимов? Ошибки типа некорректных атрибутов у псевдонимов могут возникнуть при использовании атрибута DEFINED или базированной памяти вPL/1, оператора EQUIVALENCE в Фортране, глагола REDEFINES в Коболе, записей с вариантами в Паскале илиобъединений (UNION) в языке Си. В качестве примера можнопривести программу на языке Си, содержащую вещественнуюпеременную A и целую переменную B.
Обе величины размещены на одном и том же месте памяти (т.е. помещены в одно и тоже объединение). Если программа записывает величину A, а обращается к переменной B, то, вероятно, произойдет ошибка, поскольку машина будет использовать битовое представлениечисла с плавающей точкой в данной области памяти как целое.6. Отличаются ли типы или атрибуты переменных величин от тех, которые предполагались компилятором? Это может произойти в том случае, когда программа на PL/1 или Коболе считывает записи из памяти и обращается к ним как кструктурам, но физическое представление записей отлично отописания структуры. Или программа на языке Си, допускающем произвольные преобразования типов, содержит переменную-указатель на структуру типа T1, инициализированную указателем на структуру типа T2 (не наследуемую от T1).7.
Существуют ли явные или неявные проблемы адресации, если в машине будут использованы единицы распределения памяти, меньшие, чем единицы адресации памяти? Например, в PL/1 в системе IBM S/370 битовые строки фиксированной длины не обязательно начинаются с границ байтов, а адресами могут быть только границы байтов. Аналогично, в языкеСи размер отдельных полей в структуре может задаваться в битах. Если программа вычисляет адрес битового поля и впослед-106ствии обращается к нему по этому адресу, то может произойтиошибочное обращение к памяти.
Такое же положение можетсложиться при передаче подпрограмме (процедуре) битовогополя в качестве аргумента.8. Если используются указатели или переменные-ссылки,то имеет ли адресуемая память атрибуты, предполагаемыекомпилятором? Примером несоответствия атрибутов можетслужить случай, когда указатель PL/1, по которому базируетсяструктура данных, имеет в качестве значения адрес другойструктуры.9. Если к структуре данных обращаются из несколькихпроцедур или подпрограмм, то определена ли эта структураодинаково в каждой процедуре?10. Не превышены ли границы строки при индексации вней?11. Существуют ли какие-нибудь другие ошибки в операциях с индексацией или при обращении к массивам по индексу?6.3.3.2 Ошибки описания данных1. Все ли переменные описаны явно? Отсутствие явногоописания не обязательно является ошибкой, но служит общимисточником беспокойства.
Так, если в подпрограмме на Фортране используется элемент массива и отсутствует его описание(например, в операторе DIMENSION), то обращение к массиву(например, Х = А(1)), будет интерпретироваться как вызовфункции. Последнее приведет к тому, что машина будет пытаться обработать массив как программу. Если отсутствует явное описание переменной во внутренней процедуре или блоке,следует ли понимать это так, что описание данной переменнойсовпадает с описанием во внешнем блоке?2. Если не все атрибуты переменной явно присутствуют вописании, то понятно ли их отсутствие? Например, отсутствиеатрибутов, считающееся общепринятым в PL/1, часто являетсяисточником неожиданных осложнений.3. Если начальные значения присваиваются переменным воператорах описания, то правильно ли инициализируются этизначения? Во многих языках программирования присвоение начальных значений массивам и строкам представляется довольно107сложным и, следовательно, является возможным источникомошибок.4.
Правильно ли для каждой переменной определены длина, тип и класс памяти (например, STATIC, AUTOMATIC,BASED или CONTROLLED в PL/1; AUTO, CONST, VOLATILE, REGISTER, STATIC в Си и т.д.)?5. Согласуется ли инициализация переменной с ее типомпамяти? Например, если в подпрограмме на Фортране необходимо устанавливать начальные значения переменной каждыйраз при вызове подпрограммы, переменная должна быть инициализирована в операторе описания, отличном от оператораDATA. Если в PL/1 описывается инициализация величины и начальное значение необходимо устанавливать каждый раз привызове процедуры, то для этой переменной должен быть определен класс памяти АUTОМАТIС, а не STATIC.6.
Есть ли переменные со сходными именами (например,VOLT и VOLTS)? Наличие сходных имен не обязательно является ошибкой, но служит признаком того, что имена могутбыть перепутаны где-нибудь внутри программы.6.3.3.3 Ошибки вычислений1. Имеются ли вычисления, использующие переменныенедопустимых (например, неарифметических) типов данных?2. Существуют ли вычисления, использующие данныеразного вида? Например, сложение переменной с плавающейточкой и целой переменной. Такие случаи не обязательно являются ошибочными, но они должны быть тщательно проверены для обеспечения гарантии того, что правила преобразования,принятые в языке, понятны.
Это особенно важно для языков сосложными правилами преобразования (например, для PL/1, Си).Например, следующий фрагмент программы на PL/1:DECLARE A BIT(1);A=1;определяет значение A равным битовому 0, а не 1. Или в языкеСи попытка присвоить переменной с плавающей точкой значение 1/2 даст значение 0 (т.к. 1 и 2 имеют целый тип).1083.
Существуют ли вычисления, использующие переменные, имеющие одинаковый тип данных, но разную длину? Такой вопрос справедлив для PL/1, и возник он из этого языка.Например, в PL/1 результатом вычисления выражения 25 + 1/3будет 5.333..., а не 25.333… Аналогично, в языке Си присутствуют множество данных одного типа, но имеющих разнуюдлину. Например, это целые типы (CHAR, INT, LONG, SHORT,INT64 и т.д.), вещественные типы (FLOAT, DOUBLE, LONGDOUBLE) и т.д. К тому же, эти типы могут быть как знаковыми(SIGNED), так и беззнаковыми (UNSIGNED).4. Имеет ли результирующая переменная оператора присваивания атрибуты, описывающие ее с меньшей длиной, чем ватрибутах выражения в правой части?5. Возможны ли переполнение или потеря результата вовремя вычисления выражения? Это означает, что конечный результат может казаться правильным, но промежуточный результат может быть слишком большим или слишком малым длямашинного представления данных.6.