Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Урок 10. Паттерн 2. Функции с переменным количеством аргументов

Классическими примерами, приводимыми во многих статьях по проблемам переноса программ на 64-битные системы, является некорректное использование функций printf, scanf и их разновидностей.

  • Be the first to comment

  • Be the first to like this

Урок 10. Паттерн 2. Функции с переменным количеством аргументов

  1. 1. Урок 10. Паттерн 2. Функции спеременным количеством аргументовКлассическими примерами, приводимыми во многих статьях по проблемам переноса программна 64-битные системы, является некорректное использование функций printf, scanf и ихразновидностей.Пример 1:const char *invalidFormat = "%u";size_t value = SIZE_MAX;printf(invalidFormat, value);Пример 2:char buf[9];sprintf(buf, "%p", pointer);В первом случае не учитывается, что тип size_t не эквивалентен типу unsigned на 64-битнойплатформе. Это приведет к выводу на печать некорректного результата, в случае если value >UINT_MAX.Во втором случае автор кода не учел, что размер указателя в будущем может составить более 32бит. В результате на 64-битной архитектуре данный код приведет к переполнению буфера.Некорректное использование функций с перемененным количеством параметров являетсяраспространенной ошибкой на всех архитектурах, а не только 64-битных. Это связано спринципиальной опасностью использования данных конструкций языка Си++. Общепринятойпрактикой является отказ от них и использование безопасных методик программирования. Мынастоятельно рекомендуем модифицировать код и использовать безопасные методы. Например,можно заменить printf на cout, а sprintf на boost::format или std::stringstream.Данную рекомендацию часто критикуют разработчики под Linux, аргументируя тем, что gccпроверяет соответствие строки форматирования фактическим параметрам, передаваемым вфункцию printf. Однако они забывают, что строка форматирования может передаваться из другойчасти программы, загружаться из ресурсов. Другими словами, в реальной программе строкаформатирования редко присутствует в явном виде в коде, и, соответственно, компилятор неможет ее проверить. Если же разработчик использует Visual Studio 2005/2008, то он не сможетполучить предупреждение на код вида "void *p = 0; printf("%x", p);" даже используя ключи /W4 и/Wall.Для работы с memsize-типами в функциях вида sscanf, printf имеются спецификаторы размера.Если вы разрабатываете Windows-приложение, то вы можете использовать спецификатор размера"I". Пример использования:size_t s = 1;
  2. 2. printf("%Iu", s);Если вы разрабатываете приложение под Linux, то вам будет доступен спецификатор размера "z".Пример использования:size_t s = 1;printf("%zu", s);Спецификаторы хорошо описаны в статье Wikipedia "printf".Если вы вынуждены поддерживать переносимый код, использующий функции типа sscanf, то вформате управляющих строк можно использовать специальные макросы, раскрывающиеся внеобходимые спецификаторы размера. Пример макроса, помогающего создавать переносимыйкод для разных систем:// PR_SIZET on Win64 = "I"// PR_SIZET on Win32 = ""// PR_SIZET on Linux64 = "z"// ...size_t u;scanf("%" PR_SIZET "u", &u);Рассмотрим еще один пример. Хотя этот пример выглядит наиболее странно, код, которыйприведен здесь в упрощенном виде, использовался в реальном приложении в подсистемеUNDO/REDO:// Здесь указатели сохранялись в виде строкиint *p1, *p2;....char str[128];sprintf(str, "%X %X", p1, p2);// А в другой функции данная строка// обрабатывалась следующим образом:void foo(char *str){ int *p1, *p2; sscanf(str, "%X %X", &p1, &p2); // Результат - некорректное значение указателей p1 и p2. ...
  3. 3. }Результатом манипуляций указателями с использованием %X стало некорректное поведениепрограммы на 64-битной системе. Данный пример показывает, как опасны потаенные дебрибольших и сложных проектов, которые пишутся многими годами. Если проект достаточно велик истар, то в нем можно встретить очень интересные фрагменты, подобные этому.ДиагностикаОпасность для функций с переменным количеством аргументов, представляют типы, меняющиесвой размер на 64-битной системе, то есть memsize типы. Статический анализатор PVS-Studioпредупреждает об использовании таких типов диагностическим сообщением V111.Если типы аргументов не изменили своей разрядности, то код считается корректным, ипредупреждающих сообщений выдано не будет. Пример корректного кода с точки зренияанализатора:printf("%d", 10*5);CString str;size_t n = sizeof(float);str.Format(StrFormat, static_cast<int>(n));Авторы курса: Андрей Карпов (karpov@viva64.com), Евгений Рыжков (evg@viva64.com).Правообладателем курса "Уроки разработки 64-битных приложений на языке Си/Си++"является ООО "Системы программной верификации". Компания занимается разработкойпрограммного обеспечения в области анализа исходного кода программ. Сайт компании:http://www.viva64.com.Контактная информация: e-mail: support@viva64.com, 300027, г. Тула, а/я 1800.

    Be the first to comment

    Login to see the comments

Классическими примерами, приводимыми во многих статьях по проблемам переноса программ на 64-битные системы, является некорректное использование функций printf, scanf и их разновидностей.

Views

Total views

379

On Slideshare

0

From embeds

0

Number of embeds

1

Actions

Downloads

2

Shares

0

Comments

0

Likes

0

×