19 смертных грехов, угрожающих безопасности программ. Майкл Ховард
Чтение книги онлайн.

Читать онлайн книгу 19 смертных грехов, угрожающих безопасности программ - Майкл Ховард страница 19

СКАЧАТЬ что пытается сказать компилятор, вы хотя бы задумаетесь, есть ли в вашем коде реальная проблема. К сожалению, возможности компилятора ограничены. Если бы в предыдущем примере вы избавились от ошибки, объявив a, b и с как целые со знаком, то появилась бы возможность переполнения, а компилятор ничего не сказал бы.

      Еще одна приятная особенность С# состоит в том, что он по мере необходимости пользуется 64–разрядными целыми числами. Например, следующий код дал бы неверный результат на С, но правильно работает на С#:

      int i = -1;

      uint j = 0xffffffff; // наибольшее положительное 32-разрядное целое

      if(i == j)

      Console.WriteLine("Отлично!");

      Причина в том, что С# приведет операнды к типу long (64–разрядное целое со знаком), который позволяет точно сохранить оба числа. Если вы решите пойти дальше и проделать то же самое с числами типа long и ulong (в С# оба занимают 64 разряда), то компилятор сообщит, что необходимо явно преобразовать их к одному типу. По мнению авторов, стандарт C/C++ следует уточнить: если компилятор поддерживает операции над 64–разрядными значениями, то он должен в этом отношении вести себя так же, как С#.

      Ключевые слова checked и unchecked

      В языке С# есть ключевые слова checked и unchecked. Можно объявить checked–блок:

      byte a = 1;

      byte b = 255;

      checked

      {

      byte c = (byte)(a + b);

      byte d = Convert.ToByte(a + b);

      Console.Write("{0} {1}\n", b+1, c);

      }

      В данном примере приведение а + b от int к byte возбуждает исключение. В следующей строке, где вызывается Convert.ToByte, исключение возникло бы и без ключевого слова checked, но его наличие приводит к возбуждению исключения еще и при вычислении аргументов метода Console.Write(). Поскольку иногда переполнение целого допускается намеренно, то имеется также ключевое слово unchecked, отключающее контроль на переполнение.

      Слова checked и unchecked можно также использовать для включения или отключения контроля в одном выражении:

      checked (с = (byte) (Ь + а));

      И наконец, включить контроль можно с помощью флага /checked компилятора. Если этот флаг присутствует, то нужно явно помечать словом unchecked участки кода или отдельные предложения, в которых переполнение допустимо.

      Греховность Visual Basic и Visual Basic .NET

      Visual Basic регулярно претерпевает кардинальные модификации, а переход от Visual Basic 6.0 к Visual Basic .NET стал самым значительным шагом со времен введения объектной ориентированности в Visual Basic 3.0. Одно из самых фундаментальных изменений связано с целочисленными типами (см. табл. 3.1).

      Вообще говоря, и Visual Basic 6.0, и Visual Basic .NET не подвержены угрозе исполнения произвольного кода из–за переполнения целых чисел. В Visual Basic 6.0 генерируется ошибка, если при выполнении какого–либо оператора или функции преобразования, например CInt(), возникает переполнение. В Visual Basic .NET в этом случае возбуждается исключение типа System.OverflowException. Как показано в табл. 3.1, программа на Visual Basic .NET имеет доступ ко всем целочисленным типам, определенным в каркасе .NET Framework.

      Таблица 3.1. Целочисленные типы, поддерживаемые Visual Basic 6.0 и Visual Basic .NET

      Хотя операции в самом языке Visual Basic, может быть, и неуязвимы для переполнения целого, но СКАЧАТЬ