The words you are searching are inside this book. To get more targeted content, please make full-text search by clicking here.
Discover the best professional documents and content resources in AnyFlip Document Base.
Search
Published by , 2017-02-23 10:15:38

Secure_Coding

Secure_Coding

5.4. Целочисленные операции 1 253

В любом случае первое слагаемое переносится в 32-битный регистр еах, а затем выпол­
няется сложение со вторым слагаемым.

Сложение 64-битных значений типа s igned long long и uns igned long long требует
на х86-32 двух отдельных команд суммирования.

01 sll = slll + sll2;
0 2 mov еах , dwo rd p t r [ s l l l ]
0 3 add еах , dword ptr [ s ll 2 ]
0 4 mov есх , dword ptr [ еЬр - 8 ]
0 5 adc есх , dwo rd p t r [ ebp- 1 8h ]
06 ull = ulll + ull2 ;
0 7 mov еах , dword ptr ( u l l l ]
0 8 add еах , dword p t r [ u l l 2 ]
0 9 mov е сх , dword p t r [ ebp - 2 8 h ]
1 0 adc есх, dword ptr [ ebp- 3 8 h ]

Команда add выполняет суммирование младших 32 битов. Если при этом выполнении

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

манда adc суммирует старшие 32 бита с учетом значения бита переноса, что дает коррек-

тную 64-битную сумму. .

Избежа1П1е или обнаружеlПlе знакового переполнения при суммировании. Знаковое

целочисленное переполнение является в языке программирования С неопределенным по­

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

распространенное поведение) , так и сгенерировать прерывание, присвоить результату на­

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

рые сочтет необходимыми данная реализация.

Проверка постусловия с помощью флагов состояния. На уровне ассемблера х86-32

знаковое переполнение может быть обнаружено с помощью команды j о (переход при пе­

реполнении) или j no (переход при отсутствии переполнения) после выполнения команды

add ( 32-битный случай) или adc (64-битный случай) .

Это позволяет создать библиотеку арифметических функций, которые проверяют со­

стояние флага переполнения и возвращают код состояния, указывающий, произошло

ли переполнение. Приведенная далее функция выполняет суммирование значений типа

signed int в такой библиотеке.

0 1 _Bool add_int ( i nt lhs , int rh s , int * sum ) {
02 asm {
03 mov еах , dword ptr [ lhs ]
0 4 add еах , dword p t r [ rhs ]
0 5 mov есх , dword p t r [ sum ]
О б mov dword pt r [ есх ] , еах
07 jo short j l
0 8 mov a l , 1 / / 1 в случае успеха
0 9 j mp short j 2
10 j l :
1 1 xor a l , a l / / О при неудаче
12 j2 :
13 } ;
14

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

1254 Целочисленная безопасность

ассемблера в программу на С, специфичных для компилятора (в данном случае - ком ­
пилятора Microsoft). Во-вторых, этот код использует набор команд х86-32, а следователь­
но, непереносим. В-третьих, этот подход имеет невысокую производительность, посколь­
ку компиляторы не оптимизируют ассемблерный код. Наконец, в-четвертых, этот подход
трудно использовать, поскольку он не позволяет применять стандартную встроенную
арифметику. Например, код

1 int а = /* */;

2 int ь /* */;

3

4 i n t sum = а + ь + 3 ;

должен быть реализован следующим образом:

1 int а = /* */;

2 int Ь / * */;

3

4 i f ( add_i n t ( a , Ь , & surn ) & & add_i n t ( surn, 3 , & s um ) ) {

5 / * Все в порядке * /

6

7 else {

8 / * Переполнение * /

9

Проверка предусловий) формат допшmеlПIЯ до двойки. Другой подход к устранению
ошибок, связанных с целыми числами, состоит в проверке значений операндов перед опе­
рацией для предотвращения переполнения. Эта проверка особенно важна для переполне­
ния знаковых целых чисел, которое является неопределенным поведением и может при­
вести к прерыванию в некоторых архитектурах (например, ошибка деления на платформе
х86-32). Сложность этих тестов очень разная.

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

01 s i gned int s i l , s i 2 , surn ;

02

0 3 / * Инициализация s i l и s i 2 * /

04

05 uns igned int usum = (unsigned int ) s i l + s i 2 ;

06

07 if { {usum s i l ) & ( u sum s i 2 ) & INT_MIN )
л л

0 8 / * Обработка оuмбки * /

09 else {

1 0 sum = s i l + s i 2 ;

11

исключающее или можно рассматривать как оператор «не равно" для каждого отдельно-
го бита. Мы сосредоточиваемся только на позиции знакового бита, так что используем
маску INT_MIN, в которой установлен только знаковый бит.


Click to View FlipBook Version