The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
Корректная проверка на целочисленное переполнение, !*! dimus, 17-Фев-06, 13:15  [смотреть все]
В последнее время стало появляться много сообщений об обнаружении в разных программах ошибок, связанных с целочисленным переполнением.
Допустим у нас есть код, где одна переменная время от времени увеличивается на некоторое заранее неизвестное значение. Например так:

unsigned int counter;

void accounting( unsigned int delta )
{
   counter = counter + delta;
}

В определенный момент может быть достигнуто такое состояние, когда после прибавления очередной дельты у нас будет переполнение. Я придумал такой путь решения проблемы:
void accounting2( unsigned int delta )
{
   if( counter < (counter + delta) )
   {
      counter = counter + delta;
   }
   else
   {
      printf("Overflow detected\n");
   }
}

Однако этот способ аппаратно зависимый и не лишен недостатков: он не будет работать, если при переполнении не происходит циклического перехода в регистре. (т.е. допустим у нас есть восьмиразрядный регистр А, содержащий число 0xFE. Если добавить к нему 0x1, то мы получим 0xFF, а если добавить 0x3, то мы получим переполнение, и в регистре у нас будет 0x1. По крайней мере это характерно для платформы ИНТЕЛ)

Вопрос: как правильно отслеживать факт целочисленного переполнения?

  • Корректная проверка на целочисленное переполнение, !*! СергейК, 15:32 , 17-Фев-06 (1)
    Для signed int подходит следующее

    #define SAMESIGN(a,b)   (((a) < 0) == ((b) < 0))
    void accounting2( int delta )
    {
       int counter1 = counter + delta
       if (SAMESIGN(counter, delta) && !SAMESIGN(counter, counter1))
       {
          fprintf(stderr,"Overflow detected\n");
       }
       return counter1;
    }

  • Корректная проверка на целочисленное переполнение, !*! sas, 11:44 , 18-Фев-06 (2)
    >В последнее время стало появляться много сообщений об обнаружении в разных программах
    >ошибок, связанных с целочисленным переполнением.
    >Допустим у нас есть код, где одна переменная время от времени увеличивается
    >на некоторое заранее неизвестное значение. Например так:
    >
    >unsigned int counter;
    >
    >void accounting( unsigned int delta )
    >{
    >   counter = counter + delta;
    >}
    >
    >В определенный момент может быть достигнуто такое состояние, когда после прибавления очередной
    >дельты у нас будет переполнение. Я придумал такой путь решения проблемы:
    >
    >void accounting2( unsigned int delta )
    >{
    >   if( counter < (counter + delta) )
    >   {
    >      counter = counter + delta;
    >   }
    >   else
    >   {
    >      printf("Overflow detected\n");
    >   }
    >}
    >
    >Однако этот способ аппаратно зависимый и не лишен недостатков: он не будет
    >работать, если при переполнении не происходит циклического перехода в регистре. (т.е.
    >допустим у нас есть восьмиразрядный регистр А, содержащий число 0xFE. Если
    >добавить к нему 0x1, то мы получим 0xFF, а если добавить
    >0x3, то мы получим переполнение, и в регистре у нас будет
    >0x1. По крайней мере это характерно для платформы ИНТЕЛ)
    >
    >Вопрос: как правильно отслеживать факт целочисленного переполнения?

    if ( counter > ~delta )
       fprintf( stderr, "Overflow!!!\n" );

    • Корректная проверка на целочисленное переполнение, !*! sas, 11:47 , 18-Фев-06 (3)
      >>В последнее время стало появляться много сообщений об обнаружении в разных программах
      >>ошибок, связанных с целочисленным переполнением.
      >>Допустим у нас есть код, где одна переменная время от времени увеличивается
      >>на некоторое заранее неизвестное значение. Например так:
      >>
      >>unsigned int counter;
      >>
      >>void accounting( unsigned int delta )
      >>{
      >>   counter = counter + delta;
      >>}
      >>
      >>В определенный момент может быть достигнуто такое состояние, когда после прибавления очередной
      >>дельты у нас будет переполнение. Я придумал такой путь решения проблемы:
      >>
      >>void accounting2( unsigned int delta )
      >>{
      >>   if( counter < (counter + delta) )
      >>   {
      >>      counter = counter + delta;
      >>   }
      >>   else
      >>   {
      >>      printf("Overflow detected\n");
      >>   }
      >>}
      >>
      >>Однако этот способ аппаратно зависимый и не лишен недостатков: он не будет
      >>работать, если при переполнении не происходит циклического перехода в регистре. (т.е.
      >>допустим у нас есть восьмиразрядный регистр А, содержащий число 0xFE. Если
      >>добавить к нему 0x1, то мы получим 0xFF, а если добавить
      >>0x3, то мы получим переполнение, и в регистре у нас будет
      >>0x1. По крайней мере это характерно для платформы ИНТЕЛ)
      >>
      >>Вопрос: как правильно отслеживать факт целочисленного переполнения?
      >
      if ( counter > ~delta ) fprintf( stderr, "Overflow!!!\n" );
      • Корректная проверка на целочисленное переполнение, !*! dimus, 08:21 , 21-Фев-06 (4)
        >if ( counter > ~delta ) fprintf( stderr, "Overflow!!!\n" );

        Интересно и Красиво!
        Большое вам спасибо. И этот метод вроде как должен переноситься на любые архитектуры.

        Интересно, а почему не сделали набор таких функций и не включили в стандартную библиотеку - вещь то очень нужная. Что-то типа этого:
        int   safe_add_uint32( uint32_t val1, uint32_t val2, uint32_t* result );

        • Корректная проверка на целочисленное переполнение, !*! dimus, 15:07 , 22-Фев-06 (5)
          >Интересно, а почему не сделали набор таких функций и не включили в
          >стандартную библиотеку - вещь то очень нужная. Что-то типа этого:
          >int   safe_add_uint32( uint32_t val1, uint32_t val2, uint32_t* result );

          Я решил сделать себе ряд таких функций. Для uint32_t и uint64_t все заработало прекрасно, и я ободренный этим, решил сделать также функции для uint8_t и uint16_t. Каково же было мое удивление и недоумение, когда эти функции незаработали!
          Расследование выявило, что компилятор (gcc (GCC) 3.3.4) как-то странно рожает код для оператора if: вместо того, чтобы использовать cmpb или cmpw (для uint16_t), он использовал cmpl, и в результате функция не работает. Помогло приведение типов. Вот рабочий код:

          //-------------------------------------------------------------------
          // Безопасное сложение двух чисел с контролем переполнения
          // val1 - первое число
          // val2 - второе число
          // res - указатель на переменную, в которую будет записан
          // результат. В случае, если было зафиксированно переполнение,
          // эта переменная останется в неизменном виде.
          // Возвращаемое значение: 1 в случае успеха, 0 при переполнении
          int     safe_add_uint8( uint8_t val1, uint8_t val2, uint8_t* res )
          {
                  int     result  = 0;

                  if( (uint8_t)val1 <= (uint8_t)~val2 )
                  {
                          *res = val1 + val2;
                          result = 1;
                  }

                  return  result;
          }
          //-------------------------------------------------------------------




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2025 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру