Ошибка n 39 численное переполнение данные потеряны переполнение

Артем

Сообщения: 12
Зарегистрирован: 18 фев 2014 09:19

При пакетной обработке прайс листов процесс прерывается с ошибкой №39

Вложения
2014-06-11 12-18-39 Скриншот экрана.png
2014-06-11 12-18-39 Скриншот экрана.png (6.5 КБ) 2842 просмотра

Аватара пользователя

archikes

Сообщения: 37
Зарегистрирован: 18 фев 2012 14:11

15 июн 2014 16:32

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

Вложения
2014-06-15 16-27-40 Скриншот экрана.png
2014-06-15 16-27-40 Скриншот экрана.png (17.22 КБ) 2807 просмотров

Аватара пользователя

support

Сообщения: 10553
Зарегистрирован: 09 ноя 2008 21:37

16 июн 2014 09:43

Да, вышлите архив БД программы, сообщите какое наименование добавляете, и опишите проблему в письме. Проверим.

Аватара пользователя

archikes

Сообщения: 37
Зарегистрирован: 18 фев 2012 14:11

16 июн 2014 11:05

Извините не совсем точно написал.

Когда пытаюсь перенести товар из СТИП (правой колонки где товары поставщиков) в СТУС (в левую колонку где мои товары)
Выдает эту ошибку, но товары переводит.

Отправил

Аватара пользователя

support

Сообщения: 10553
Зарегистрирован: 09 ноя 2008 21:37

16 июн 2014 15:44

archikes писал(а):Извините не совсем точно написал.

Когда пытаюсь перенести товар из СТИП (правой колонки где товары поставщиков) в СТУС (в левую колонку где мои товары)
Выдает эту ошибку, но товары переводит.

Отправил

Не получали от Вас ничего.

Аватара пользователя

support

Сообщения: 10553
Зарегистрирован: 09 ноя 2008 21:37

17 июн 2014 09:58

В связи с тем, что у Вас в настройках программы включен параметр формирования числового артикула,
При добавлении нового товара, программа не может сформировать новый артикул по принципу
+1 от последнего артикула в стус, так как товары TCL 42E5300F и TCL 39E5000
имеют в артикуле «39E» — программа думает что это число с 39 нулями. (

http://otvet.mail.ru/question/62425550

)
Для этих товаров необходимо вручную скорректировать артикул.

  • Новичок

    • Регистрация: 22.11.2005
    • Сообщений: 87
    • Спасибо: 0

    Ошибка при дополнении списка сотрудников

    08.12.2005, 16:52

    Подскажите пожалуйста! Дополняем список новыми сотрудниками. При заполнении поля «Дата рождения» программа (Зарплата 2005) выдает сообщение: Ошибка 39.Численное переполнение. Данные потеряны.
    И далее.. В чем дело?

    Метки:

    Нет



    • Спасибо



      0

  • Денис У.

    Сотрудник Бухсофт.ру

    • Регистрация: 05.03.2005
    • Сообщений: 1246
    • Спасибо: 203

    Ответ: Ошибка при дополнении списка сотрудников

    Сообщение от ААА

    Подскажите пожалуйста! Дополняем список новыми сотрудниками. При заполнении поля «Дата рождения» программа (Зарплата 2005) выдает сообщение: Ошибка 39.Численное переполнение. Данные потеряны.
    И далее.. В чем дело?

    Скорей всего проблема с базой данных программы. Высылайте архив (описано в инструкции) для анализа и устранения проблемы.



    • Спасибо



      0

    Комментарий

  • Новичок

    • Регистрация: 22.11.2005
    • Сообщений: 87
    • Спасибо: 0

    Ответ: Ошибка при дополнении списка сотрудников

    Архив выслан. В течении какого времени можно будет ожидать ответ?



    • Спасибо



      0

    Комментарий

  • Денис У.

    Сотрудник Бухсофт.ру

    • Регистрация: 05.03.2005
    • Сообщений: 1246
    • Спасибо: 203

    Ответ: Ошибка при дополнении списка сотрудников

    Архив получили. Постараемся сегодня разобраться.



    • Спасибо



      0

    Комментарий

  • Новичок

    • Регистрация: 22.11.2005
    • Сообщений: 87
    • Спасибо: 0

    Ответ: Ошибка при дополнении списка сотрудников

    Спасибо. Буду ждать.



    • Спасибо



      0

    Комментарий

  • Новичок

    • Регистрация: 22.11.2005
    • Сообщений: 87
    • Спасибо: 0

    Ответ: Ошибка при дополнении списка сотрудников

    Не хочется Вас торопить, однако не могли бы Вы дать знать о результатах хода работы над проблемой?



    • Спасибо



      0

    Комментарий

  • Денис У.

    Сотрудник Бухсофт.ру

    • Регистрация: 05.03.2005
    • Сообщений: 1246
    • Спасибо: 203

    Ответ: Ошибка при дополнении списка сотрудников

    Ответ с исправленной базой был Вам отправлен в 18-46 08.12.05. Выслал повторно.



    • Спасибо



      0

    Комментарий

  • Новичок

    • Регистрация: 22.11.2005
    • Сообщений: 87
    • Спасибо: 0

    Ответ: Ошибка при дополнении списка сотрудников

    Благодарю Вас за оперативную помощь. Не могли бы Вы сказать, не была ли причиной ошибки некорректная работа с базой, во избежание повторения подобных ошибок в будущем?
    C уважением, Антон



    • Спасибо



      0

    Комментарий

  • Денис У.

    Сотрудник Бухсофт.ру

    • Регистрация: 05.03.2005
    • Сообщений: 1246
    • Спасибо: 203

    Ответ: Ошибка при дополнении списка сотрудников

    Что явилось причиной этой проблемы — наверняка сказать сложно. Если вдаваться в теорию, то это общая проблема всех современных СУБД. У них иногда возникают проблемы с построением и своевременным обновлением структурных индексных файлов. Бояться этого не стоит. Рекомендуем Вам раз в месяц делать архив данных и все будет нормально. В случае возникновения подобных проблем наши специалисты всегда их оперативно решают.



    • Спасибо



      0

    Комментарий

  • Remove From My Forums
  • Question

  • Hello Folks, How are you All? I’m facing problem when try to add serial number more than 1000? When do error message occured «Numeric overflow, Data was lost», Any advice please? Thank you in advance.

     I’m using code below:

    For print command,

    ch_ser=2
    DO CASE
       CASE ch_ser=1
            SELECT materinf.mat_mtnama,demas2.s2d_serial as serial,0000 as se;
              FROM voucher!demas1,voucher!demas2,voucher!materinf;
             WHERE ALLTRIM(demas1.s1d_matno) == ALLTRIM(materinf.mat_matno) AND demas1.s1d_deseq1==demas2.s2d_deseq1 ;
                   and demas1.s1d_mdeseq==mdeseq AND NOT EMPTY(demas2.s2d_serial) ;
             ORDER BY materinf.mat_mtnama ;  

           INTO TABLE c:temvouprserial.dbf
     CASE ch_ser=2
            SELECT materinf.mat_mtnama,charges2.s2c_serial as serial,0000 as se;
              FROM voucher!demas1,voucher!charges2,voucher!materinf;
             WHERE ALLTRIM(demas1.s1d_matno) == ALLTRIM(materinf.mat_matno) AND demas1.s1d_deseq1=charges2.s2c_deseq1 ;
                   and demas1.s1d_mdeseq==mdeseq AND charges2.s2c_dempoi ;
             ORDER BY materinf.mat_mtnama ;  

           INTO TABLE c:temvouprserial.dbf
    ENDCASE
    REPLACE ALL se WITH RECNO()       ;;
    Error here
    USE
    REPORT FORM ..vourepprintserial.frx PREVIEW
    RETURN

    …………………………………….

    For generate command,

     SELECT demas1
       REPLACE s1d_mtname WITH mtname
       IF logserx
          mtotcou=0
         SELECT charges2
          SET filt to s2c_dempoi
         seek deseq1x
          do while .not. eof() .and. s2c_deseq1=deseq1x
             mtotcou=mtotcou+1
             serial=s2c_serial
             IF uop=30
                SELECT demas2
                m.s2d_deseq1=deseq1x
                m.s2d_seq=mtotcou
                m.s2d_serial=serial
                m.s2d_chseq1=deseq1x
                m.s2d_no=’ 1′
                APPEND BLANK
                GATHER memvar     ;; Error here
             endif  

             SELECT charges2
             SKIP
             IF serial=s2c_serial .and. s2c_deseq1=deseq1x

               messagebox(‘ This serial number already has been chosen ‘+’:’+mtname+’:ser.no.:’+serial)
            SET FILTER TO
            SET EXACT ON
                return
             ENDIF
          ENDDO

    • Edited by

      Monday, November 12, 2012 8:33 AM

Answers

  • No, in this case CAST will not work. I suggest then to try more 0, e.g.

    00000000 as se

    In other words, use as many 0 as you anticipate the width of the field should be.


    For every expert, there is an equal and opposite expert. — Becker’s Law

    My blog

    • Marked as answer by
      Ed Price — MSFTMicrosoft employee
      Monday, November 12, 2012 6:21 AM

Итак, компания, в которой я работаю, имеет более старую ERP-систему, в которой используется FoxPro 4 или 5. У этой системы нет поддержки, поэтому я пытаюсь использовать навыки, которых у меня нет. Я хорошо разбираюсь в серверах и даже в сетях, но не в программировании. Я приложил ссылки на две похожие ошибки, которые возникают у двух разных пользователей в разных отделах, использующих разные компьютеры. Ваша помощь будет оценена по достоинству.

ФоксПро Ошибка 1

ФоксПро Ошибка 2

2 ответа

Ну, проблема именно в том, что написано на банке. Похоже, проблема связана с полем BODY.COST. Поле будет иметь максимальную емкость, например, N(12, 2) позволит хранить в нем числа до 999999999,99.

Система пытается ввести в это поле число, превышающее заданную емкость. Как видите, в обоих случаях это оператор GATHER MEMVAR. Этот оператор принимает переменные памяти и обновляет таблицу базы данных, используя их. Одна из переменных памяти оказалась с большим числом, чем поле базы данных (выглядит как BODY.COST), которое предназначено для ее хранения.

Кроме того, без поддержки и без исходного кода вы действительно ограничены тем, что смотрите, что пользователь пытается опубликовать, и смотрите, дает ли это вам какие-либо подсказки. Это объем дампов ошибок или это просто фрагменты?


6

Alan B
27 Авг 2015 в 13:38

В сообщениях говорится, что вы пытаетесь сохранить большее значение, чем может принять поле. Это происходит с числовыми и плавающими полями в Foxpro. В обоих сообщениях таблица была косвенно названа «ТЕЛО», а проблемное поле — «СТОИМОСТЬ».

В качестве решения, используя VFP5 (не используйте более позднюю версию — не было VFP4), вы можете преобразовать все числовые поля и поля с плавающей точкой в ​​тип данных Currency или Double. Валюта имеет высокую надежность и предлагается для денежных значений (не обязательно денежных). Он находится в диапазоне от –922337203685477,5808 до 922337203685477,5807. Этот диапазон на самом деле выше того, что может поддерживать числовое/плавающее поле.

Если вы считаете, что этого недостаточно, вы можете использовать double (что-то вроде -10 ^ 327 до 10 ^ 304 — VFP имеет точность 15 цифр, вы теряете точность за ее пределами).

Я бы пошел с валютой.


3

Cetin Basoz
29 Авг 2015 в 02:21

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

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

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

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

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

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

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

Содержание

  • 1 Источник
  • 2 Флаги
  • 3 Варианты определения и неоднозначность
  • 4 Методы решения проблем целочисленного переполнения
    • 4.1 Обнаружение
    • 4.2 Предотвращение
    • 4.3 Обработка
    • 4.4 Явное распространение
    • 4.5 Поддержка языка программирования
    • 4.6 Насыщенная арифметика
  • 5 Примеры
  • 6 См. Также
  • 7 Ссылки
  • 8 Внешние ссылки

Источник

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

  • 4 бита: максимальное представимое значение 2-1 = 15
  • 8 битов: максимальное представимое значение 2-1 = 255
  • 16 бит: максимальное представляемое значение 2-1 = 65 535
  • 32 бита: максимальное представляемое значение 2-1 = 4294967 295 (наиболее распространенная ширина для персональных компьютеров с 2005 года),
  • 64 биты: максимальное представляемое значение 2-1 = 18,446,744,073,709,551,615 (наиболее распространенная ширина для персональных компьютеров процессоров, по состоянию на 2017 год),
  • 128 бит: максимальное представляемое значение 2-1 = 340,282,366,920,938,463,463,374,607,431,768,211,455

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

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

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

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

Флаги

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

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

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

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

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

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

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

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

Методы решения проблем целочисленного переполнения

Обработка целочисленного переполнения в различных языках программирования

Язык Целое число без знака Целое число со знаком
Ada по модулю модуль типа поднять Constraint_Error
C /C ++ по модулю степени двойки неопределенное поведение
C# по модулю степени 2 в непроверенном контексте; System.OverflowExceptionвозникает в проверенном контексте
Java N / A степень двойки по модулю
JavaScript все числа имеют двойную точность с плавающей запятой, за исключением нового BigInt
MATLAB Встроенные целые числа насыщаются. Целые числа с фиксированной запятой, настраиваемые для переноса или насыщения
Python 2 N/A , преобразовываются в longтип (bigint)
Seed7 N / A поднять OVERFLOW_ERROR
Схема Н / Д преобразовать в bigNum
Simulink , конфигурируемый для переноса или насыщения
Smalltalk Н / Д преобразовать в LargeInteger
Swift Вызывает ошибку, если не используются специальные операторы переполнения.

Обнаружение

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

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

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

Предотвращение

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

Обработка

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

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

Явное распространение

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

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

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

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

Насыщенная арифметика

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

Примеры

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

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

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

30 апреля 2015 года Федеральное управление гражданской авиации США объявил, что прикажет операторам Boeing 787 периодически перезагружать его электрическую систему, чтобы избежать целочисленного переполнения, которое может привести к потере электроэнергии и развертыванию воздушной турбины, и Boeing развернул обновление ПО в четвертом квартале. Европейское агентство по авиационной безопасности последовало 4 мая 2015 года. Ошибка возникает через 2 центсекунды (248,55134814815 дней), указывая на 32-битное подписанное целое число.

. очевидно в некоторых компьютерных играх. В аркадной игре Donkey Kong, невозможно продвинуться дальше 22 уровня из-за целочисленного переполнения его времени / бонуса. Игра берет номер уровня, на котором находится пользователь, умножает его на 10 и добавляет 40. Когда они достигают уровня 22, количество времени / бонуса равно 260, что слишком велико для его 8-битного регистра значений 256, поэтому он сбрасывается. до 0 и дает оставшиеся 4 как время / бонус — слишком мало для завершения уровня. В Donkey Kong Jr. Math при попытке вычислить число, превышающее 10 000, отображаются только первые 4 цифры. Переполнение является причиной знаменитого уровня «разделенного экрана» в Pac-Man и «Ядерного Ганди» в Civilization. Это также привело к появлению «Дальних земель» в Minecraft, которые существовали с периода разработки Infdev до Beta 1.7.3; однако позже это было исправлено в Beta 1.8, но все еще существует в версиях Minecraft Pocket Edition и Windows 10 Edition. В игре Super Nintendo Lamborghini American Challenge игрок может заставить свою сумму денег упасть ниже 0 долларов во время гонки, будучи оштрафованным сверх лимита оставшихся денег после уплаты сбора за гонка, в которой происходит сбой целого числа, и игрок получает на 65 535 000 долларов больше, чем он получил бы после отрицательного результата. Подобный сбой происходит в S.T.A.L.K.E.R.: Clear Sky, где игрок может упасть до отрицательной суммы, быстро путешествуя без достаточных средств, а затем перейти к событию, где игрока ограбят и у него заберут всю валюту. После того, как игра попытается забрать деньги игрока на сумму в 0 долларов, игроку выдается 2147482963 игровой валюты.

В структуре данных Покемон в играх с покемонами число полученных очков опыта хранится в виде 3-байтового целого числа. Однако в первом и втором поколениях группа опыта со средней медленной скоростью, которой требуется 1 059 860 очков опыта для достижения 100 уровня, по расчетам имеет -54 очка опыта на уровне 1. Поскольку целое число не имеет знака, значение превращается в 16 777 162. Если покемон набирает менее 54 очков опыта в битве, то покемон мгновенно перескакивает на 100-й уровень. Кроме того, если эти покемоны на уровне 1 помещаются на ПК, и игрок пытается их вывести, игра вылетает., из-за чего эти покемоны навсегда застревают на ПК. В тех же играх игрок, используя Редкие Конфеты, может повысить уровень своего Покемона выше 100 уровня. Если он достигает уровня 255 и используется другая Редкая Конфета, то уровень переполняется до 0 (из-за того, что уровень кодируется в один байт, например, 64 16 соответствует уровню 100).

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

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

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

См. Также

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

Ссылки

Внешние ссылки

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

The previous postings all commented on the C99 standard, but in fact this guarantee was already available earlier.

The 5th paragraph of Section 6.1.2.5 Types

of the C89 standard states

A computation involving unsigned operands can never overflow,
because a result that cannot be represented by the resulting unsigned
integer type is reduced modulo the number that is one greater than
the largest value that can be represented by the resulting unsigned integer type.

Note that this allows C programmers to replace all unsigned divisions by some constant to be replaced by a multiplication with the inverse element of the ring formed by C’s modulo 2^N interval arithmetic.

And this can be done without any «correction» as it would be necessary by approximating the division with a fixed-point multiplication with the reciprocal value.

Instead, the Extended Euclidian Algorithm can be used to find the inverse Element and use it as the multiplier. (Of course, for the sake of staying portable, bitwise AND operations should also be applied in order to ensure the results have the same bit widths.)

It may be worthwhile to comment that most C compilers already implement this as an optimization. However, such optimizations are not guaranteed, and therefore it might still be interesting for programmers to perform such optimizations manually in situations where speed matters, but the capabilities of the C optimizer are either unknown or particularly weak.

And as a final remark, the reason for why trying to do so at all: The machine-level instructions for multiplication are typically much faster than those for division, especially on high-performance CPUs.

The previous postings all commented on the C99 standard, but in fact this guarantee was already available earlier.

The 5th paragraph of Section 6.1.2.5 Types

of the C89 standard states

A computation involving unsigned operands can never overflow,
because a result that cannot be represented by the resulting unsigned
integer type is reduced modulo the number that is one greater than
the largest value that can be represented by the resulting unsigned integer type.

Note that this allows C programmers to replace all unsigned divisions by some constant to be replaced by a multiplication with the inverse element of the ring formed by C’s modulo 2^N interval arithmetic.

And this can be done without any «correction» as it would be necessary by approximating the division with a fixed-point multiplication with the reciprocal value.

Instead, the Extended Euclidian Algorithm can be used to find the inverse Element and use it as the multiplier. (Of course, for the sake of staying portable, bitwise AND operations should also be applied in order to ensure the results have the same bit widths.)

It may be worthwhile to comment that most C compilers already implement this as an optimization. However, such optimizations are not guaranteed, and therefore it might still be interesting for programmers to perform such optimizations manually in situations where speed matters, but the capabilities of the C optimizer are either unknown or particularly weak.

And as a final remark, the reason for why trying to do so at all: The machine-level instructions for multiplication are typically much faster than those for division, especially on high-performance CPUs.

У этого термина существуют и другие значения, см. Переполнение.

Целочи́сленное переполне́ние (англ. integer overflow) — ситуация в компьютерной арифметике, при которой вычисленное в результате операции значение не может быть помещено в n-битный целочисленный тип данных. Различают переполнение через верхнюю границу представления и через нижнюю (англ. Underflow).

Пример: сложение двух переменных размером 8 бит с записью результата в переменную того же размера:

[math]displaystyle{ 210_{10} + 61_{10} = 11010010_{2} + 00111101_{2} = ? }[/math]

[math]displaystyle{
begin{array}{c}
begin{array}{cc}
+ & begin{array}{c}
11010010_{2}
00111101_{2}
end{array}
end{array}
hline
begin{array}{cc}
& {color{Red}1}00001111_{2}
end{array}
end{array}
}[/math]

возникает переполнение.

При этом в результат записывается не ожидаемое [math]displaystyle{ 271_{10} = {color{Red}1}00001111_2 }[/math], а [math]displaystyle{ 15_{10} = 00001111_2 }[/math]. Стоит отметить, что вычисление здесь произошло по модулю 2n, а арифметика по модулю циклическая, то есть 255+1=0 (при n = 8). Данная ситуация переполнения фиксируется вычислительной машиной установкой специальных битов регистра флагов Overflow и Carry (пункт 3.4.3.1 Combined Volume: Volume 1[1]). При программировании на языке ассемблера такую ситуацию можно напрямую установить, например, вручную проверив состояние регистра флагов после выполнения операции (пункт 7.3.13.2 Combined Volume: Volume 1[1]).

Происхождение проблемы

Битность регистра определяет диапазон данных, представимый в нём. Диапазоны представления для целых типов в бинарных вычислительных машинах:

Битность 8 бит 16 бит 32 бит 64 бит
Беззнаковый Диапазон 0..28−1 0..216−1 0..232−1 0..264−1
Диапазон (десятич.) 0..255 0..65535 0..4294967295 0.. 18446744073709551615
Знаковый Диапазон -27.. 27−1 -215.. 215−1 -231.. 231−1 -263.. 263−1
Диапазон (десятич.) -128..127 -32768..32767 -2147483648.. 2147483647 -9223372036854775808.. 9223372036854775807

Переполнение может возникнуть в исходном коде вследствие ошибки программиста или его недостаточной бдительности к входным данным[2].

  • Несоответствие знакового и беззнакового. Если числа представляются на вычислителе в дополнительном коде, то одному потоку бит соответствуют различные числа. В 32-битной арифметике знаковому −1 соответствует беззнаковое 4294967295 (верхняя граница представления). То есть приведение одного типа к другому может привести к значительной разнице в значении. Этот тип ошибки часто является последствием signedness error ( and), то есть неправильного приведения типов между типами разной знаковости
  • Проблема срезки. Возникает, если число интерпретируется как целое меньшей длины. В таком случае только младшие биты останутся в числе. Старшие отбросятся, что приведет к изменению численного значения
  • Знаковое расширение. Стоит помнить, что при приведении знакового числа к типу большей длины происходит копирование старшего бита, что в случае интерпретации как беззнаковое приведет к получению очень большого числа[3]

Риски для безопасности

Возможность переполнения широко используется программистами, например, для хеширования и криптографии, генерирования случайных чисел и нахождения границ представления типа[4]. В то же время, например, по стандарту языков C и C++, беззнаковые вычисления выполняются по модулю 2, в то время как знаковое переполнение является классическим примером[5] неопределённого поведения[6].

Такой вид некорректности в коде ведёт к следующим последствиям[4]:

  1. Компиляция может пойти неожиданным образом. Из-за наличия неопределённого поведения в программе, оптимизации компилятора могут изменить поведение программы.
  2. Бомба замедленного действия. На текущей версии ОС, компилятора, опций компиляции, структурной организации программы и т. д. всё может работать, а при любом изменении, например, появлении более агрессивных оптимизаций, сломаться.
  3. Иллюзия предсказуемости. Конкретная конфигурация компилятора может иметь вполне определённое поведение, например компиляторы языков C и C++ обычно реализуют операции по модулю 2n и для знаковых типов (только интерпретированных в дополнительном коде), если отключены агрессивные оптимизации. Однако, надеяться на такое поведение нельзя, иначе есть риск эффекта «бомбы замедленного действия»
  4. Образование диалектов. Некоторые компиляторы предоставляют дополнительные опции для того, чтобы доопределить неопределённое поведение. Например, и GCC, и Clang поддерживают опцию -fwrapv, обеспечивающую выше описанное (в пункте 3) поведение.

Изменение стандарта может привести к новым проблемам с переполнением. К примеру, 1<<31 было зависимым от реализации в стандартах ANSI C и C++98, в то время как стали неопределённым в C99 и C11 (для 32-битных целых).[4]

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

Эксплуатация и последствия

Основные последствия для безопасности[7]:

  • Для доступности. Возможный отказ системы (окно для DoS-атак)
  • Для целостности. Неавторизированный доступ к данным
  • Для конфиденциальности. Исполнение стороннего кода, обход защитного механизма

Классически переполнение может быть эксплуатировано через переполнение буфера.

img_t* table_ptr; /*struct containing img data, 10kB each*/
int num_imgs;
...
num_imgs = get_num_imgs();
table_ptr = (img_t*)malloc(sizeof(img_t)*num_imgs);
...

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

Другая уязвимость в том, что если num_imgs ещё больше, это приведёт к переполнению аргумента malloc. Тогда выделится лишь небольшой буфер. При записи в него произойдёт переполнение буфера, последствиями чего могут стать: перехват контроля над исполнением, исполнение кода злоумышленника, доступ к важной информации.[8]

Предотвращение проблемы

Защита от подобного поведения должна проводиться на нескольких уровнях[7]:

  1. Планирования и требований к программе:
    • Убедитесь, что все протоколы взаимодействия между компонентами строго определены. В том числе, что все вычисления вне границ представления будут обнаружены. И требуйте строгого соответствия этим протоколам
    • Используйте язык программирования и компилятор, которые не позволяет этой уязвимости воплотиться, либо позволяют легче её обнаружить, либо выполняют авто-проверку границ. Инструменты, которые предоставляются компилятором, включают санитайзеры (например, Address Sanitizer[en] или Undefined Behavior Sanitizer).
  2. Архитектуры программы:
    • Используйте проверенные библиотеки или фреймворки, помогающие проводить вычисления без риска непредсказуемых последствий. Примеры включают такие библиотеки, как SafeInt (C++) или IntegerLib (C или C++).
    • Любые проверки безопасности на стороне клиента должны быть продублированы на стороне сервера, чтобы не допустить CWE-602. Злоумышленник может миновать проверку на стороне клиента, изменив сами значения непосредственно после прохождения проверки или модифицируя клиента, чтобы полностью убрать проверки.
  3. Реализации:
    • Проводите валидацию любых поступивших извне числовых данных, проверяя что они находятся внутри ожидаемого диапазона. Проверяйте обязательно как минимальный порог, так и максимальный. Используйте беззнаковые числа, где это возможно. Это упростит проверки на переполнение.
    • Исследуйте все необходимые нюансы языка программирования, связанные с численными вычислениями (CWE-681). Как они представляются, какие различия между знаковыми и беззнаковыми, 32-битными и 64-битными, проблемы при кастовании (обрезка, знаково-беззнаковое приведения типов — выше) и как обрабатываются числа, слишком маленькие или, наоборот, большие для их машинного представления. Также убедитесь, что используемый вами тип (например, int или long) покрывают необходимый диапазон представления
    • Подробно изучите полученные от компилятора предупреждения и устраните возможные проблемы безопасности, такие как несоответствия знаковости операндов при операциях с памятью или использование неинициализированных переменных. Даже если уязвимость совсем небольшая, это может привести к опасности для всей системы.

Другие правила, позволяющие избежать этих уязвимостей, опубликованы в стандарте CERT C Secure Coding Standard в 2008 году, включают[9]:

  • Не пишите и не используйте функции обработки строкового ввода, если они обрабатывают не все случаи
  • Не используйте битовые операции над знаковыми типами
  • Вычисляйте выражения на типе большего размера перед сравнением или присваиванием в меньший
  • Будьте внимательны перед приведением типа между числом и указателем
  • Убедитесь, что вычисления по модулю или результаты деления не приводят к последующему делению на ноль
  • Используйте intmax_t или uintmax_t для форматированного ввода-вывода пользовательских числовых типов

Примеры из жизни

Исследование SPECCINT

В статье[4] в качестве предмета исследования программ на языках C и C++ на целочисленное переполнение подробно исследуется один из самых широко применимых и известных тестовых пакетов SPEC, используемый для измерений производительности. Состоит он из фрагментов наиболее распространённых задач, как то: тестов вычислительной математики, компиляции, работы с базами данных, диском, сетью и прочее.

Результаты анализа SPECCINT2000 показывают наличие 219 статических источников переполнения в 8 из 12 бенчмарков, из которых 148 использовали беззнаковое переполнение и 71 — знаковое (снова неопределённое поведение). В то же время, беззнаковое переполнение тоже не всегда намеренное и может являться ошибкой и источником уязвимости (например, Listing 2 той же статьи[4]).

Также был проведён тест на «бомбы замедленного действия» в SPECCINT2006. Его идеей является в каждом месте неопределённого поведения вернуть случайное число и посмотреть, к каким последствиям это может привести. Если оценивать неопределённое поведение с точки зрения стандарта C99/C++11, то тест не пройдут целых 6 бенчмарков из 9.

Примеры из других программных пакетов

int addsi (int lhs, int rhs) {
    errno = 0;
    if (((( lhs+rhs)^lhs)&(( lhs+rhs)^rhs)) >> (sizeof(int)*CHAR_BIT -1)) {
        error_handler("OVERFLOW ERROR", NULL, EOVERFLOW);
        errno = EINVAL;
    }
    return lhs + rhs;
}

Данный фрагмент кода[4] из пакета IntegerLib проверяет, могут ли быть lhs и rhs сложены без переполнения. И ровно в строчке 3 это переполнение может возникнуть (при сложении lhs+rhs). Это UB, так как lhs и rhs — знакового типа. Кроме этого, в данной библиотеке найдено ещё 19 UB-переполнений.

Также авторы сообщили разработчикам о 13 переполнениях в SQLite, 43 в SafeInt, 6 в GNU MPC library, 30 в PHP, 18 в Firefox, 71 в GCC, 29 в PostgreSQL, 5 в LLVM и 28 в Python. Большинство из ошибок были вскоре исправлены.

Другие примеры

Известный пример целочисленного переполнения происходит в игре Pac-Man, так же, как и в других играх серии: Ms. Pac-Man, Jr. Pac-Man. Также этот глюк появляется в Pac-Man Google Doodle в качестве так называемого «пасхального яйца».[10] Здесь же на уровне 256 можно наблюдать «экран смерти», а сам уровень называют «уровнем разделенного экрана». Энтузиасты дизассемблировали исходный код, пытаясь исправить ошибку модифицированием игры.

Такая же проблема якобы была в игре Sid Meier’s Civilization и известна как Ядерный Ганди[11]. Согласно легенде, на определённом этапе игры с очень миролюбивым Ганди, происходит переполнение через 0 уровня враждебности, результатом чего может стать ядерная война с Ганди. На самом деле, такой миф появился лишь с выходом Civilization V, где параметр его искусственного интеллекта, регулирующий создание и использование ядерного вооружения, имеет наивысшее значение 12, что не противоречило тому, что Ганди является одним из самых миролюбивых лидеров в игре[12].

Ещё одним примером является глюк в SimCity 2000[13]. Здесь дело в том, что бюджет игрока стал очень большим, а после перехода через 231 внезапно стал отрицательным. Игра оканчивается поражением.

Этот глюк из Diablo III. Из-за одного из изменений патча 1.0.8, игровая экономика сломалась. Максимальную сумму для сделок повысили с 1 млн до 10 млн. Стоимость покупки переполнялась через 32-битный тип, а при отмене операции возвращалась полная сумма. То есть игрок оставался с прибылью в 232 игровой валюты[14]

См. также

  • Переполнение буфера
  • Переполнение стека

Примечания

  1. 1,0 1,1 Intel® 64 and IA-32 Architectures Software Developer Manuals | Intel® Software (англ.). software.intel.com. Дата обращения: 22 декабря 2017.
  2. x86 Exploitation 101: “Integer overflow” – adding one more… aaaaaaaaaaand it’s gone (англ.), gb_master’s /dev/null (12 August 2015). Дата обращения 20 декабря 2017.
  3. The Web Application Security Consortium / Integer Overflows. projects.webappsec.org. Дата обращения: 8 декабря 2017.
  4. 4,0 4,1 4,2 4,3 4,4 4,5 W. Dietz, P. Li, J. Regehr, V. Adve. Understanding integer overflow in C/C #x002B; #x002B; // 2012 34th International Conference on Software Engineering (ICSE). — June 2012. — С. 760—770. — doi:10.1109/icse.2012.6227142.
  5. CWE — 2011 CWE/SANS Top 25 Most Dangerous Software Errors (англ.). cwe.mitre.org. Дата обращения: 21 декабря 2017.
  6. ISO/IEC 9899:2011 — Information technology — Programming languages — C (англ.). www.iso.org. Дата обращения: 21 декабря 2017.
  7. 7,0 7,1 7,2 CWE-190: Integer Overflow or Wraparound (3.0) (англ.). cwe.mitre.org. Дата обращения: 12 декабря 2017.
  8. CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer (3.0) (англ.). cwe.mitre.org. Дата обращения: 12 декабря 2017.
  9. CWE-738: CERT C Secure Coding (2008 Version) Section 04 — Integers (INT) (3.0) (англ.). cwe.mitre.org. Дата обращения: 15 декабря 2017.
  10. Map 256 Glitch (англ.), Pac-Man Wiki. Дата обращения 12 декабря 2017.
  11. Nuclear Gandhi, Know Your Meme. Дата обращения 15 декабря 2017.
  12. Артемий Леонов. Почему история о баге с «ядерным Ганди» в Civilization, скорее всего, выдумана. DTF (5 сентября 2019). Дата обращения: 24 октября 2020.
  13. Sim City 2000 Integer Overflow. Blake O’Hare. Дата обращения: 12 декабря 2017.
  14. Diablo III Economy Broken by an Integer Overflow Bug (англ.), minimaxir | Max Woolf’s Blog. Дата обращения 12 декабря 2017.

Переполнение целых знаковых чисел

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

Компьютер не может напрямую работать с бесконечно «длинными» числами — хранить все их цифры. Как бы много оперативной памяти у нас ни было — все же она конечна. Да и хранить, и обрабатывать величины, сопоставимые с числом атомов в видимой части вселенной — безнадежное занятие. Так что ограничения типов int64 или int128 не очень нас-то и ограничивают

Тем не менее при выполнении операций над целыми числами мы все же имеем шанс выпасть за пределы допустимого диапазона (например, [-2^31, 2^31-1] для int32), и тут в игру вступают особенности поддержки целых чисел для того или иного языка программирования, а также, быть может, особенности реализации конкретной платформы.

При выполнении инструкции add (iadd) платформы х86 переполнение целого числа сопровождается выставлением специального флага переполнения, а результирующее значение просто получается отбрасыванием старшего бита результата. И следует ожидать, что по окончании работы условной программы

произойдет перенос разряда в знаковый бит, и переменная x примет отрицательное значение.

В реализации конкретного языка программирования может быть проверка флага переполнения и сообщение об ошибке. А может и не быть. Может быть гарантия «цикличности» значений (после 2^31-1 идет -2^31), а может и не быть.

Проверки и гарантии — это дополнительные инструкции, которые нужно генерировать компилятору, а процессору потом исполнять.

В языке C++ решили не жертвовать производительностью и заставлять компиляторы генерировать код проверки, а объявили переполнение целых знаковых (signed) чисел неопределенным, открывая простор для оптимизаций. Компилятор может генерировать любой код, какой ему вздумается, ориентируясь лишь на одно правило: переполнения не бывает.

Многие программисты свято верят, что переполнение чисел работает, как ожидается, «циклично» — и пишут проверки вида

if (x > 0 && a > 0 && x + a <= 0) {
    // обработай переполнение
}

Но, увы, это неопределенное поведение. И компилятор имеет полное право выкинуть такую проверку.

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

int hash_code(std::string s) {
    int h = 13;
    for (char c : s) {
        h += h * 27752 + c;
    }
    if (h < 0) h += std::numeric_limits<int>::max();
    return h;
}

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

Корректные проверки переполнения куда сложнее и тяжелее.

Так, для C++20, безопасный обобщенный код арифметических операций над целыми знаковыми числами мог бы выглядеть так

#include <concepts>
#include <type_traits>
#include <variant>
#include <limits>

namespace safe {

// Все эти проверки справедливы только для целых знаковых чисел
template <class T>
concept SignedInteger = std::is_signed_v<T>
                     && std::is_integral_v<T>;

enum class ArithmeticError {
    Overflow,
    ZeroDivision
};

template <SignedInteger I>
using ErrorOrInteger = std::variant<I, ArithmeticError>;

template <SignedInteger I>
ErrorOrInteger<I> add(I a,    // выключаем вывод параметра шаблона по
                      std::type_identity_t<I> b) // второму аргументу
{
    if (b > 0 && a > std::numeric_limits<I>::max - b) {
        // положительное переполнение
        return ArithmeticError::Overflow;
    }
    if (b < 0 && a < std::numeric_limits<I>::min - b) {
        // отрицательное переполнение
        return ArithmeticError::Overflow;
    }
    return a + b;
}

template <SignedInteger I>
ErrorOrInteger<I> sub(I a, std::type_identity_t<I> b) {
    if (b < 0 && a > std::numeric_limits<I>::max + b) {
        // положительное переполнение
        return ArithmeticError::Overflow;
    }
    if (b > 0 && a < std::numeric_limits<I>::min + b) {
        // отрицательное переполнение
        return ArithmeticError::Overflow;
    }
    return a - b;
}

template <SignedInteger I>
ErrorOrInteger<I> mul(I a, std::type_identity_t<I> b) {
   if (a == 0 || b == 0) {
       return 0;
   }

   if (a > 0) {
       if (b > 0) {
           if (a > std::numeric_limits<I>::max / b) {
              return ArithmeticError::Overflow;
           }
       } else {
           if (b < std::numeric_limits<I>::min / a) {
              return ArithmeticError::Overflow;
            }
      }
   } else {
      if (b > 0) {
          if (a < std::numeric_limits<I>::min / b) {
              return ArithmeticError::Overflow;
          }
      } else {
          if (b < std::numeric_limits<I>::max / a) {
              return ArithmeticError::Overflow;
          }
      }
   }
   return a * b;
}

template <SignedInteger I>
ErrorOrInteger<I> div(I a, std::type_identity_t<I> b) {
  if (b == 0) {
      return ArithmeticError::ZeroDivision;
  }

  if (a == std::numeric_limits<I>::min && b == -1) {
      // диапазон [min, max] несимметричный относительно 0.
      // abs(min) > max — будет переполнение
      return ArithmeticError::Overflow;
  }
  return a / b;
}


template <SignedInteger I>
ErrorOrInteger<I> mod(I a, std::type_identity_t<I> b) {
  if (b == 0) {
      return ArithmeticError::ZeroDivision;
  }

  if (b == -1) {
      // По стандарту в этом случае также неопределенное поведение при
      // a == std::numeric_limits<I>::min
      // поскольку остаток и неполное частное от деления,
      // например, на платформе x86
      // получаются одной и той же инструкцией div (idiv),
      // что потребует дополнительной обработки.
      //
      // Но совершенно ясно, что остаток от деления чего угодно на -1 равен 0
      return 0;
  }
  return a % b;
}

}

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

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

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

Итак, если вы работаете только лишь с беззнаковыми числами (unsigned), то с неопределенным поведением при переполнении никаких проблем нет — все определено как вычисления по модулю 2^N (N — количество бит для выбранного типа чисел).

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

Для выведения ограничений вам помогут отладочные assert с правильными проверками переполнения, которые нужно написать. Или включение ubsan (undefined behavior sanitizer) при сборке компиляторами clang или gcc.
А также тестовые constexpr вычисления.

Также проблемы неопределенного поведения при переполнении касаются битовых сдвигов влево для отрицательных чисел (или при сдвиге положительного числа с залезанием в знаковый бит). Начиная с C++20, стандарт требует фиксированной единой реализации отрицательных чисел — через дополнительный код (two’s complement), и многие проблемы сдвигов сняты. Тем не менее все равно стоит следовать общей рекомендации: любые битовые операции выполнять только в unsigned типах.

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

    constexpr int x = 12345678;
    constexpr uint8_t first_byte = x; // Implicit cast. Warning

Очень неприятным является переполнение целых, возникающее из-за правил integer promotion:

constexpr std::uint16_t IntegerPromotionUB(std::uint16_t x) {
    x *= x;
    return x;
}

// 65535 * 65535 mod 1<<16 = 1

static_assert(IntegerPromotionUB(65535) == 1); // won't compile

Несмотря на то, что для беззнаковых переполнение определено как взятие остатка по модулю 2^n и мы используем только беззнаковую переменную,
из-за integer promotion в этом примере возникает переполнение знакового! числа и вытекающее из этого UB. Справедливости ради, надо заметить, что такое происходит только на платформах, где размер int больше uint16_t (то есть практически везде в наши дни).

x *= x; // переписывается как x = x * x;
// тип uint16 меньше чем тип int — для * выполняется неявное приведение к int.

Полезные ссылки

  1. https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
  2. https://stackoverflow.com/a/46073296
  3. https://habr.com/ru/post/307702/

Действие по умолчанию зависит от процессора, компилятора и настроек. На MIPS, например, его «классические» компиляторы превращали сложение знаковых в команду add, которая генерирует исключение при переполнении, а беззнаковых — addu, которая не генерирует. Но gcc, clang уже такого не делали, всё через addu. На x86 — родные команды add, sub игнорируют переполнение (точнее, ставят флаг CF или OF, но не генерируют исключение).
Компиляторы современного типа считают, что переполнения в операциях с целыми со знаком не должно быть, иногда из-за этого возникают интересные эффекты — вот самый убойный пример из тех, что я видел. Стандарт тут действует по принципу «мы вам даём возможность писать максимально эффективно, потому что это C, а не учебный язык, а защита от кривостей — ваша проблема». В отличие от них, для целых без знака определено поведение как для арифметики по модулю 2**N, где N — количество битов в значении. Это различие возникло из-за того, что не было извесно в общем случае, какое представление целых со знаком будет из набора: прямой код (sign and magnitude), обратный код (1ʼs complement), дополнительный код (0ʼs complement, но на устоявшемся уже жаргоне twoʼs complement), это сейчас можно смело говорить, что кроме дополнительного кода вариантов нет. Но потом это различие было реально заабьюзено на возможность делать хитрые оптимизации на основании предположения о непереполнении.

Для C++ есть, например, библиотечка (шаблонный заголовочный файл) SafeInt3 от Microsoft, под свободной лицензией; ею можно покрыть все основные операции, хотя она весьма стара, не использует специфику процессоров (даже x86) и оттого во многих случаях неэффективна — там, где достаточно одного OF или CF, или overflow builtins от GCC, она городит много сложных расчётов.

Для C придётся всё писать вручную, заменяя обычные операции на свои эквиваленты функциями или макросами.

Про новые встроенные функции последних gcc и clang (__builtin_add_overflow, __builtin_mul_overflow и вся группа) уже писали. На них можно всегда получить урезанное (оно же wrapped) значение операции (как в 16 битах 30000 + 30000 -> -5536), и признак переполнения, и можно получать каждый из них безопасно (не будет неожиданных оптимизаций). Но и без них можно сделать достаточно неплохо. Например, в случае сложения двух int, проверка вида a > INT_MAX - b, если b > 0, иначе a < INT_MIN - b, достаточна, чтобы проверить разрешимость сложения. Самое тяжёлое тут проверка умножения без поддержки компилятора: единственным всегда работающим вариантом считается проверка делением, а это очень дорого. Я считаю, что overflow builtins надо ввести во все стандарты (кроме нынешнего набора add, mul, div добавить ещё shl).

Теги: Переполнение целых, переполнение целых без знака, int overflow, unsigned overflow.

Переполнение целых чисел

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

Переполнение может привести к серьёзным проблемам: обнулению и потере данных, возможным эксплойтам, трудноуловимым ошибкам, которые будут накапливаться с течением времени.

Рассмотрим несколько приёмов отслеживания переполнения целых со знаком и переполнения целых без знака.

1. Предварительная проверка данных. Мы знаем, из файла limits.h, максимальное и минимальное значение для чисел типа int. Если оба числа положительные,
то их сумма не превысит INT_MAX, если разность INT_MAX и одного из чисел меньше второго числа. Если оба числа отрицательные, то разность INT_MIN и
одного из чисел должна быть больше другого. Если же оба числа имеют разные знаки, то однозначно их сумма не превысит INT_MAX или INT_MIN.

int sum1(int a, int b, int *overflow) {
	int c = 0;
	if (a > 0 && b > 0 && (INT_MAX - b < a) || 
		a < 0 && b < 0 && (INT_MIN - b > a)) {
		*overflow = 1;
	} else {
		*overflow = 0;
		c = a + b;
	}
	return c;
}

В этой функции переменной overflow будет присвоено значение 1, если было переполнение. Функция возвращает сумму, независимо от результата сложения.

2. Второй способ проверки – взять для суммы тип, максимальное (и минимальное) значение которого заведомо больше суммы двух целых. После сложения необходимо проверить, чтобы сумма была не больше , чем INT_MAX и не меньше INT_MIN.

int sum2(int a, int b, int *overflow) {
	signed long long c = (signed long long) a + (signed long long) b;
	if (c < INT_MAX && c > INT_MIN) {
		*overflow = 0;
		c = a + b;
	} else {
		*overflow = 1;
	}
	return (int) c;
}

Обратите внимание на явное приведение типов. Без него сначала произойдёт переполнение, и неправильное число будет записано в переменную c.

3. Третий способ проверки платформозависимый, более того, его реализация будет разной для разных компиляторов. При переполнении целых (обычно) поднимается флаг переполнения в регистре флагов. Можно на ассемблере проверить значение флага сразу же после выполнения суммирования.

int sum3(int a, int b, int *overflow) {
	int noOverflow = 1;
	int c = a + b;
	__asm {
		jno NO_OVERFLOW
		mov noOverflow, 0
	NO_OVERFLOW:
	}
	if (noOverflow) {
		*overflow = 0;
	} else {
		*overflow = 1;
	}
	return c;
}

Здесь переменная noOverflow равна 1, если нет переполнения. jno (jump if no overflow) выполняет переход к метке NO_OVERFLOW, если переполнения не было.
Если же переполнение было, то выполняется

mov noOverflow, 0

По адресу переменной noOverflow записывается нуль.

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

unsigned usumm(unsigned a, unsigned b, int *overflow) {
	unsigned c = a + b;
	if (c < a || c < b) {
		*overflow = 1;
	} else {
		*overflow = 0;
	}
	return c;
}

Вот полный код, с проверками.

#include <conio.h>
#include <stdio.h>
#include <limits.h>

int sum1(int a, int b, int *overflow) {
	int c = 0;
	if (a > 0 && b > 0 && (INT_MAX - b < a) || 
		a < 0 && b < 0 && (INT_MIN - b > a)) {
		*overflow = 1;
	} else {
		*overflow = 0;
		c = a + b;
	}
	return c;
}

int sum2(int a, int b, int *overflow) {
	signed long long c = (signed long long) a + (signed long long) b;
	if (c < INT_MAX && c > INT_MIN) {
		*overflow = 0;
		c = a + b;
	} else {
		*overflow = 1;
	}
	return (int) c;
}

int sum3(int a, int b, int *overflow) {
	int noOverflow = 1;
	int c = a + b;
	__asm {
		jno NO_OVERFLOW
		mov noOverflow, 0
	NO_OVERFLOW:
	}
	if (noOverflow) {
		*overflow = 0;
	} else {
		*overflow = 1;
	}
	return c;
}

unsigned usumm(unsigned a, unsigned b, int *overflow) {
	unsigned c = a + b;
	if (c < a || c < b) {
		*overflow = 1;
	} else {
		*overflow = 0;
	}
	return c;
}

void main() {
	int overflow;
	int sum;
	unsigned usum;
	//sum1
	sum = sum1(3, 5, &overflow);
	printf("%d + %d = %d (%d)n", 3, 5, sum, overflow);
	sum = sum1(INT_MAX, 5, &overflow);
	printf("%d + %d = %d (%d)n", INT_MAX, 5, sum, overflow);
	sum = sum1(INT_MIN, -5, &overflow);
	printf("%d + %d = %d (%d)n", INT_MIN, -5, sum, overflow);
	sum = sum1(INT_MAX, INT_MIN, &overflow);
	printf("%d + %d = %d (%d)n", INT_MAX, INT_MIN, sum, overflow);
	sum = sum1(-10, -20, &overflow);
	printf("%d + %d = %d (%d)n", -10, -20, sum, overflow);
	//sum2
	sum = sum2(3, 5, &overflow);
	printf("%d + %d = %d (%d)n", 3, 5, sum, overflow);
	sum = sum2(INT_MAX, 5, &overflow);
	printf("%d + %d = %d (%d)n", INT_MAX, 5, sum, overflow);
	sum = sum2(INT_MIN, -5, &overflow);
	printf("%d + %d = %d (%d)n", INT_MIN, -5, sum, overflow);
	sum = sum2(INT_MAX, INT_MIN, &overflow);
	printf("%d + %d = %d (%d)n", INT_MAX, INT_MIN, sum, overflow);
	sum = sum2(-10, -20, &overflow);
	printf("%d + %d = %d (%d)n", -10, -20, sum, overflow);
	//sum3
	sum = sum3(3, 5, &overflow);
	printf("%d + %d = %d (%d)n", 3, 5, sum, overflow);
	sum = sum3(INT_MAX, 5, &overflow);
	printf("%d + %d = %d (%d)n", INT_MAX, 5, sum, overflow);
	sum = sum3(INT_MIN, -5, &overflow);
	printf("%d + %d = %d (%d)n", INT_MIN, -5, sum, overflow);
	sum = sum3(INT_MAX, INT_MIN, &overflow);
	printf("%d + %d = %d (%d)n", INT_MAX, INT_MIN, sum, overflow);
	sum = sum3(-10, -20, &overflow);
	printf("%d + %d = %d (%d)n", -10, -20, sum, overflow);
	//usum
	usum = usumm(10u, 20u, &overflow);
	printf("%u + %u = %u (%d)n", 10u, 20u, usum, overflow);
	usum = usumm(UINT_MAX, 20u, &overflow);
	printf("%u + %u = %u (%d)n", UINT_MAX, 20u, usum, overflow);
	usum = usumm(20u, UINT_MAX, &overflow);
	printf("%u + %u = %u (%d)n", 20u, UINT_MAX, usum, overflow);
	getch();
}

Q&A

Всё ещё не понятно? – пиши вопросы на ящик email

Функции с переменным числом параметров

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

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

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

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

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

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

Источник

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

  • 4 бита: максимальное представимое значение 24 — 1 = 15
  • 8 бит: максимальное представимое значение 28 − 1 = 255
  • 16 бит: максимальное представимое значение 216 − 1 = 65,535
  • 32 бита: максимальное представимое значение 232 — 1 = 4 294 967 295 (наиболее распространенная ширина для персональных компьютеров с 2005 г.),
  • 64 бита: максимальное представимое значение 264 — 1 = 18 446 744 073 709 551 615 (наиболее распространенная ширина для персонального компьютера Процессоры, по состоянию на 2017 год),
  • 128 бит: максимальное представимое значение 2128 − 1 = 340,282,366,920,938,463,463,374,607,431,768,211,455

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

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

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

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

Флаги

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

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

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

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

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

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

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

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

Методы решения проблем целочисленного переполнения

Обработка целочисленного переполнения в различных языках программирования

Язык Беззнаковое целое Знаковое целое число
Ада по модулю модуля типа поднимать Constraint_Error
C /C ++ степень двойки по модулю неопределенное поведение
C # по модулю степени 2 в непроверенном контексте; System.OverflowException поднимается в проверяемом контексте[10]
Ява Нет данных степень двойки по модулю
JavaScript все числа с плавающей запятой двойной точности кроме нового BigInt
MATLAB Встроенные целые числа насыщают. Целые числа с фиксированной запятой, настраиваемые для переноса или насыщения
Python 2 Нет данных преобразовать в длинный тип (bigint)
Семя7 Нет данных поднимать OVERFLOW_ERROR[11]
Схема Нет данных преобразовать в bigNum
Simulink настраивается на обертывание или насыщение
Болтовня Нет данных преобразовать в LargeInteger
Быстрый Вызывает ошибку, если не используются специальные операторы переполнения.[12]

Обнаружение

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

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

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

Избегание

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

Умение обращаться

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

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

Явное распространение

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

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

В языках программирования реализованы различные методы защиты от случайного переполнения: Ада, Семя7 (и некоторые варианты функциональных языков) запускают условие исключения при переполнении, а Python (начиная с версии 2.4) легко преобразует внутреннее представление числа в соответствии с его ростом, в конечном итоге представляя его как длинный — чьи возможности ограничены только доступной памятью.[15]

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

Насыщенная арифметика

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

Примеры

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

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

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

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

Ошибки переполнения очевидны в некоторых компьютерных играх. В аркадной игре Осел Конг, невозможно продвинуться дальше 22 уровня из-за целочисленного переполнения по времени / бонусу. Игра берет номер уровня, на котором находится пользователь, умножает его на 10 и добавляет 40. Когда они достигают уровня 22, количество времени / бонуса равно 260, что слишком велико для его 8-битного регистра значений 256, поэтому он сбрасывается. до 0 и дает оставшиеся 4 в качестве времени / бонуса — слишком мало для завершения уровня. В Donkey Kong Jr. Math, при попытке вычислить число больше 10 000 показывает только первые 4 цифры. Перелив — причина знаменитого уровень «разделенный экран» в Pac-Man[27] и «Ядерный Ганди» в Цивилизация.[28] Это также привело к появлению «Дальних земель» в Шахтерское ремесло который существовал с периода разработки Infdev до Beta 1.7.3; однако позже он был исправлен в Beta 1.8, но все еще существует в версиях Pocket Edition и Windows 10 Edition. Шахтерское ремесло.[29] в Супер Нинтендо игра Lamborghini American Challenge, игрок может заставить свою сумму денег упасть ниже 0 долларов во время гонки, будучи оштрафованным сверх лимита оставшихся денег после уплаты сбора за гонку, что приводит к сбоям в работе целого числа и дает игроку на 65 535 000 долларов больше, чем он имел бы после прохождения отрицательный.[30] Аналогичный глюк возникает в S.T.A.L.K.E.R .: Чистое небо где игрок может упасть до отрицательной суммы, быстро путешествуя без достаточных средств, а затем перейдя к событию, где игрока ограбят и у него отберут всю его валюту. После того, как игра попытается забрать деньги игрока на сумму в 0 долларов, игроку предоставляется 2147482963 игровой валюты.[31]

В структуре данных Покемон в играх с покемонами количество полученных очков опыта хранится в виде 3-байтового целого числа. Однако в первом и втором поколениях группа опыта со средней медленной скоростью, которой требуется 1 059 860 очков опыта для достижения 100 уровня, по расчетам имеет -54 очка опыта на уровне 1. Поскольку целое число не имеет знака, значение превращается в 16 777 162. Если покемон набирает менее 54 очков опыта в битве, то покемон мгновенно перескакивает на 100-й уровень. Кроме того, если эти покемоны на уровне 1 помещаются на ПК, и игрок пытается их вывести, игра вылетает. , из-за чего эти покемоны навсегда застревают на ПК. В тех же играх игрок, используя Редкие Конфеты, может повысить уровень своего Покемона выше 100 уровня. Если он достигает уровня 255 и используется другая Редкая Конфета, то уровень переполняется до 0 (из-за того, что уровень кодируется в один байт, например, 6416 соответствует уровню 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 года автомат казино в Курорты мира Казино распечатало призовой билет на 42 949 672,76 долларов в результате ошибки переполнения. Казино отказалось выплатить эту сумму, назвав это неисправностью, используя в свою защиту то, что в автомате четко указано, что максимальная выплата составляет 10 000 долларов, поэтому любой превышающий эту сумму приз должен быть результатом ошибки программирования. В Верховный суд Айовы вынесено решение в пользу казино.[37]

Смотрите также

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

Рекомендации

  1. ^ а б c 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. ^ Билл Вагнер. «Проверено и отключено (Справочник по C #)». msdn.microsoft.com.
  11. ^ Руководство Seed7, раздел 15.2.3 OVERFLOW_ERROR.
  12. ^ Язык программирования Swift. Версия Swift 2.1. 21 октября 2015 года.
  13. ^ Как если бы бесконечно ранжированная целочисленная модель
  14. ^ Мунтян, Пол Иоан; Монперрус, Мартин; Сунь, Хао; Гроссклагс, Йенс; Эккерт, Клаудия (2019). «IntRepair: информированное восстановление целочисленных переполнений». IEEE Transactions по разработке программного обеспечения: 1. arXiv:1807.05092. Дои:10.1109 / TSE.2019.2946148. ISSN  0098-5589.
  15. ^ Документация Python, раздел 5.1 Арифметические преобразования.
  16. ^ «Декларация ТИП«. Common Lisp HyperSpec.
  17. ^ «Декларация ОПТИМИЗИРОВАТЬ«. Common Lisp HyperSpec.
  18. ^ Редди, Абхишек (22 августа 2008 г.). «Особенности Common Lisp».
  19. ^ Пирс, Бенджамин С. (2002). Типы и языки программирования. MIT Press. ISBN  0-262-16209-1.
  20. ^ Райт, Эндрю К .; Маттиас Фелляйзен (1994). «Синтаксический подход к правильности написания». Информация и вычисления. 115 (1): 38–94. Дои:10.1006 / inco.1994.1093.
  21. ^ Макракис, Ставрос (апрель 1982 г.). «Безопасность и мощь». Примечания по разработке программного обеспечения ACM SIGSOFT. 7 (2): 25–26. Дои:10.1145/1005937.1005941.
  22. ^ «Extra, Extra — прочтите все об этом: почти все двоичные поиски и слияния не работают». googleresearch.blogspot.co.uk.
  23. ^ Глейк, Джеймс (1 декабря 1996 г.). «Ошибка и авария». Нью-Йорк Таймс. Получено 17 января 2019.
  24. ^ Официальный отчет об инциденте с неудачным запуском Ariane 5.
  25. ^ Муавад, Джад (30 апреля 2015 г.). «Постановление ФАА о возможной потере мощности в Боинге 787». Нью-Йорк Таймс.
  26. ^ «US-2015-09-07: Электроэнергия — Деактивация». Директивы по летной годности. Европейское агентство авиационной безопасности. 4 мая 2015.
  27. ^ Питтман, Джейми. «Досье Пакмана».
  28. ^ Планкетт, Люк (2016-03-02). «Почему Ганди такой засранец в цивилизации». Котаку. Получено 2018-07-30.
  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. ^ Структура данных покемонов в поколении I
  33. ^ Структура данных покемонов в поколении II
  34. ^ Структура данных покемонов в поколении III
  35. ^ Структура данных покемонов в поколении IV
  36. ^ Lenclud, Кристоф. «Отладка IBM MACRO Assembler версии 1.00».
  37. ^ Кравец, Давид (15 июня 2017 г.). «Извините, мэм, вы не выиграли 43 миллиона долларов — произошла неисправность игрового автомата.«. Ars Technica.

внешняя ссылка

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

Целочи́сленное переполне́ние (англ. integer overflow) — ситуация в компьютерной арифметике, при которой вычисленное в результате операции значение не может быть помещено в n-битный целочисленный тип данных. Различают переполнение через верхнюю границу представления и через нижнюю (англ. Underflow).

Пример: сложение двух переменных размером 8 бит с записью результата в переменную того же размера:

{displaystyle 210_{10}+61_{10}=11010010_{2}+00111101_{2}=?}

{displaystyle {begin{array}{c}{begin{array}{cc}+&{begin{array}{c}11010010_{2}0111101_{2}end{array}}end{array}}hline {begin{array}{cc}&{color {Red}1}00001111_{2}end{array}}end{array}}}

возникает переполнение.

При этом в результат записывается не ожидаемое {displaystyle 271_{10}={color {Red}1}00001111_{2}}, а {displaystyle 15_{10}=00001111_{2}}. Стоит отметить, что вычисление здесь произошло по модулю 2n, а арифметика по модулю циклическая, то есть 255+1=0 (при n = 8). Данная ситуация переполнения фиксируется вычислительной машиной установкой специальных битов регистра флагов Overflow и Carry (пункт 3.4.3.1 Combined Volume: Volume 1[1]). При программировании на языке ассемблера такую ситуацию можно напрямую установить, например, вручную проверив состояние регистра флагов после выполнения операции (пункт 7.3.13.2 Combined Volume: Volume 1[1]).

Содержание

  • 1 Происхождение проблемы
  • 2 Риски для безопасности
  • 3 Эксплуатация и последствия
  • 4 Предотвращение проблемы
  • 5 Примеры из жизни
    • 5.1 Исследование SPECCINT
    • 5.2 Примеры из других программных пакетов
    • 5.3 Другие примеры
  • 6 См. также
  • 7 Примечания

Происхождение проблемы

Битность регистра определяет диапазон данных, представимый в нём. Диапазоны представления для целых типов в бинарных вычислительных машинах:

Битность 8 бит 16 бит 32 бит 64 бит
Беззнаковый Диапазон 0..28−1 0..216−1 0..232−1 0..264−1
Диапазон (десятич.) 0..255 0..65535 0..4294967295 0.. 18446744073709551615
Знаковый Диапазон -27.. 27−1 -215.. 215−1 -231.. 231−1 -263.. 263−1
Диапазон (десятич.) -128..127 -32768..32767 -2147483648.. 2147483647 -9223372036854775808.. 9223372036854775807

Переполнение может возникнуть в исходном коде вследствие ошибки программиста или его недостаточной бдительности к входным данным[2].

  • Несоответствие знакового и беззнакового. Если числа представляются на вычислителе в дополнительном коде, то одному потоку бит соответствуют различные числа. В 32-битной арифметике знаковому −1 соответствует беззнаковое 4294967295 (верхняя граница представления). То есть приведение одного типа к другому может привести к значительной разнице в значении. Этот тип ошибки часто является последствием signedness error ( and), то есть неправильного приведения типов между типами разной знаковости
  • Проблема срезки. Возникает, если число интерпретируется как целое меньшей длины. В таком случае только младшие биты останутся в числе. Старшие отбросятся, что приведет к изменению численного значения
  • Знаковое расширение. Стоит помнить, что при приведении знакового числа к типу большей длины происходит копирование старшего бита, что в случае интерпретации как беззнаковое приведет к получению очень большого числа[3]

Риски для безопасности

Возможность переполнения широко используется программистами, например, для хеширования и криптографии, генерирования случайных чисел и нахождения границ представления типа[4]. В то же время, например, по стандарту языков C и C++, беззнаковые вычисления выполняются по модулю 2, в то время как знаковое переполнение является классическим примером[5] неопределённого поведения[6].

Такой вид некорректности в коде ведёт к следующим последствиям[4]:

  1. Компиляция может пойти неожиданным образом. Из-за наличия неопределённого поведения в программе, оптимизации компилятора могут изменить поведение программы.
  2. Бомба замедленного действия. На текущей версии ОС, компилятора, опций компиляции, структурной организации программы и т. д. всё может работать, а при любом изменении, например, появлении более агрессивных оптимизаций, сломаться.
  3. Иллюзия предсказуемости. Конкретная конфигурация компилятора может иметь вполне определённое поведение, например компиляторы языков C и C++ обычно реализуют операции по модулю 2n и для знаковых типов (только интерпретированных в дополнительном коде), если отключены агрессивные оптимизации. Однако, надеяться на такое поведение нельзя, иначе есть риск эффекта «бомбы замедленного действия»
  4. Образование диалектов. Некоторые компиляторы предоставляют дополнительные опции для того, чтобы доопределить неопределённое поведение. Например, и GCC, и Clang поддерживают опцию -fwrapv, обеспечивающую выше описанное (в пункте 3) поведение.

Изменение стандарта может привести к новым проблемам с переполнением. К примеру, 1<<31 было зависимым от реализации в стандартах ANSI C и C++98, в то время как стали неопределённым в C99 and C11 (для 32-битных целых).[4]

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

Эксплуатация и последствия

Основные последствия для безопасности[7]:

  • Для доступности. Возможный отказ системы (окно для DoS-атак)
  • Для целостности. Неавторизированный доступ к данным
  • Для конфиденциальности. Исполнение стороннего кода, обход защитного механизма

Классически переполнение может быть эксплуатировано через переполнение буфера.

img_t table_ptr; /*struct containing img data, 10kB each*/
int num_imgs;
...
num_imgs = get_num_imgs();
table_ptr = (img_t*)malloc(sizeof(img_t)*num_imgs);
...

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

Другая уязвимость в том, что если num_imgs ещё больше, это приведёт к переполнению аргумента malloc. Тогда выделится лишь небольшой буфер. При записи в него произойдёт переполнение буфера, последствиями чего могут стать: перехват контроля над исполнением, исполнение кода злоумышленника, доступ к важной информации.[8]

Предотвращение проблемы

Защита от подобного поведения должна проводиться на нескольких уровнях[7]:

  1. Планирования и требований к программе:
    • Убедитесь, что все протоколы взаимодействия между компонентами строго определены. В том числе, что все вычисления вне границ представления будут обнаружены. И требуйте строгого соответствия этим протоколам
    • Используйте язык программирования и компилятор, которые не позволяет этой уязвимости воплотиться, либо позволяют легче её обнаружить, либо выполняют авто-проверку границ. Инструменты, которые предоставляются компилятором, включают санитайзеры (например, Address Sanitizer или Undefined Behavior Sanitizer) .
  2. Архитектуры программы:
    • Используйте проверенные библиотеки или фреймворки, помогающие проводить вычисления без риска непредсказуемых последствий. Примеры включают такие библиотеки, как SafeInt (C++) или IntegerLib (C or C++).
    • Любые проверки безопасности на стороне клиента должны быть продублированы на стороне сервера, чтобы не допустить CWE-602. Злоумышленник может миновать проверку на стороне клиента, изменив сами значения непосредственно после прохождения проверки или модифицируя клиента, чтобы полностью убрать проверки.
  3. Реализации:
    • Проводите валидацию любых поступивших извне числовых данных, проверяя что они находятся внутри ожидаемого диапазона. Проверяйте обязательно как минимальный порог, так и максимальный. Используйте беззнаковые числа, где это возможно. Это упростит проверки на переполнение.
    • Исследуйте все необходимые нюансы языка программирования, связанные с численными вычислениями (CWE-681). Как они представляются, какие различия между знаковыми и беззнаковыми, 32-битными и 64-битными, проблемы при кастовании (обрезка, знаково-беззнаковое приведения типов — выше) и как обрабатываются числа, слишком маленькие или, наоборот, большие для их машинного представления. Также убедитесь, что используемый вами тип (например, int или long) покрывают необходимый диапазон представления
    • Подробно изучите полученные от компилятора предупреждения и устраните возможные проблемы безопасности, такие как несоответствия знаковости операндов при операциях с памятью или использование неинициализированных переменных. Даже если уязвимость совсем небольшая, это может привести к опасности для всей системы.

Другие правила, позволяющие избежать этих уязвимостей, опубликованы в стандарте CERT C Secure Coding Standard в 2008 году, включают[9]:

  • Не пишите и не используйте функции обработки строкового ввода, если они обрабатывают не все случаи
  • Не используйте битовые операции над знаковыми типами
  • Вычисляйте выражения на типе большего размера перед сравнением или присваиванием в меньший
  • Будьте внимательны перед приведением типа между числом и указателем
  • Убедитесь, что вычисления по модулю или результаты деления не приводят к последующему делению на ноль
  • Используйте intmax_t или uintmax_t для форматированного ввода-вывода пользовательских числовых типов

Примеры из жизни

Исследование SPECCINT

В статье[4] в качестве предмета исследования программ на языках C и C++ на целочисленное переполнение подробно исследуется один из самых широко применимых и известных тестовых пакетов SPEC, используемый для измерений производительности. Состоит он из фрагментов наиболее распространённых задач, как то: тестов вычислительной математики, компиляции, работы с базами данных, диском, сетью и прочее.

Результаты анализа SPECCINT2000 показывают наличие 219 статических источников переполнения в 8 из 12 бенчмарков, из которых 148 использовали беззнаковое переполнение и 71 — знаковое (снова неопределённое поведение). В то же время, беззнаковое переполнение тоже не всегда намеренное и может являться ошибкой и источником уязвимости (например, Listing 2 той же статьи[4]).

Также был проведён тест на «бомбы замедленного действия» в SPECCINT2006. Его идеей является в каждом месте неопределённого поведения вернуть случайное число и посмотреть, к каким последствиям это может привести. Если оценивать неопределённое поведение с точки зрения стандарта C99/C++11, то тест не пройдут целых 6 бенчмарков из 9.

Примеры из других программных пакетов

1 int  addsi (int lhs , int  rhs) {
2     errno = 0;
3     if (((( lhs+rhs)^lhs)&(( lhs+rhs)^rhs))
4     >> (sizeof(int)*CHAR_BIT -1)) {
5         error_handler("OVERFLOW  ERROR", NULL , EOVERFLOW);
6         errno = EINVAL;
7     }
8     return  lhs+rhs;
9 }

Данный фрагмент кода[4] из пакета IntegerLib проверяет, могут ли быть lhs и rhs сложены без переполнения. И ровно в строчке 3 это переполнение может возникнуть (при сложении lhs+rhs). Это UB, так как lhs и rhs — знакового типа. Кроме этого, в данной библиотеке найдено ещё 19 UB-переполнений.

Также авторы сообщили разработчикам о 13 переполнениях в SQLite, 43 в SafeInt, 6 в GNU MPC library, 30 в PHP, 18 в Firefox, 71 в GCC, 29 в PostgreSQL, 5 в LLVM и 28 в Python. Большинство из ошибок были вскоре исправлены.

Другие примеры

Известный пример целочисленного переполнения происходит в игре Pac-Man, так же, как и в других играх серии: Ms. Pac-Man, Jr. Pac-Man. Также этот глюк появляется в Pac-Man Google Doodle в качестве так называемого «пасхального яйца».[10] Здесь же на уровне 256 можно наблюдать «экран смерти», а сам уровень называют «уровнем разделенного экрана». Энтузиасты дизассемблировали исходный код, пытаясь исправить ошибку модифицированием игры.

Такая же проблема появляется в игре Civilization 4 и известна как Nuclear Gandhi[11]. Дело в том, что после заключения партнёрских соглашений с очень миролюбивым Ганди, происходит переполнение через 0 уровня враждебности, результатом чего может стать ядерная война с Ганди.

Ещё одним примером является глюк в SimCity 2000[12]. Здесь дело в том, что бюджет игрока стал очень большим, а после перехода через 231 внезапно стал отрицательным. Игра оканчивается поражением.

Этот глюк из Diablo III. Из-за одного из изменений патча 1.0.8, игровая экономика сломалась. Максимальную сумму для сделок повысили с 1 млн до 10 млн. Стоимость покупки переполнялась через 32-битный тип, а при отмене операции возвращалась полная сумма. То есть игрок оставался с прибылью в 232 игровой валюты[13]

См. также

  • Переполнение буфера
  • Переполнение стека

Примечания

  1. 1 2 Intel® 64 and IA-32 Architectures Software Developer Manuals | Intel® Software (англ.). software.intel.com. Проверено 22 декабря 2017.
  2. x86 Exploitation 101: “Integer overflow” – adding one more… aaaaaaaaaaand it’s gone (англ.), gb_master’s /dev/null (12 августа 2015). Проверено 20 декабря 2017.
  3. The Web Application Security Consortium / Integer Overflows. projects.webappsec.org. Проверено 8 декабря 2017.
  4. 1 2 3 4 5 6 W. Dietz, P. Li, J. Regehr, V. Adve. Understanding integer overflow in C/C #x002B; #x002B; // 2012 34th International Conference on Software Engineering (ICSE). — June 2012. — С. 760–770. — DOI:10.1109/icse.2012.6227142.
  5. CWE — 2011 CWE/SANS Top 25 Most Dangerous Software Errors (англ.). cwe.mitre.org. Проверено 21 декабря 2017.
  6. ISO/IEC 9899:2011 — Information technology — Programming languages — C (англ.). www.iso.org. Проверено 21 декабря 2017.
  7. 1 2 3 CWE-190: Integer Overflow or Wraparound (3.0) (англ.). cwe.mitre.org. Проверено 12 декабря 2017.
  8. CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer (3.0) (англ.). cwe.mitre.org. Проверено 12 декабря 2017.
  9. CWE-738: CERT C Secure Coding (2008 Version) Section 04 — Integers (INT) (3.0) (англ.). cwe.mitre.org. Проверено 15 декабря 2017.
  10. Map 256 Glitch (англ.), Pac-Man Wiki. Проверено 12 декабря 2017.
  11. Nuclear Gandhi, Know Your Meme. Проверено 15 декабря 2017.
  12. Sim City 2000 Integer Overflow. Blake O’Hare. Проверено 12 декабря 2017.
  13. Diablo III Economy Broken by an Integer Overflow Bug (англ.), minimaxir | Max Woolf’s Blog. Проверено 12 декабря 2017.

  • Ошибка n 1426 ошибка ole код 0x80040154 class not registered
  • Ошибка n 1426 ошибка ole код 0x80004005 unspecified error
  • Ошибка n 1104 ошибка чтения файла парус
  • Ошибка n 006 триколор gs gamekit
  • Ошибка mysql unknown mysql server host