Из Википедии, бесплатной энциклопедии
  (Перенаправлено из арифметического переполнения )
Перейти к навигации Перейти к поиску

Целочисленное переполнение может быть продемонстрировано через переполнение одометра , механическую версию явления. Все цифры устанавливаются на максимум 9, и следующее приращение белой цифры вызывает каскад переходящих добавлений, устанавливающих все цифры на 0, но нет более высокой цифры (цифра 1000000), которая могла бы измениться на 1, поэтому счетчик сбрасывается в ноль. Это обертывание в отличие от насыщения .

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

Наиболее частым результатом переполнения является сохранение наименее значимых представимых цифр результата; считается, что результат оборачивается вокруг максимума (т. е. по модулю степени системы счисления , обычно два в современных компьютерах, но иногда десять или другое основание системы счисления).

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

Для некоторых приложений, таких как таймеры и часы, может быть желательно перенос при переполнении. Стандарт C11 утверждает, что для беззнаковых целых чисел перенос по модулю является определенным поведением, и термин «переполнение» никогда не применяется: «вычисление с участием беззнаковых операндов никогда не может переполниться». [1]

На некоторых процессорах, таких как графические процессоры (GPU) и процессоры цифровых сигналов (DSP), которые поддерживают арифметику насыщения , результаты переполнения будут «фиксироваться», то есть устанавливаться на минимальное или максимальное значение в представляемом диапазоне, а не обертываться.

Происхождение [ править ]

Ширина регистра процессора определяет диапазон значений , которые могут быть представлены в его регистрах. Хотя подавляющее большинство компьютеров может выполнять арифметические операции с множественной точностью для операндов в памяти, позволяя числам быть произвольно длинными и избегать переполнения, ширина регистра ограничивает размеры чисел, с которыми можно работать (например, складывать или вычитать) с использованием одна инструкция на операцию. Типичная ширина двоичного регистра для целых чисел без знака включает:

  • 4 бита: максимальное представимое значение 2 4 - 1 = 15
  • 8 бит: максимальное представимое значение 2 8 - 1 = 255
  • 16 бит: максимальное представимое значение 2 16 - 1 = 65 535
  • 32 бита: максимальное представимое значение 2 32 - 1 = 4294967295 (наиболее распространенная ширина для персональных компьютеров по состоянию на 2005 год ),
  • 64 бита: максимальное представимое значение 2 64 - 1 = 18 446 744 073 709 551 615 (наиболее распространенная ширина для процессоров персональных компьютеров по состоянию на 2017 год ),
  • 128 бит: Максимальное значение представима 2 128 - 1 = 340.282.366.920.938.463.463.374.607.431.768.211.455

Когда арифметическая операция дает результат, превышающий указанный выше максимум для N-битового целого числа, переполнение уменьшает результат до N-й степени по модулю 2, сохраняя только младшие значащие биты результата и эффективно вызывая циклический переход .

В частности, умножение или сложение двух целых чисел может привести к неожиданно маленькому значению, а вычитание из небольшого целого числа может вызвать перенос на большое положительное значение (например, сложение 8-битных целых чисел 255 + 2 дает 1, что равно 257 по модулю 2 8 , и аналогичным образом вычитание 0-1 дает 255, представление с дополнением до двух для −1).

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

Если переменная имеет целочисленный тип со знаком , программа может сделать предположение, что переменная всегда содержит положительное значение. Целочисленное переполнение может привести к переносу значения и стать отрицательным, что нарушает предположение программы и может привести к неожиданному поведению (например, сложение 8-битного целого числа 127 + 1 дает -128, дополнение до двух до 128). (Решением этой конкретной проблемы является использование целочисленных типов без знака для значений, которые программа ожидает и предполагает, что они никогда не будут отрицательными.)

Флаги [ править ]

Большинство компьютеров имеют два выделенных флага процессора для проверки условий переполнения.

Флаг переноса устанавливается , если результат сложения или вычитания, учитывая операнды и результат в виде числа без знака, не укладывается в заданное число битов. Это указывает на переполнение с переносом или заимствованием из наиболее значимого бита . Сразу после операции сложения с переносом или вычитания с заимствованием содержимое этого флага будет использоваться для изменения регистра или области памяти, которая содержит старшую часть многословного значения.

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

Варианты определения и неоднозначность [ править ]

Для беззнакового типа, когда идеальный результат операции находится за пределами представимого диапазона типа и возвращаемый результат получается путем упаковки, это событие обычно определяется как переполнение. Напротив, стандарт C11 определяет, что это событие не является переполнением, и заявляет, что «вычисление с участием беззнаковых операндов никогда не может переполниться». [1]

Когда идеальный результат целочисленной операции находится за пределами представимого диапазона типа и возвращаемый результат получается путем ограничения, то это событие обычно определяется как насыщение. Использование зависит от того, является ли насыщение переполнением или нет. Чтобы устранить двусмысленность, можно использовать термины обертывающее переполнение [2] и насыщающее переполнение [3] .

Термин «потеря значимости» чаще всего используется для математики с плавающей запятой, а не для целочисленной. [4] Но можно найти много ссылок на целочисленное недополнение. [5] [6] [7] [8] [9] Когда используется термин целочисленное исчезновение, это означает, что идеальный результат был ближе к минус бесконечности, чем представимое значение выходного типа, ближайшее к минус бесконечности. Когда используется термин целочисленное отсутствие переполнения, определение переполнения может включать в себя все типы переполнения или только те случаи, когда идеальный результат был ближе к положительной бесконечности, чем представимое значение выходного типа, ближайшее к положительной бесконечности.

Когда идеальный результат операции не является точным целым числом, значение переполнения может быть неоднозначным в крайних случаях. Рассмотрим случай, когда идеальный результат имеет значение 127,25, а максимальное представимое значение типа вывода - 127. Если переполнение определено как идеальное значение, выходящее за пределы представимого диапазона типа вывода, то этот случай будет классифицирован как переполнение. Для операций с четко определенным поведением округления может потребоваться отложить классификацию переполнения до тех пор, пока не будет применено округление. Стандарт C11 [1]определяет, что преобразования из числа с плавающей запятой в целое число должны округляться до нуля. Если C используется для преобразования значения 127,25 с плавающей запятой в целое число, то сначала следует применить округление, чтобы получить идеальное целое число на выходе 127. Поскольку округленное целое число находится в диапазоне выходных значений, стандарт C не классифицирует это преобразование как переполнение. .

Непоследовательное поведение [ править ]

Стоит отметить, что поведение при возникновении переполнения может быть непротиворечивым во всех обстоятельствах. В Русте программирование языка , например, в то время как функциональность будет предоставлена дать выбор пользователей и управление, поведение для основного использования математических операторов естественно фиксированным; это фиксированное поведение, однако, различается между программой, встроенной в режим «отладки», и программой, встроенной в режим «выпуска». [10] В C целочисленное переполнение без знака определено для переноса, в то время как целочисленное переполнение со знаком вызывает неопределенное поведение .

Методы решения проблем с целочисленным переполнением [ править ]

Обнаружение [ править ]

Реализация обнаружения переполнения Запуск времени UBSanдоступна для компиляторов C .

В Java 8 есть перегруженные методы , например, такие как Math.addExact(int, int), которые срабатываютArithmeticException в случае переполнения.

Группа реагирования на компьютерные чрезвычайные ситуации (CERT) разработала целочисленную модель с неограниченным диапазоном значений (AIR) - в значительной степени автоматизированный механизм для устранения целочисленного переполнения и усечения в C / C ++ с использованием обработки ошибок во время выполнения. [14]

Избегание [ править ]

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

Обработка [ править ]

Если ожидается, что может произойти переполнение, тогда в программу можно вставить тесты, чтобы определить, когда это произойдет или вот-вот произойдет, и выполнить другую обработку, чтобы смягчить его. Например, если важный результат, вычисленный из переполнения пользовательского ввода, программа может остановиться, отклонить ввод и, возможно, предложить пользователю другой ввод, вместо того, чтобы программа продолжала работу с недопустимым переполненным вводом и, возможно, как следствие, неисправна. Этот полный процесс можно автоматизировать: можно автоматически синтезировать обработчик для целочисленного переполнения, где обработчик, например, является чистым выходом. [15]

У ЦП обычно есть способ обнаружения этого для поддержки добавления чисел, превышающих размер их регистра, обычно с помощью бита состояния; этот метод называется арифметикой с высокой точностью. Таким образом, можно добавить два числа шириной в два байта, используя только пошаговое добавление байтов: сначала добавьте младшие байты, затем добавьте старшие байты, но если необходимо выполнить из младших байтов, это арифметическое переполнение добавление байтов, и становится необходимым обнаруживать и увеличивать сумму старших байтов.

Обработка возможного переполнения при вычислении может иногда представлять выбор между выполнением проверки перед фактическим вычислением (чтобы определить, произойдет ли переполнение) или после него (чтобы определить, произошло ли это, вероятно, на основании полученного значения) . К последнему выбору следует проявлять осторожность. Во-первых, поскольку это может быть ненадежный метод обнаружения (например, добавление не обязательно может привести к более низкому значению). Во-вторых, поскольку возникновение переполнения может в некоторых случаях быть неопределенным.. В языке программирования C переполнение целочисленных типов без знака приводит к переносу, однако переполнение целочисленных типов со знаком является неопределенным поведением; следовательно, компилятор C может предположить, что программист гарантировал невозможность подписанного переполнения, и, таким образом, он может молча оптимизировать любую проверку после вычисления, которая включает проверку результата для его обнаружения, не давая программисту никакого предупреждения о том, что это было сделано. Таким образом, рекомендуется всегда проводить проверки до расчетов, а не после них.

Явное распространение [ править ]

если значение слишком велико для сохранения, ему может быть присвоено специальное значение, указывающее, что произошло переполнение, а затем все последующие операции возвращают это значение флага. Такие значения иногда называют NaN , что означает «не число». Это полезно для того, чтобы можно было проверить проблему один раз в конце длинных вычислений, а не после каждого шага. Это часто поддерживается оборудованием с плавающей запятой, называемым FPU .

Поддержка языков программирования [ править ]

Языки программирования реализуют различные методы смягчения последствий случайного переполнения: Ada , Seed7 (и некоторые варианты функциональных языков) запускают условие исключения при переполнении, а Python (начиная с версии 2.4) легко преобразует внутреннее представление числа в соответствии с его ростом, в конечном итоге представляя это как long- чьи возможности ограничены только доступной памятью. [16]

В языках с встроенной поддержкой арифметики произвольной точности и безопасности типов (таких как Python , Smalltalk или Common Lisp ) числа автоматически увеличиваются до большего размера при возникновении переполнения или выдаче исключений (сигнализация условий) при наличии ограничения диапазона. Таким образом, использование таких языков может помочь смягчить эту проблему. Однако в некоторых таких языках все еще возможны ситуации, когда может произойти целочисленное переполнение. Примером является явная оптимизация пути кода, который профилировщик считает узким местом. В случае Common Lisp это возможно за счет использования явного объявления для аннотации типа переменной к слову машинного размера (fixnum)[17] и понизьте уровень безопасности типа до нуля [18] для конкретного кодового блока. [19] [20] [21] [22]

В отличие от более старых языков, таких как C, некоторые новые языки, такие как Rust, например, предоставляют встроенную функциональность, которая позволяет легко обнаруживать и выбирать пользователю, как следует обрабатывать переполнение в каждом конкретном случае. В Rust, хотя использование основных математических операторов, естественно, лишено такой гибкости, пользователи могут альтернативно выполнять вычисления с помощью набора методов, предоставляемых каждым из целочисленных примитивных типов. Эти методы предоставляют пользователям несколько вариантов выбора между выполнением «проверенной» (или «переполненной») операции (которая указывает, произошло ли переполнение через возвращаемый тип); «неконтролируемая» операция; операция, которая выполняет упаковку, или операцию, которая выполняет насыщение на числовых границах.

Насыщенная арифметика [ править ]

В компьютерной графике или обработке сигналов обычно работают с данными в диапазоне от 0 до 1 или от -1 до 1. Например, возьмите изображение в градациях серого, где 0 представляет черный цвет, 1 представляет белый цвет, а значения между ними представляют оттенки серого. Одна операция, которую можно поддержать, - это осветление изображения путем умножения каждого пикселя на константу. Насыщенная арифметика позволяет просто слепо умножать каждый пиксель на эту константу, не беспокоясь о переполнении, просто придерживаясь разумного результата, что все эти пиксели больше 1 (т. Е. «Ярче белого» ) просто становятся белыми, а все значения «темнее черного» "просто стать черным.

Примеры [ править ]

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

Получение среднего арифметического двух чисел путем сложения их и деления на два, как это делается во многих алгоритмах поиска , вызывает ошибку, если сумма (хотя и не результирующее среднее) слишком велика для представления и, следовательно, выходит за пределы. [23]

Необработанное арифметическое переполнение в программном обеспечении управления двигателем было основной причиной крушения первого полета ракеты Ariane 5 в 1996 году . [24]Считалось, что программное обеспечение не содержит ошибок, поскольку оно использовалось во многих предыдущих полетах, но в них использовались ракеты меньшего размера, которые генерировали меньшее ускорение, чем Ariane 5. К сожалению, часть программного обеспечения, в которой произошла ошибка переполнения, даже не требовалась. запускался для Ariane 5 в то время, когда он привел к отказу ракеты - это был процесс режима запуска для меньшего предшественника Ariane 5, который остался в программном обеспечении, когда он был адаптирован для новой ракеты. Кроме того, фактической причиной сбоя была ошибка в технической спецификации того, как программное обеспечение справлялось с переполнением, когда оно было обнаружено: оно выполнило диагностический дамп на свою шину, которая должна была быть подключена к испытательному оборудованию во время тестирования программного обеспечения во время разработки но был связан с двигателями рулевого управления ракеты во время полета;сброс данных сильно отклонил сопло двигателя в сторону, что вывело ракету из-под контроля аэродинамики и ускорило ее быстрое разрушение в воздухе.[25]

30 апреля 2015 года Федеральное управление гражданской авиации США объявило, что прикажет операторам Boeing 787 периодически перезагружать его электрическую систему, чтобы избежать целочисленного переполнения, которое может привести к потере электроэнергии и развертыванию воздушной турбины с набегающим потоком , и Boeing развернул обновление программного обеспечения в четвертый квартал. [26] Европейское агентство по авиационной безопасности с последующим 4 мая 2015 года [27] Ошибка происходит после того, как 2³¹ сантисекундах (248.55134814815 дней), что указывает на 32-битовую подписанную целое .

Ошибки переполнения очевидны в некоторых компьютерных играх. В аркадной игре Donkey Kong , невозможно продвинуться мимо уровня 22 из - за целочисленное переполнение в свое время / бонус. Игра берет номер уровня, на котором находится пользователь, умножает его на 10 и добавляет 40. Когда они достигают уровня 22, количество времени / бонуса равно 260, что слишком велико для его 8-битного регистра значений 256, поэтому он сбрасывается. до 0 и дает оставшиеся 4 как время / бонус - слишком мало для завершения уровня. В Donkey Kong Jr. Math при попытке вычислить число, превышающее 10 000, отображаются только первые 4 цифры. Переполнение является причиной известного уровня «разделенного экрана» в Pac-Man . [28] Это также привело к появлению "Дальних земель" вMinecraft, который существовал с периода разработки Infdev до Beta 1.7.3; однако позже это было исправлено в Beta 1.8, но все еще существует в версиях Minecraft Pocket Edition и Windows 10 Edition. [29] Вигре Lamborghini American Challenge для Super Nintendo , игрок может привести к тому, что его сумма денег упадет ниже 0 долларов во время гонки, будучи оштрафована сверх лимита оставшихся денег после уплаты сбора за гонку, что приводит к сбою целого числа и дает игрок на 65 535 000 долларов больше, чем он получил бы после отрицательного результата. [30] Аналогичный сбой происходит в STALKER: Clear Sky.где игрок может упасть до отрицательной суммы, быстро путешествуя без достаточных средств, а затем перейдя к событию, где игрока ограбят и у него отберут всю его валюту. После того, как игра попытается забрать деньги игрока на сумму в 0 долларов, игроку предоставляется 2147482963 игровой валюты. [31]

В структуре данных Pokémon в играх Pokémon количество полученных очков опыта хранится в виде 3-байтового целого числа. Однако в первом и втором поколениях группа опыта со средней медленной скоростью, которой требуется 1 059 860 очков опыта для достижения 100 уровня, по расчетам имеет -54 очка опыта на уровне 1. Поскольку целое число не имеет знака, значение превращается в 16 777 162. Если Покемон набирает менее 54 очков опыта в битве, тогда Покемон мгновенно переходит на уровень 100. [32] [33] [34] [35] [ ненадежный источник? ]

Ошибка целочисленной подписи в коде настройки стека, выдаваемая компилятором Pascal, не позволяла Microsoft / IBM MACRO Assembler Version 1.00 (MASM), программе DOS 1981 года и многим другим программам, скомпилированным с тем же компилятором, работать в некоторых конфигурациях с более чем 512 КБ памяти.

Microsoft / IBM MACRO Assembler (MASM) версии 1.00 и, вероятно, все другие программы, созданные тем же компилятором Pascal, имели целочисленное переполнение и ошибку подписи в коде настройки стека, что препятствовало их запуску на новых машинах DOS или эмуляторах с некоторыми распространенными конфигурации с объемом памяти более 512 КБ. Программа либо зависает, либо отображает сообщение об ошибке и выходит в DOS. [36]

В августе 2016 года автомат в казино Resorts World Casino распечатал призовой билет на 42 949 672,76 долларов в результате ошибки переполнения. Казино отказалось выплатить эту сумму, назвав это неисправностью, используя в свою защиту то, что в автомате четко указано, что максимальная выплата составляет 10 000 долларов, поэтому любой превышающий эту сумму приз должен быть результатом ошибки программирования. Верховный суд штата Айова вынес решение в пользу казино. [37]

См. Также [ править ]

  • Переполнение буфера
  • Переполнение кучи
  • Модульная арифметика
  • Указатель swizzling
  • Тестирование программного обеспечения
  • Переполнение буфера стека
  • Статический анализ программы
  • Сигнал Unix

Ссылки [ править ]

  1. ^ а б в ISO. «ISO / IEC 9899: 2011 Информационные технологии - Языки программирования - C» . webstore.ansi.org .
  2. ^ «Обертывание при переполнении - MATLAB и Simulink» . www.mathworks.com .
  3. ^ "Насыщение при переполнении - MATLAB и Simulink" . www.mathworks.com .
  4. ^ Арифметическое переполнение
  5. ^ "CWE - CWE-191: Целочисленное недополнение (перенос или повторение) (3.1)" . cwe.mitre.org .
  6. ^ «Переполнение и потеря типов данных в Java - DZone Java» . dzone.com .
  7. Мир, Табиш (4 апреля 2017 г.). «Целочисленное переполнение / потеря значимости и неточность с плавающей точкой» . medium.com .
  8. ^ «Целочисленное переполнение и обработка метаданных MP4 в libstagefright при переполнении буфера» . Mozilla .
  9. ^ «Предотвращение переполнения и истощения буфера» . developer.apple.com .
  10. ^ "Операторные выражения - Справочник по Rust" . doc.rust-lang.org . Проверено 12 февраля 2021 .
  11. ^ Билл Вагнер. «Проверено и отключено (Справочник по C #)» . msdn.microsoft.com .
  12. ^ Руководство по Seed7, раздел 15.2.3 OVERFLOW_ERROR.
  13. ^ Язык программирования Swift. Версия Swift 2.1. 21 октября 2015 года.
  14. ^ Как если бы бесконечно ранжированная целочисленная модель
  15. ^ Мунтян, Пол Иоан; Монперрус, Мартин; Сунь, Хао; Гроссклагс, Йенс; Эккерт, Клаудия (2019). «IntRepair: информированное восстановление целочисленных переполнений». IEEE Transactions по разработке программного обеспечения : 1. arXiv : 1807.05092 . DOI : 10.1109 / TSE.2019.2946148 . ISSN 0098-5589 . 
  16. ^ Документация Python , раздел 5.1 Арифметические преобразования.
  17. ^ " Декларация TYPE " . Common Lisp HyperSpec .
  18. ^ " Декларация ОПТИМИЗАЦИЯ " . Common Lisp HyperSpec .
  19. Редди, Абхишек (22 августа 2008 г.). «Особенности Common Lisp» .
  20. ^ Пирс, Бенджамин С. (2002). Типы и языки программирования . MIT Press. ISBN 0-262-16209-1.
  21. ^ Райт, Эндрю К .; Маттиас Фелляйзен (1994). «Синтаксический подход к правильности шрифтов» . Информация и вычисления . 115 (1): 38–94. DOI : 10.1006 / inco.1994.1093 .
  22. ^ Macrakis, Ставрос (апрель 1982 г.). «Безопасность и мощь». Примечания по разработке программного обеспечения ACM SIGSOFT . 7 (2): 25–26. DOI : 10.1145 / 1005937.1005941 .
  23. ^ «Extra, Extra - прочтите все об этом: почти все двоичные поиски и слияния не работают» . googleresearch.blogspot.co.uk .
  24. ^ Gleick, Джеймс (1 декабря 1996). «Ошибка и авария» . Нью-Йорк Таймс . Проверено 17 января 2019 .
  25. Официальный отчет о неудачном запуске Ariane 5.
  26. ^ Mouawad, Джад (30 апреля 2015). «Приказ FAA о возможной потере мощности в Boeing 787» . Нью-Йорк Таймс .
  27. ^ «US-2015-09-07: Электроэнергия - Деактивация» . Директивы по летной годности . Европейское агентство по авиационной безопасности . 4 мая 2015.
  28. ^ Питтман, Джейми. "Досье Пакмана" .
  29. ^ Minecraft Gamepedia. «Страница Minecraft Gamepedia» .
  30. ^ https://www.youtube.com/watch?v=aNQdQPi0xMo&t=17m55s
  31. ^ https://steamcommunity.com/app/20510/discussions/0/1484358860942756615/
  32. ^ Структура данных покемонов в Generation I
  33. ^ Структура данных покемонов в поколении II
  34. ^ Структура данных покемонов в Generation III
  35. ^ Структура данных покемонов в IV поколения
  36. ^ Lenclud, Кристоф. «Отладка IBM MACRO Assembler версии 1.00» .
  37. Кравец, Дэвид (15 июня 2017 г.). « К сожалению , мэм вы не выиграли $ 43M - был игровой автомат„неисправность » . Ars Technica .

Внешние ссылки [ править ]

  • Фракция № 60, Основные целочисленные переполнения
  • Фрак № 60, Целочисленная защита большого цикла
  • Эффективное и точное обнаружение целочисленных атак
  • Классификация угроз WASC - целочисленные переполнения
  • Понимание целочисленного переполнения в C / C ++
  • Двоичное переполнение - двоичная арифметика
  • Стандарт ISO C11