Введение
Ошибка в программном обеспечении
Ошибка в программном обеспечении – это дефект в компьютерной программе. Компьютерную программу с большим количеством или серьезными ошибками можно назвать «с дефектами» или «нестабильной». Последствия ошибки в программном обеспечении варьируются от незначительных (например, опечатка в пользовательском интерфейсе) до критических (например, сбой или зависание). Катастрофы связывают с ошибками в программном обеспечении. Ошибки в программном обеспечении аппарата для лучевой терапии Therac 25 были непосредственно причиной гибели пациентов в 1980-х годах. В 1996 году прототип ракеты Ariane 5 Европейского космического агентства стоимостью 1 миллиард долларов США был уничтожен менее чем через минуту после запуска из-за ошибки в бортовой программе управления. В 1994 году потерпел крушение вертолет RAF Chinook, в результате чего погибли 29 человек; изначально причиной считалась ошибка пилота, но позже предполагалось, что причиной стала ошибка в программном обеспечении компьютера управления двигателем. Ошибки в программном обеспечении стали причиной скандала в британском почтовом отделении в начале XXI века. В 2002 году исследование, заказанное Национальным институтом стандартов и технологий Министерства торговли США, пришло к выводу, что «распространенность ошибок в программном обеспечении настолько велика и наносит такой ущерб, что ежегодно обходится экономике США в 59 миллиардов долларов, или примерно 0,6 процента валового внутреннего продукта». С 1950-х годов некоторые компьютерные системы разрабатываются с возможностью обнаружения или автоматической коррекции различных программных ошибок в процессе работы.
Терминология
Метаморфизм ошибок (от греческого meta = "изменение", morph = "форма") относится к эволюции дефекта на финальной стадии развертывания программного обеспечения. Превращение "ошибки", допущенной аналитиком на ранних этапах жизненного цикла разработки программного обеспечения, приводящее к "дефекту" на заключительной стадии цикла, получило название "метаморфизм ошибки". Различные стадии проявления ошибки в цикле разработки могут описываться как ошибка, аномалия, неисправность, сбой, ошибка, исключение, аварийное завершение, сбой, глюк, дефект, инцидент или побочный эффект. Некоторые полагают, что термин "ошибка" может использоваться для маскировки намеренного дизайнерского решения. В 2011 году, после критики со стороны сенатора США Ала Франкена за запись и хранение местоположения пользователей в незашифрованных файлах, компания Apple назвала это поведение ошибкой. Однако Джастин Брукман из Центра демократии и технологий напрямую оспорил эту интерпретацию, заявив: "Я рад, что они исправляют то, что называют ошибками, но я не согласен с их категорическим отрицанием отслеживания пользователей".
Профилактика
Предотвращение ошибок на самых ранних этапах процесса разработки программного обеспечения является областью для инвестиций и инноваций.
Спецификация
Некоторые полагают, что составление спецификации программы, описывающей её поведение, может предотвратить появление ошибок. Другие утверждают, что формальные спецификации непрактичны ни для чего, кроме самых простых программ, из-за проблем комбинаторного взрыва и недетерминированности.
Тестирование программного обеспечения
Одна из целей тестирования программного обеспечения — обнаружение дефектов. Измерения, проводимые в процессе тестирования, могут дать оценку вероятного количества оставшихся дефектов. Эта оценка становится более точной по мере увеличения времени, затраченного на тестирование и разработку продукта.
Гибкая практика
Гибкая разработка программного обеспечения может включать частые релизы с относительно небольшими изменениями. Дефекты обнаруживаются на основе отзывов пользователей. При разработке через тестирование (TDD) модульные тесты пишутся одновременно с производственным кодом, и производственный код не считается завершённым, пока все тесты не пройдут успешно.
Статический анализ
Инструменты статического анализа кода помогают разработчикам, анализируя текст программы глубже, чем это делает компилятор, для выявления потенциальных проблем. Хотя в общем случае задача обнаружения всех ошибок в программе, исходя из заданной спецификации, неразрешима (см. проблему останова), эти инструменты используют тот факт, что люди-программисты склонны часто допускать одни и те же простые ошибки при разработке программного обеспечения.
Инструментовка
Инструменты для мониторинга производительности программного обеспечения во время его работы, будь то для выявления проблем, таких как узкие места, или для подтверждения корректности работы, могут быть явно встроены в код (например, в виде простой команды вроде PRINT "Я здесь") или предоставляться как отдельные инструменты. Зачастую бывает неожиданно, какая часть кода потребляет больше всего времени, и осознание этого может потребовать переработки кода.
Открытый исходный код
Разработка с открытым исходным кодом позволяет любому изучать исходный код. Существует мнение, популяризированное Эриком С. Реймондом как закон Линуса, согласно которому популярное программное обеспечение с открытым исходным кодом имеет больше шансов быть свободным от ошибок, чем другое программное обеспечение, поскольку "чем больше глаз, тем меньше ошибок". Однако это утверждение подвергается сомнению: специалист по компьютерной безопасности Элиас Леви отмечал, что "легко скрыть уязвимости в сложном, недостаточно понятном и не документированном исходном коде", потому что "даже если код просматривается, это не гарантирует квалификации рецензентов". Примером ошибки в программном обеспечении с открытым исходным кодом является уязвимость OpenSSL, обнаруженная в Debian в 2008 году.
Очистка
Отладка может быть значительной частью жизненного цикла разработки программного обеспечения. Морис Уилкс, один из первых пионеров вычислительной техники, в конце 1940-х годов описал, как он осознал, что большую часть оставшейся жизни он проведет, выявляя ошибки в своих программах. Программа, известная как отладчик, может помочь программисту найти ошибочный код, исследуя внутреннюю работу программы, например, выполняя код построчно и просматривая значения переменных. В качестве альтернативы использованию отладчика, код может быть инструментирован логикой для вывода отладочной информации, чтобы отслеживать выполнение программы и просматривать значения. Вывод обычно осуществляется в консоль, окно, файл журнала или на аппаратное устройство (например, светодиод). Некоторые считают, что поиск ошибок – это своего рода искусство. Нередко ошибка в одном разделе программы приводит к сбоям в другом разделе, что затрудняет ее отслеживание в, казалось бы, не связанной части системы. Например, ошибка в подпрограмме графического рендеринга может привести к сбою подпрограммы ввода-вывода файлов. Иногда самая сложная часть отладки – это найти причину ошибки. Как только причина найдена, исправление проблемы иногда бывает легким или даже тривиальным. Иногда ошибка – это не изолированный дефект, а ошибка в мышлении или планировании со стороны программистов. Часто такая логическая ошибка требует переработки или переписывания части программы. Некоторые утверждают, что в процессе проверки кода, пошаговое выполнение кода и представление или транскрибирование процесса выполнения часто могут выявить ошибки, не воспроизводя саму ошибку. Обычно первым шагом в поиске ошибки является ее надежное воспроизведение. Если проблему не удается воспроизвести, программист не сможет найти причину ошибки и, следовательно, не сможет ее исправить. Некоторые ошибки проявляются при вводе данных, которые программисту может быть трудно воссоздать. Одной из причин гибели людей при использовании радиационной установки Therac 25 была ошибка (в частности, состояние гонки), которая возникала только тогда, когда оператор установки очень быстро вводил план лечения; для этого требовались дни практики, поэтому ошибка не проявлялась при тестировании или попытках производителя ее воспроизвести. Другие ошибки могут перестать возникать, когда настройка изменяется для облегчения их поиска, например, при запуске программы с отладчиком; такие ошибки называются хайзенбугами (в шутку названными в честь принципа неопределенности Гейзенберга). С 1990-х годов, особенно после катастрофы рейса 501 "Ариан-5", возрос интерес к автоматизированным средствам отладки, таким как статический анализ кода с помощью абстрактной интерпретации. Часто ошибки возникают в процессе кодирования, но ошибочная проектная документация также может быть причиной ошибок. В некоторых случаях изменения кода могут устранить проблему, даже если код больше не соответствует документации. Во встроенных системах программное обеспечение часто модифицируется для обхода аппаратной ошибки, поскольку это дешевле, чем модификация аппаратного обеспечения.
Управление
Баги управляются посредством таких действий, как документирование, категоризация, назначение ответственного, воспроизведение, исправление и выпуск исправленного кода. Инструменты часто используются для отслеживания ошибок и других проблем в программном обеспечении. Как правило, команда разработки программного обеспечения использует одни инструменты для отслеживания своей рабочей нагрузки, а служба поддержки клиентов – другие для отслеживания отзывов пользователей. Отслеживаемый элемент часто называют ошибкой, дефектом, заявкой, проблемой, функцией или, в случае гибкой разработки программного обеспечения, историей пользователя или эпосом. Элементы часто классифицируются по таким параметрам, как серьезность, приоритет и номер версии. В процессе, иногда называемом триажем, принимается решение по каждой ошибке о том, нужно ли её исправлять и когда, основываясь на информации о её серьезности и приоритете, а также на внешних факторах, таких как сроки разработки. Триаж обычно не включает в себя анализ причин возникновения ошибки. Триаж может проводиться регулярно и обычно состоит из рассмотрения новых ошибок, появившихся с момента предыдущего триажа, и, возможно, всех открытых ошибок. В числе участников могут быть руководитель проекта, руководитель разработки, руководитель тестирования, руководитель сборки и технические специалисты.
are used by the software development team to track their workload than by customer service to track user feedback. A tracked item is often called bug, defect, ticket, issue, feature, or for agile software development, story or epic. Items are often categorized by aspects such as severity, priority and version number. In a process sometimes called triage, choices are made for each bug about whether and when to fix it based on information such as the bug's severity and priority and external factors such as development schedules. Triage generally does not include investigation into cause. Triage may occur regularly. Triage generally consists of reviewing new bugs since the previous triage and maybe all open bugs. Attendees may include project manager, development manager, test manager, build manager, and technical experts.
Тяжесть
Тяжесть – это мера влияния, которое оказывает ошибка. Это влияние может выражаться в потере данных, финансовых убытках, утрате доверия и затраченных впустую усилиях. Уровни тяжести не стандартизированы и различаются в зависимости от контекста, например, от отрасли или используемого инструмента отслеживания. Например, сбой в видеоигре имеет иные последствия, чем сбой в банковском сервере. Уровни тяжести могут включать в себя: критический сбой или зависание, отсутствие обходного решения (пользователь не может выполнить задачу), наличие обходного решения (пользователь все же может выполнить задачу), визуальный дефект (например, опечатка) или ошибка в документации. Другой пример набора уровней тяжести: критическая, высокая, низкая, блокирующая, незначительная. Тяжесть ошибки может быть отдельной категорией от её приоритета исправления, либо оба параметра могут быть оценены количественно и управляться независимо. Ошибка, достаточно серьезная, чтобы задержать выпуск продукта, называется критической.
Приоритет
Приоритет описывает важность устранения ошибки по сравнению с другими ошибками. Приоритеты могут быть числовыми, например, от 1 до 5, или текстовыми, такими как критический, высокий, низкий и отложенный. Значения приоритетов могут быть схожими или идентичными оценкам серьезности, хотя приоритет – это отдельный аспект. Приоритет может определяться сочетанием серьезности ошибки и объема работы, необходимого для её исправления. Ошибка с низкой серьезностью, но простой в исправлении, может получить более высокий приоритет, чем ошибка со средней серьезностью, требующая значительно больших усилий для исправления.
Пластырь
Для ошибок с достаточно высоким приоритетом может потребоваться специальный релиз, который иногда называют патчем.
Релиз по техническому обслуживанию
Релиз программного обеспечения, ориентированный на исправление ошибок, может называться релизом технической поддержки, чтобы отличать его от релиза, ориентированного на новые функции или другие изменения.
Последствия
Размер и тип ущерба, который может вызвать ошибка в программном обеспечении, влияет на процесс принятия решений, процедуры и политику в отношении качества программного обеспечения. В таких областях, как пилотируемые космические полеты, авиация, атомная энергетика, здравоохранение, общественный транспорт или безопасность автомобилей, поскольку дефекты программного обеспечения могут привести к травмам или даже смерти людей, такое программное обеспечение подвергается гораздо более тщательному контролю и обеспечению качества, чем, например, веб-сайт для онлайн-покупок. В таких приложениях, как банковское дело, где дефекты программного обеспечения могут нанести серьезный финансовый ущерб банку или его клиентам, контроль качества также важнее, чем, скажем, приложение для редактирования фотографий. Помимо ущерба, причиняемого ошибками, часть их стоимости обусловлена усилиями, затраченными на их исправление. В 1978 году Линц и др. показали, что в среднем проекты тратят 17% усилий на разработку на исправление ошибок. В 2020 году исследования репозиториев GitHub показали, что медианное значение составляет 20%.
Стоимость
В 1994 году Центру космических полетов Годдарда НАСА удалось снизить среднее количество ошибок с 4,5 до 1 на 1000 строк кода (SLOC). Другое исследование, проведенное в 1990 году, показало, что при использовании исключительно качественных процессов разработки программного обеспечения уровень отказов при развертывании может достигать 0,1 на 1000 SLOC. Эта цифра упоминается в таких работах, как Code Complete Стива Макконнелла и исследование NASA о сложности летного программного обеспечения. Некоторые проекты даже добились нулевого количества дефектов: прошивка пишущей машинки IBM Wheelwriter, состоящая из 63 000 SLOC, и программное обеспечение космического шаттла объемом 500 000 SLOC. Defects4J представляет собой набор из 341 ошибки Java, обнаруженных в 5 проектах с открытым исходным кодом, и включает соответствующие исправления, охватывающие различные типы патчей. Также существует эталон, содержащий 185 ошибок на языке C, обнаруженных в девяти программах с открытым исходным кодом.
Ошибка проектирования
Ошибка может быть вызвана недостаточным или неверным проектированием, основанным на спецификации. Например, если спецификация требует алфавитной сортировки списка слов, ошибка проектирования может возникнуть, если в проекте не предусмотрена обработка символов, что приведет к неправильной сортировке слов, содержащих символы.
Арифметика
Числовые операции могут приводить к неожиданным результатам, замедленной обработке или аварийному завершению программы. Подобная ошибка может быть вызвана недостаточным пониманием особенностей хранения данных, таких как потеря точности при округлении, использованием численно неустойчивых алгоритмов, арифметическим переполнением или исчезновением значения, а также незнанием того, как вычисления обрабатываются в разных языках программирования – например, деление на ноль, которое в одних языках может вызывать исключение, а в других возвращать специальное значение, такое как NaN или бесконечность.
Контрольный поток
Ошибка управления потоком выполнения, также известная как логическая ошибка, характеризуется кодом, который не приводит к ошибке, но при этом работает не так, как ожидается, например, бесконечный цикл, бесконечная рекурсия, некорректное сравнение в условном операторе (например, использование неверного оператора сравнения) или ошибка "на единицу".
Интерфейс
Неправильное использование API. Неправильная реализация протокола. Неправильная обработка оборудования. Неверные предположения о конкретной платформе. Несовместимые системы. Новый API или протокол связи может казаться работающим, когда две системы используют разные версии, но ошибки могут возникать, если функция или компонент, реализованный в одной версии, изменен или отсутствует в другой. В производственных системах, которые должны работать непрерывно, отключение всей системы для масштабного обновления может быть невозможным, например, в телекоммуникационной отрасли или в интернете. В этом случае меньшие сегменты большой системы обновляются по отдельности, чтобы минимизировать сбои в работе большой сети. Однако некоторые участки могут быть пропущены и не обновлены, что может привести к ошибкам совместимости, которые сложно обнаружить и исправить. Некорректные аннотации кода.
Конкуренция
Дэдлок: задача не может продолжить выполнение, пока не завершится вторая, но в то же время вторая задача не может продолжить выполнение, пока не завершится первая. Состояние гонки: несколько одновременных задач конкурируют за ресурсы. Ошибки в критических секциях, взаимном исключении и других аспектах параллельной обработки. Уязвимость "время проверки — время использования" (TOCTOU) является разновидностью незащищенной критической секции.
Распределение ресурсов
Разделение по нулевому указателю. Использование неинициализированной переменной. Использование допустимой инструкции для неверного типа данных (например, упакованного десятичного или двоично-десятичного кода). Нарушения доступа. Утечки ресурсов, когда исчерпаемый ресурс системы (такой как память или дескрипторы файлов) истощается из-за многократного выделения без освобождения. Переполнение буфера, при котором программа пытается сохранить данные за пределами выделенной памяти. Это может, но не обязательно, привести к нарушению доступа или нарушению хранения. Такие ошибки часто являются уязвимостями в системе безопасности. Чрезмерная рекурсия, которая, будучи логически верной, вызывает переполнение стека. Использование указателя после освобождения памяти, на которую он указывает. Двойное освобождение памяти.
Синтаксис
Использование неверного токена, например, присваивания вместо проверки на равенство. Например, в некоторых языках x=5 присвоит переменной x значение 5, а x==5 проверит, равно ли x 5 или какому-либо другому числу. В интерпретируемых языках такой код может привести к ошибке во время выполнения. Компилируемые языки способны обнаруживать подобные ошибки до начала тестирования.
Работа в команде
Нераспространенные обновления; например, программист изменяет "myAdd", но забывает изменить "mySubtract", использующий тот же алгоритм. Эти ошибки смягчаются принципом "Не повторяйся". Устаревшие или неточные комментарии: многие программисты полагают, что комментарии точно отражают код. Расхождения между документацией и продуктом.
Отчет "Ошибки в системе"
Институт открытых технологий, управляемый организацией New America, опубликовал отчет "Bugs in the System" в августе 2016 года, в котором утверждается, что американским законодателям следует провести реформы, чтобы помочь исследователям выявлять и устранять ошибки в программном обеспечении. В отчете "подчеркивается необходимость реформирования в сфере обнаружения и раскрытия информации об уязвимостях программного обеспечения". Один из авторов отчета заявил, что Конгресс недостаточно внимания уделяет проблеме уязвимостей киберпрограммного обеспечения, несмотря на принятие ряда законопроектов для борьбы с более широкой проблемой кибербезопасности. Канадский фильм 2008 года "Control Alt Delete" рассказывает о программисте, который в конце 1999 года пытается исправить ошибки в своей компании, связанные с проблемой 2000 года.