Корректная проверка на целочисленное переполнение, 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; } //-------------------------------------------------------------------
|