пятница, июля 13, 2007

Безопасность в С++

C++: A Cautionary Tale, or, 1 Hour Of Your Black Hat Trip is Spoken For - Томас Пташек рассказывает почему язык С++ небезопасен. Критикует следующие моменты.

Исключения. Есть такая точка зрения, что исключения есть зло. По этому поводу еще как-то Джоэл Спольски высказывался. Пташек рассказывает о следующем: после выброса исключения останавливается выполнение всех функций по цепочке до места выброса исключения. И в этих функциях могут остаться невалидные уже указатели.

delete. В С++ есть выражение delete и есть delete[]. И их очень легко перепутать. У меня есть старый пост про работу delete'ов Что делает выражение вида delete p. Пташек дает ссылку на Attacking delete and delete [] in C++, где гораздо подробнее рассказывается о работе delete'ов, со схемами использования ошибок программистов для всяких злобных дел.

STL. Итераторы, например, вектора становятся невалидными после изменения этого вектора.

Это не все, у Пташека написано больше и подробнее. Все эти проблемы решаются, все знают как их решать. Чтобы не было неприятностей с исключениями есть RAII, потом нужно вызывать правильный вариант delete и быть повнимательнее с итераторами... Но люди, они ошибаются.

Цитата из поста Пташека:
"Я - специалист по безопасности, которому платят, чтобы проискивать исходники самых крупных и известных C++ продуктов и, проблема в том, что я продолжаю находить ошибки. Просто знать как надо делать недостаточно."

15 комментариев:

  1. Все это немного притянуто за уши. Можно очень сильно сократить негатив от этих моментов. Достаточно пользоваться простыми правилами (мы используем подобные в наших проектах):

    1. все операции с памятью - через умные указатели (std::auto_ptr, boost::shared_ptr, boost::scoped_ptr, scoped_array, std::vector, Loki::SmartPtr). тогда про delete вспоминать и не придется. а если не нашелся подходящий умный указатель - напиши его и локализуй в нем все эти delete.

    2. все использование ресурсов - через RAII (в частности, для простых случаев очень подходит Loki::ScopeGuard)

    ОтветитьУдалить
  2. В целом пост Пташека можно резюмировать как "C++ позволяет вам выстрелить себе в ногу". Пташек перечисляет 3 достаточно известные потенциальные ошибки, но - ничего нового по сути. SNR поста очень низкий.

    А то что "люди ошибаются" - ну так люди всегда ошибаются, вне зависимости от того, насколько idiot-proof язык/инструмент им дать.

    ОтветитьУдалить
  3. В целом пост Пташека можно резюмировать как "C++ позволяет вам выстрелить себе в ногу"

    Хех, ну себе-то еще ничего. Но тут объясняется, что другие могут использовать эти ошибки с выгодой для себя.

    ОтветитьУдалить
  4. Анонимный13/7/07 20:46

    Вопрос не не в том, похож ли C++ на опасную бритву без ручки, вопрос в том, почему им продолжают пользоваться. Для любителей безопасной езды есть ява, есть си-шарп.

    ОтветитьУдалить
  5. Но тут объясняется, что другие могут использовать эти ошибки с выгодой для себя.

    :) Это справедливо для любой более-менее серъёзной ошибки.


    Кстати, такое впечатление, что пост is kind of rant. Или самореклама (см. point 1) :)

    Вообще, начиная с "the notion that C++ is a more secure language than C is a myth" всё уже плохо пахнет. :)

    ОтветитьУдалить
  6. Вопрос не не в том, похож ли C++ на опасную бритву без ручки, вопрос в том, почему им продолжают пользоваться. Для любителей безопасной езды есть ява, есть си-шарп.
    Они исключают только один пункт - управление памятью.
    В остальном(управление ресурсами, те же итераторы и т.д.) они ничем не лучше.

    И ни один язык не выпрямит кривые руки.

    ОтветитьУдалить
  7. Они исключают только один пункт - управление памятью.
    Это на первый взгляд такая мелочь :)
    Реально основной плюс -- это размещение всех объектов на хипе (boxed values) и отсутствие низкоуровневых указателей (=>нормальная безопасная система типов), а к этому уже как логичное дополнение -- сборка мусора.

    Вроде бы всего ничего, а уже сразу можно и замыкания в язык добавить, и хвостовую рекурсию оптимизировать, а оттуда и до, не побоюсь этого слова, функциональщины всякой недалеко ;)

    ОтветитьУдалить
  8. Насчет же "кривых рук" -- это разумеется.

    Но если исходить из того что "плохие" программисты все же присутствуют в команде, то у них остается меньше возможностей делать трудновылавливаемые баги, и это замечательно.

    ОтветитьУдалить
  9. Реально основной плюс -- это размещение всех объектов на хипе (boxed values) и отсутствие низкоуровневых указателей (=>нормальная безопасная система типов), а к этому уже как логичное дополнение -- сборка мусора.

    Ну не знаю, не знаю. Кому это "реально основной" плюс, кому - нет. Кому это "нормальная" система типов, кому - нет(см. D&E про эту "нормальную" систему типов).

    ISO/IEC 14883:2009 будет поддерживать GC как опциональную возможность языка. Точнее говоря, она будет обязательной, но ею можно будет не пользоваться(так же, как исключениями, например) и не получать падения производительности просто из-за факта, что эта возможность есть в языке(опять же, см. D&E про zero-overhead principle). Лично я, даже после этого нововведения в язык, использовать GC-MM не буду. По мне, эта технология - излишество, причём очень дорогое: возможностей RAII вполне хватает для полноценного контроля ситуации.

    ОтветитьУдалить
  10. Анонимный16/7/07 09:24

    По поводу exceptions - Джоэль забыл добавить один чрезвычайно важный факт. Код с exceptions получается хуже (и по памяти, и по быстродействию) на десятки процентов, а то и в разы. По-крайней мере, это верно для GCC - посмотрите в результирующем ассемблере, как компилятор строит function frame. А теперь, перекомпилируйте с -fno-exceptions и посмотрите ещё раз...

    Так что, как бы не был красив, логичен и лаконичен код без exceptions - в сад. По крайней мере, до тех пор, пока их кто-нибудь нормально не имплементирует.

    ОтветитьУдалить
  11. Вообще то я про D&E - Design & Evolution, Страуструп.

    ОтветитьУдалить
  12. 2archimed7592
    ISO/IEC 14883:2009 будет поддерживать GC как опциональную возможность языка.
    ...
    По мне, эта технология - излишество, причём очень дорогое: возможностей RAII вполне хватает для полноценного контроля ситуации.


    Автоматическая сборка мусора решает две проблемы из перечисленных Пташеком. Причем без участия программиста, что исключает возможность ошибиться. Я никак не могу назвать ее излишеством.

    2rsx11
    Так что, как бы не был красив, логичен и лаконичен код без exceptions - в сад. По крайней мере, до тех пор, пока их кто-нибудь нормально не имплементирует.

    Эээ... Возможно, имелся в виду код c исключениями? А то фраза теряет смысл.

    ОтветитьУдалить
  13. Ну не знаю, не знаю. Кому это "реально основной" плюс, кому - нет. Кому это "нормальная" система типов, кому - нет.
    Ну я той точки зрения, что это все помогает сделать язык "более высокоуровневым", а систему типов более выразительной и стройной.

    Когда нужно написать супербыстрый низкоуровневый код, это все может мешать, да.

    Предлагаемая в C++09 сборка мусора, согласен -- во многом как пятое колесо выглядит. Чтоб было органично -- нужно ее сделать обязательной, выкинуть поинтеры и выкинуть RAII (и получится C# :).

    Про C++, GC и хип я чуть подробнее тут и тут мысль развернул, если интересно.

    ОтветитьУдалить
  14. Анонимный16/7/07 15:26

    Так что, как бы не был красив, логичен и лаконичен код без exceptions - в сад. По крайней мере, до тех пор, пока их кто-нибудь нормально не имплементирует.

    Эээ... Возможно, имелся в виду код c исключениями? А то фраза теряет смысл.


    Да, конечнo, имeнно с исключениями, sorry.

    ОтветитьУдалить
  15. Анонимный22/7/07 16:44

    archimed7592
    Лично я, даже после этого нововведения в язык, использовать GC-MM не буду. По мне, эта технология - излишество, причём очень дорогое: возможностей RAII вполне хватает для полноценного контроля ситуации.
    Правильно :-) RAII позволяет контролировать ресурсы вообще, а не только лишь память. Все эти джавы со своими GC идут лесом, как только дело доходит до контроля за ресурсами, ибо написание exception-safe кода без RAII превращается в сущую муку (не говоря уже о том, чтобы потом этот код читать и сопровождать).

    ОтветитьУдалить