В конце 2013 года вышла довольно интересная статья "Towards Optimization-Safe Systems: Analyzing the Impact of Undefined Behavior" про то как компиляторы, применяя различные агрессивные оптимизации убирают проверки безопасности. Хочу поделиться своими мыслями на этот счёт.
Во-первых часть той статьи я перевёл на русский (остаток переводить лень, но если кому-то нужно готов продолжить). Команда, написавшая эту статью весьма интересная - у них есть и более ранние работы, посвящённые неопределённому поведению и ошибкам, к которым оно приводит. Очень советую почитать, вот пара названий их статей: "Linux kernel vulnerabilities:
State-of-the-art defenses and open problems", "Undefined Behavior: What Happened to My Code?", по ссылкам там можно и массу других любопытных статей найти.
Если кому-то лень читать статью целиком, то в двух словах суть сводится к следующему: если Вы пишете код, который приводит в UB (undefined behaviour), то готовьтесь к неприятным последствиям. Например:
Во-первых часть той статьи я перевёл на русский (остаток переводить лень, но если кому-то нужно готов продолжить). Команда, написавшая эту статью весьма интересная - у них есть и более ранние работы, посвящённые неопределённому поведению и ошибкам, к которым оно приводит. Очень советую почитать, вот пара названий их статей: "Linux kernel vulnerabilities:
State-of-the-art defenses and open problems", "Undefined Behavior: What Happened to My Code?", по ссылкам там можно и массу других любопытных статей найти.
Если кому-то лень читать статью целиком, то в двух словах суть сводится к следующему: если Вы пишете код, который приводит в UB (undefined behaviour), то готовьтесь к неприятным последствиям. Например:
char *buf = ...;
char *buf_end = ...;
unsigned int len = ...;
if (buf + len >= buf_end)
return;
/* len too large */
if (buf + len < buf)
return;
Здесь вторая проверка будет удалена, т.к. компилятор уверен, что buf + len не может быть меньше buf, ведь в противном случае было переполнение, приводящее к UB, а программист умный и ну никак не мог привести свою программу в такое состояние.
Понятно, что таким образом написана гигантская часть кода и что большинство людей даже не подозревает о таком поведении компилятора. Очень забавно было читать истерику одного программиста, который столкнулся с таким поведением.
Как компиляторщик, который сам разрабатывает подобные оптимизации могу сказать, что
Формально, конечно, правы компиляторщики. И более того, разработчики компилятора обычно делают warning'и, которые предупреждают об опасности. Более того в gcc-4.9 появился специальный санитайзер:
-fsanitize=undefined
, отлавливающий потенциально опасные конструкции. Да, понятно, что все опасные случаи, которыми воспользуется компилятор отловить невозможно, но к сожалению, не все компилят даже с ключом -Wall, про -Werror даже говорить не приходится, поэтому программисты в любом случае попадают в истории.Мне как-то высказывали мнение, что в "нормальных языках" такая ситуация невозможна в принципе. Я посмотрел в стандарт Haskell - в соответствии с ним компилятор имеет полное право убрать вторую проверку из нашего примера, хотя на практике мне этого добиться не удалось. Думаю, компилятор до этого ещё не дорос ;) Я также посмотрел в стандарт Erlang, но там вообще ничего про переполнение не сказано и хотел посмотреть в стандарт OCaml, но как бы это сказать... Нет у OCaml стандарта! Да, они в качестве стандарта используют книгу по OCaml, но понятно, что нельзя сделать что-либо серьёзное по документу который обновляют раз в несколько месяцев.
Лично мне кажется, что такие оптимизации делать нужно в любом случае, ведь никогда не знаешь когда 2% ускорения превратятся в 20% из-за наложения эффекта нескольких оптимизаций. Вопрос безопасности... Ну для начала пусть программисты перестанут игнорировать предупреждения компилятора, а там уже о чём-то рассуждать можно будет. Если нужна сверх надёжность, либо -O0, либо качественный код и качественное тестирование. К сожалению, в российских гос. шарагах хорошие программисты - редкость и там проблемы возникают не из-за коварного компилятора, а из-за банального говнокода.
Комментариев нет:
Отправить комментарий
Примечание. Отправлять комментарии могут только участники этого блога.