SlideShare une entreprise Scribd logo
1  sur  3
Télécharger pour lire hors ligne
Урок 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;
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.

    ...
}

Результатом манипуляций указателями с использованием %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.

Contenu connexe

En vedette

Loovus reaalainetes
Loovus reaalainetesLoovus reaalainetes
Loovus reaalainetes
TKHK
 
Trabajo a entregar de historia
Trabajo a entregar de historiaTrabajo a entregar de historia
Trabajo a entregar de historia
KARICLAU
 
Kelmser poetryanthology
Kelmser poetryanthologyKelmser poetryanthology
Kelmser poetryanthology
jkmarie
 
Project Delta Communication Package - Dec 7 Final
Project Delta Communication Package  - Dec 7 FinalProject Delta Communication Package  - Dec 7 Final
Project Delta Communication Package - Dec 7 Final
David Donohue
 
Millennialmedia Year in Review - 2012
Millennialmedia Year in Review - 2012Millennialmedia Year in Review - 2012
Millennialmedia Year in Review - 2012
Can Bakir
 
Ignite For Ian Leslie
Ignite For Ian LeslieIgnite For Ian Leslie
Ignite For Ian Leslie
il4818leslie
 

En vedette (19)

Loovus reaalainetes
Loovus reaalainetesLoovus reaalainetes
Loovus reaalainetes
 
Neil Gains and Happy Anggraini Festival of NewMR 2016
Neil Gains and Happy Anggraini   Festival of NewMR 2016Neil Gains and Happy Anggraini   Festival of NewMR 2016
Neil Gains and Happy Anggraini Festival of NewMR 2016
 
Booming Beijing
Booming BeijingBooming Beijing
Booming Beijing
 
Iblc Congres 2009 Presentatie Paul Bessems
Iblc Congres 2009 Presentatie  Paul  BessemsIblc Congres 2009 Presentatie  Paul  Bessems
Iblc Congres 2009 Presentatie Paul Bessems
 
Project idea savyuk
Project idea savyukProject idea savyuk
Project idea savyuk
 
Trabajo a entregar de historia
Trabajo a entregar de historiaTrabajo a entregar de historia
Trabajo a entregar de historia
 
Kelmser poetryanthology
Kelmser poetryanthologyKelmser poetryanthology
Kelmser poetryanthology
 
Project Delta Communication Package - Dec 7 Final
Project Delta Communication Package  - Dec 7 FinalProject Delta Communication Package  - Dec 7 Final
Project Delta Communication Package - Dec 7 Final
 
Slide share social media introduction by oliver de leeuw and salmaan (for dow...
Slide share social media introduction by oliver de leeuw and salmaan (for dow...Slide share social media introduction by oliver de leeuw and salmaan (for dow...
Slide share social media introduction by oliver de leeuw and salmaan (for dow...
 
bbnn
bbnnbbnn
bbnn
 
10 3 мalta_2014_25_03_2014
10 3 мalta_2014_25_03_201410 3 мalta_2014_25_03_2014
10 3 мalta_2014_25_03_2014
 
Asyse nuestros servicios
Asyse nuestros serviciosAsyse nuestros servicios
Asyse nuestros servicios
 
Social media marketing for small business
Social media marketing for small businessSocial media marketing for small business
Social media marketing for small business
 
Resume - Alejandro Mercado
Resume - Alejandro MercadoResume - Alejandro Mercado
Resume - Alejandro Mercado
 
Millennialmedia Year in Review - 2012
Millennialmedia Year in Review - 2012Millennialmedia Year in Review - 2012
Millennialmedia Year in Review - 2012
 
Home energy efficiency 101
Home energy efficiency 101Home energy efficiency 101
Home energy efficiency 101
 
Customer Loyalty Dps
Customer Loyalty DpsCustomer Loyalty Dps
Customer Loyalty Dps
 
Hilltopfarms
Hilltopfarms  Hilltopfarms
Hilltopfarms
 
Ignite For Ian Leslie
Ignite For Ian LeslieIgnite For Ian Leslie
Ignite For Ian Leslie
 

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

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

Безопасность 64-битного кода
Безопасность 64-битного кодаБезопасность 64-битного кода
Безопасность 64-битного кода
 
Урок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметикаУрок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметика
 
Статический анализ кода для верификации 64-битных приложений
Статический анализ кода для верификации 64-битных приложенийСтатический анализ кода для верификации 64-битных приложений
Статический анализ кода для верификации 64-битных приложений
 
Что такое size_t и ptrdiff_t
Что такое size_t и ptrdiff_tЧто такое size_t и ptrdiff_t
Что такое size_t и ptrdiff_t
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложений
 
20 ловушек переноса Си++ - кода на 64-битную платформу
20 ловушек переноса Си++ - кода на 64-битную платформу20 ловушек переноса Си++ - кода на 64-битную платформу
20 ловушек переноса Си++ - кода на 64-битную платформу
 
Правила статического анализа кода для диагностики потенциально опасных констр...
Правила статического анализа кода для диагностики потенциально опасных констр...Правила статического анализа кода для диагностики потенциально опасных констр...
Правила статического анализа кода для диагностики потенциально опасных констр...
 
32 подводных камня OpenMP при программировании на Си++
32 подводных камня OpenMP при программировании на Си++32 подводных камня OpenMP при программировании на Си++
32 подводных камня OpenMP при программировании на Си++
 
Урок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данныхУрок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данных
 
Поиск уязвимостей в программах с помощью анализаторов кода
Поиск уязвимостей в программах с помощью анализаторов кодаПоиск уязвимостей в программах с помощью анализаторов кода
Поиск уязвимостей в программах с помощью анализаторов кода
 
Что такое "Parallel Lint"?
Что такое "Parallel Lint"?Что такое "Parallel Lint"?
Что такое "Parallel Lint"?
 
Отладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программОтладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программ
 
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
 
Статический анализ исходного кода на примере WinMerge
Статический анализ исходного кода на примере WinMergeСтатический анализ исходного кода на примере WinMerge
Статический анализ исходного кода на примере WinMerge
 
Разница в подходах анализа кода компилятором и выделенным инструментом
Разница в подходах анализа кода компилятором и выделенным инструментомРазница в подходах анализа кода компилятором и выделенным инструментом
Разница в подходах анализа кода компилятором и выделенным инструментом
 
Багдатов Методы автоматического выявления плагиата в текстах компьютерных про...
Багдатов Методы автоматического выявления плагиата в текстах компьютерных про...Багдатов Методы автоматического выявления плагиата в текстах компьютерных про...
Багдатов Методы автоматического выявления плагиата в текстах компьютерных про...
 
Урок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложенияУрок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложения
 
Разработка статического анализатора кода для обнаружения ошибок переноса прог...
Разработка статического анализатора кода для обнаружения ошибок переноса прог...Разработка статического анализатора кода для обнаружения ошибок переноса прог...
Разработка статического анализатора кода для обнаружения ошибок переноса прог...
 
Урок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметикаУрок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметика
 
VivaMP, система выявления ошибок в коде параллельных программ на языке С++, и...
VivaMP, система выявления ошибок в коде параллельных программ на языке С++, и...VivaMP, система выявления ошибок в коде параллельных программ на языке С++, и...
VivaMP, система выявления ошибок в коде параллельных программ на языке С++, и...
 

Plus de Tatyanazaxarova

Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Tatyanazaxarova
 

Plus de Tatyanazaxarova (20)

Урок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окруженияУрок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окружения
 
Урок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программУрок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программ
 
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокУрок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
 
Урок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиУрок 24. Фантомные ошибки
Урок 24. Фантомные ошибки
 
Урок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структурУрок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структур
 
Урок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. ИсключенияУрок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. Исключения
 
Урок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен даннымиУрок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен данными
 
Урок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединенияхУрок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединениях
 
Урок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвигаУрок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвига
 
Урок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибокУрок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибок
 
Урок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибокУрок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибок
 
Урок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном кодеУрок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном коде
 
Урок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурацииУрок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурации
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кода
 
PVS-Studio
PVS-Studio PVS-Studio
PVS-Studio
 
PVS-Studio научился следить за тем, как вы программируете
PVS-Studio научился следить за тем, как вы программируетеPVS-Studio научился следить за тем, как вы программируете
PVS-Studio научился следить за тем, как вы программируете
 
Пояснения к статье про Copy-Paste
Пояснения к статье про Copy-PasteПояснения к статье про Copy-Paste
Пояснения к статье про Copy-Paste
 
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
 
Статический анализ и ROI
Статический анализ и ROIСтатический анализ и ROI
Статический анализ и ROI
 
Вечный вопрос измерения времени
Вечный вопрос измерения времениВечный вопрос измерения времени
Вечный вопрос измерения времени
 

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

  • 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. 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. } Результатом манипуляций указателями с использованием %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.