Pull to refresh

Неопределенное поведение и реляционные СУБД: открытые лекции в ноябре

Reading time 1 min
Views 715
Образовательные проекты JetBrains corporate blog C++ *SQL *Studying in IT

Computer Science Center приглашает на открытые лекции в ноябре. Опытные разработчики расскажут, как устроены реляционные СУБД и какие выгоды даёт неопределенное поведение языкам программирования. 

Обе лекции можно посмотреть онлайн. Расписание и подробное описание внутри.

Читать далее
Total votes 4: ↑4 and ↓0 +4
Comments 0

Неопределённое поведение и теорема Ферма

Reading time 4 min
Views 51K
Programming *C++ *Compilers *
В соответствии со стандартами C и C++, если выполнение программы приводит к переполнению знаковой целой переменной, или к любому из сотен других «неопределённых действий» (undefined behaviour, UB), то результат выполнения программы может быть любым: она может запостить на Твиттер непристойности, может отформатировать вам диск…
Увы, в действительности «пасхальные яйца», которые бы заставляли программу в случае UB делать что-то из ряда вон выходящее, не встречались со времён GCC 1.17 — та запускала nethack, когда встречала в коде программы неизвестные #pragma. Обычно же результат UB намного скучнее: компилятор просто оптимизирует код для тех случаев, когда UB не происходит, не придавая ни малейшего значения тому, что этот код будет делать в случае UB — ведь стандарт разрешает сделать в этом случае что угодно!
В качестве иллюстрации того, как изобилие UB в стандарте позволяет компилятору выполнять неочевидные оптимизации, Реймонд Чен приводит такой пример кода:

int table[4];
bool exists_in_table(int v)
{
    for (int i = 0; i <= 4; i++) {
        if (table[i] == v) return true;
    }
    return false;
}

В условии цикла мы ошиблись на единицу, поставив <= вместо <. В итоге exists_in_table() либо должна вернуть true на одной из первых четырёх итераций, либо она прочтёт table[4], что является UB, и в этом случае exists_in_table() может сделать всё что угодно — в том числе, вернуть true! В полном соответствии со стандартом, компилятор может соптимизировать код exists_in_table() до
int table[4];
bool exists_in_table(int v)
{
    return true;
}

Такие оптимизации иногда застают программистов врасплох.
Читать дальше →
Total votes 107: ↑104 and ↓3 +101
Comments 129

Ещё раз о неопределённом поведении или «почему не стоит забивать гвозди бензопилой»

Reading time 8 min
Views 37K
Programming *Compilers *C *
Про неопределённое поведение писали не раз. Приводились цитаты из стандартов, объяснения их интерпретации, разного рода поучительные примеры, но, похоже, все люди, пытавшиеся об этом писать пропускали важный пункт: по-моему никто внятно так и не удосужился объяснить — откуда это понятие в языке, собственно, появилось, и, главное, кому оно адресовано.

Хотя на самом-то деле, если вспомнить историю Си, всё достаточно очевидно и, главное, логично. А все жалобы людей, «обжёгшихся» на неопределённом поведении для людей не забывших что такое Си и зачем он вообще существует звучат примерно как: «я тут гвозди бензопилой забивал… забивал и забивал, всё было хорошо, а потом я дёрнул за ручку и у неё коготки как забегают, задёргаются, мне руку оттяпало и полноги… ну кто так строит?».

Люди, которые знают что такое бензопила пытаются, конечно, объяснить, что за если за эту рукоятку дёрнуть, то так, в общем-то, и должно быть, но люди, считающие, что у них у руках такой себе молоток говорят «мимо» них, и, в результате, все остаются при своих.

Так какой же важный секрет люди упускают из виду?
Total votes 83: ↑76 and ↓7 +69
Comments 206

Разыменовывание нулевого указателя приводит к неопределённому поведению

Reading time 6 min
Views 51K
PVS-Studio corporate blog C++ *C *
Silent NULL (Разыменовывание нулевого указателя приводит к неопределённому поведению)
Ненароком я породил большую дискуссию, касающуюся того, допустимо ли использовать в Си/Си++ выражение &P->m_foo, если P является нулевым указателем. Программисты разделились на два лагеря. Одни уверенно доказывали, что так писать нельзя, другие столь же уверенно утверждали, что можно. Приводились различные аргументы и ссылки. И я понял, что нужно внести окончательную ясность в этот вопрос. Для этого я обратился к экспертам Microsoft MVP и разработчикам Visual C++, общающимся через закрытый список рассылки. Они помогли подготовить эту статью, и я представляю её всем желающим. Для нетерпеливых: этот код не корректен.
Читать дальше →
Total votes 91: ↑88 and ↓3 +85
Comments 193

Откуда берутся бреши в безопасности программ?

Reading time 6 min
Views 39K
Фонд ReactOS corporate blog Information Security *C++ *C *Reverse engineering *
Tutorial
Translation
                                             — У нас дыра в безопасности.
                                             — Ну, хоть что-то у нас в безопасности.
                                                                                  Анекдот

image Если вы Windows-пользователь, то вам должны быть знакомы всплывающие каждый второй вторник месяца окошки, рапортующие об установке «критических обновлений безопасности». Microsoft прилагает немалые усилия, постоянно работая над исправлениями уязвимостей в своих операционных системах, но оно того стоит: в мире, где число кибератак день ото дня только возрастает, ни одна лазейка в обороне наших компьютеров не должна оставаться открытой для потенциальных злоумышленников.

Недавнее обсуждение в списке рассылки, посвящённого 66192-й SVN ревизии ReactOS, показало как это легко — внести в код ядра критическую уязвимость. Я буду использовать этот случай как пример простой, но влияющей на безопасность ошибки, а также для наглядного представления некоторых мер, которым необходимо подвергать код ядра, если вы действительно хотите получить безопасную систему.

Отыщем уязвимость

Читать дальше →
Total votes 91: ↑79 and ↓12 +67
Comments 9

По следам C++ Siberia: дракон в мешке

Reading time 7 min
Views 23K
C++ *System Programming *Compilers *
Конференции бывают разные. Некоторые собирают огромные толпы зрителей, другие могут быть интересны лишь полутора специалистам.

Забавно другое: часто бывает, что зал собирает большое количество слушателей, которым любопытна тема, они задают вопросы и впоследствии с энтузиазмом рассказывают о пережитом коллегам. В то же время, запись оного мероприятия собирает несоизмеримо меньше просмотров, чем котики на ютубе. Предполагаю, что видео банально теряются на просторах видеохостингов и не могут найти зрителей. Сей досадный факт обязательно надо исправлять!

На самом деле, пост не о том.

Так уж вышло, что мне довелось выступать на означенной конференции, где я на пальцах и с приплясываниями рассказывал, что такое LLVM, чем интересна нотация SSA, что такое IR код и, наконец, как так получается, что детерменированные на первый взгляд C++ программы, оказывается, провоцируют неопределенное поведение.

Кстати, этот доклад можно поставить пятым номером в серии статей про виртуальную машину Smalltalk. Многие просили подробнее рассказать о LLVM. В общем, убиваем всех зайцев сразу. Заинтересовавшимся, предлагаю «откинуться на спинку кресла», опционально налить чего-нибудь интересного и послушать. Обещаю, что больше часа времени я не отниму.

Ах да, под катом можно найти пояснения тех моментов, которым не было уделено должное внимание на конференции. Я постарался ответить на часто задаваемые вопросы и детально разобрать листинги LLVM IR. В принципе, текстовую часть статьи можно читать как самостоятельное произведение, тем не мене я рассчитывал на то, что читатель обратится к нему уже после просмотра видео.


Читать дальше →
Total votes 23: ↑22 and ↓1 +21
Comments 10

Undefined behavior ближе, чем вы думаете

Reading time 5 min
Views 30K
PVS-Studio corporate blog C++ *C *
Ад ближе чем кажетсяМногие считают, что неопределённое поведение программы возникает из-за грубых ошибок (например, запись за границы массива) или на неадекватных конструкциях (например, i = i++ + ++i). Поэтому для многих является неожиданностью, когда неопределенное поведение вдруг проявляет себя во вполне привычном и ничем не настораживающем коде. Рассмотрим один из таких примеров. Программируя на C/C++ никогда нельзя терять бдительность. Ад ближе чем кажется.

Читать дальше →
Total votes 50: ↑46 and ↓4 +42
Comments 51

Чего из Rust мне не хватает в C

Reading time 7 min
Views 22K
Programming *C *Rust *
Translation
Об авторе. Федерико Мена-Кинтеро — мексиканский программист, один из основателей проекта GNOME.

Librsvg достиг переломного момента: внезапно выясняется, что легче портировать некоторые основные части из C на Rust, чем просто добавить аксессоры. Кроме того, всё больше «мяса» библиотеки сейчас написано на Rust.

Сейчас мне приходится часто переключаться между двумя языками, и C теперь выглядит очень, очень примитивным.

Элегия C


Я влюбился в C около 24 лет назад. Выучил азы по второму изданию “The C Programming Language by K&R” в переводе на испанский. До этого я использовал достаточно низкоуровневый Turbo Pascal, с указателями и ручным распределением памяти, так что C казался приятным и придающим сил.

K&R — отличная книга для выработки стиля и лаконичности. Эта маленькая книжка даже научит вас реализовать простой malloc()/free(), что поистине просветляет. Даже низкоуровневые конструкции можно вставлять в самом языке!

В последующие годы я хорошо освоил C. Это небольшой язык с маленькой стандартной библиотекой. Вероятно, идеальный язык для реализации ядра Unix на 20 000 строк кода или около того.
Читать дальше →
Total votes 80: ↑76 and ↓4 +72
Comments 179

Как обезопасить C

Reading time 4 min
Views 9.7K
System Programming *C *Development for Linux *
Translation


Язык C очень мощный и много где используется — особенно в ядре Linux — но при этом очень опасный. Один из разработчиков ядра Linux рассказал, как справиться с уязвимостями безопасности С.

Вы можете сделать практически любую вещь на С, но это не значит, что её нужно делать. Код C очень быстр, но несётся без ремней безопасности. Даже если вы эксперт, как большинство разработчиков ядра Linux, всё равно возможны убийственные ошибки.

Кроме подводных камней типа псевдонимов указателей, у языка C фундаментальные неисправленные ошибки, которые ждут своих жертв. Именно эти уязвимости Кейс Кук, инженер по безопасности ядра Google Linux, рассмотрел на конференции по безопасности Linux в Ванкувере.
Читать дальше →
Total votes 37: ↑23 and ↓14 +9
Comments 19

Почему перенос при целочисленном переполнении — не очень хорошая идея

Reading time 11 min
Views 12K
PVS-Studio corporate blog C++ *C *
Translation
Эта статья посвящена неопределённому поведению и оптимизациям компилятора, особенно в контексте знакового целочисленного переполнения.

Примечание от переводчика: в русском языке нет четкого соответствия в употребляемом контексте слова «wrap»/«wrapping». Существует математический термин "перенос", который близок к описываемому явлению, а термин "флаг переноса" (carry flag) — механизм выставления флага в процессорах при целочисленном переполнении. Другим вариантом перевода может быть фраза «вращение/переворот/оборот вокруг нуля». Она лучше отображает смысл «wrap» по сравнению с «перенос», т.к. показывает переход чисел при переполнении из положительного в отрицательный диапазон. Однако, как оказалось, эти слова смотрятся в тексте непривычно для тестовых читателей. Для упрощения в дальнейшем примем в качестве перевода термина «wrap» слово «перенос».

Компиляторы языка C (и C++) в своей работе всё чаще руководствуются понятием неопределённого поведения — представлением о том, что поведение программы при некоторых операциях не регламентировано стандартом и что, генерируя объектный код, компилятор вправе исходить из предположения, что программа таких операций не производит. Немало программистов возражало против такого подхода, поскольку сгенерированный код в этом случае может вести себя не так, как задумывал автор программы. Эта проблема становится всё острее, так как компиляторы применяют всё более хитроумные методы оптимизации, которые наверняка будут опираться на понятие неопределённого поведения.
Читать дальше →
Total votes 30: ↑29 and ↓1 +28
Comments 24

C++: сеанс спонтанной археологии и почему не стоит использовать вариативные функции в стиле C

Reading time 18 min
Views 20K
Programming *C++ *Compilers *C *
Tutorial
Sandbox
Началось все, как водится, с ошибки. Я первый раз работал с Java Native Interface и делал в C++ части обертку над функцией, создающей Java объект. Эта функция — CallVoidMethod — вариативна, т.е. помимо указателя на среду JNI, указателя на тип создаваемого объекта и идентификатора вызываемого метода (в данном случае конструктора), она принимает произвольное число других аргументов. Что логично, т.к. эти другие аргументы передаются вызываемому методу на стороне Java, а методы могут быть разные, с разным числом аргументов любых типов.

Соответственно и свою обертку я тоже сделал вариативной. Для передачи произвольного числа аргументов в CallVoidMethod использовал va_list, потому что по-другому в данном случае никак. Да, так и отправил va_list в CallVoidMethod. И уронил JVM банальным segmentation fault.

За 2 часа я успел перепробовать несколько версий JVM, от 8-ой до 11-ой, потому что: во-первых это мой первый опыт с JVM, и в этом вопросе я StackOverflow доверял больше, чем себе, а во-вторых кто-то на StackOverflow посоветовал в таком случае использовать не OpenJDK, а OracleJDK, и не 8, а 10. И лишь потом я наконец заметил, что помимо вариативной CallVoidMethod есть CallVoidMethodV, которая произвольное число аргументов принимает через va_list.

Что мне больше всего не понравилось в этой истории, так это то, что я не сразу заметил разницу между эллипсисом (многоточием) и va_list. А заметив, не смог объяснить себе, в чем принципиальное отличие. Значит, надо разобраться и с эллипсисом, и с va_list, и (поскольку речь все-таки о C++) с вариативными шаблонами.
Читать дальше →
Total votes 28: ↑27 and ↓1 +26
Comments 11

Неопределённое поведение и правда не определено

Reading time 12 min
Views 19K
PVS-Studio corporate blog C++ *C *
Translation
Термином «неопределённое поведение» в языке C и C++ обозначают ситуацию, в которой буквально «чего только не бывает». Исторически, к неопределённому поведению относили случаи, когда прежние компиляторы для C (и архитектуры на нём) вели себя несовместимым образом, и комитет по разработке стандарта, в своей безграничной мудрости, решил ничего не решать по этому поводу (т.е. не отдавать предпочтение какой-то одной из конкурирующих реализаций). Неопределённым поведением также называли возможные ситуации, в которых стандарт, обычно столь исчерпывающий, не предписывал никакого конкретного поведения. У этого термина есть и третье значение, которое в наше время становится всё более актуальным: неопределённое поведение — это возможности для оптимизации. А разработчики на C и C++ обожают оптимизации; они настойчиво требуют, чтобы компиляторы прикладывали все усилия для ускорения работы кода.

Данная статья была впервые опубликована на сайте Cryptography Services. Перевод публикуется с разрешения автора Томаса Порнина (Thomas Pornin).
Читать дальше →
Total votes 90: ↑87 and ↓3 +84
Comments 60

Исследование одного неопределённого поведения

Reading time 18 min
Views 6.5K
C++ *
В статье исследуются возможные проявления неопределённого поведения, возникающего в c++ при завершении не-void функции без вызова return с подходящим значением. Статья носит больше научно-развлекательный характер, чем практический.

Кому не нравится весело скакать по граблям — проходим мимо, не задерживаемся.
Читать дальше →
Total votes 37: ↑33 and ↓4 +29
Comments 5

Анализатор кода не прав, да здравствует анализатор

Reading time 6 min
Views 5.6K
PVS-Studio corporate blog Programming *C++ *
Foo(std::move(buffer), line_buffer - buffer.get());

Совмещать много действий в одном выражении языка C++ плохо, так как такой код тяжело понимать, тяжело поддерживать, так в нём еще и легко допустить ошибку. Например, создать баг, совмещая различные действия при вычислении аргументов функции. Мы согласны с классической рекомендацией, что код должен быть прост и понятен. И сейчас рассмотрим интересный случай, когда формально анализатор PVS-Studio не прав, но с практической точки зрения код всё равно стоит изменить.
Читать дальше →
Total votes 28: ↑25 and ↓3 +22
Comments 35

Неопределенное поведение, пронесенное сквозь года

Reading time 8 min
Views 5.5K
Open source *C++ *SQL *SQLite *GitHub *
✏️ Technotext 2021

У вас бывают в разработке такие периоды, когда что-то в коде идет не так, ты ищешь баг, а потом оказывается, что за ним стоял еще один баг? Мне нравится искать баги. Это создает ощущение словно ты Шерлок Холмс и являешься главным героем в детективе, где кто-то из обширного списка на вид безобидных классов и функций вызывает неожиданное и даже неопределенное поведение программы, а ты своим зорким взглядом и экспериментами пытаешься вычислить этого мерзавца в кратчайшие сроки.

Можно выделить несколько стадий поиска бага:

• удивление (не знаю как вы, но я каждый раз как в первый раз удивляюсь когда что-то вдруг в моем коде работает не так, как ожидается);

• обвинение всех кругом в баге (коллег по проекту, github, сторонние либы, компилятор), но только не себя;

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

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

• если причина бага все время ускользает, то приятное ощущение того, что ты суперпупердетектив сменяется глупой злостью, и чем дольше я не могу найти причину бага, тем больше я злюсь. И вот такие истории почему-то всегда запоминаются больше всех. Об одной такой истории я вам как раз хочу поведать.

Читать далее
Total votes 33: ↑31 and ↓2 +29
Comments 35

Безопасное использование C++

Reading time 34 min
Views 14K
PVS-Studio corporate blog Information Security *Programming *C++ *Google Chrome
Translation

От переводчика. Данный текст является переводом документа Safer Usage Of C++, выложенного в общий доступ командой Chromium/Chrome из компании Google. Текст активно обсуждался на Reddit, и команда PVS-Studio решила, что аудитории Habr-а может быть интересно познакомиться с его русскоязычным вариантом. Для перевода использован текст от 20 сентября 2021, и на момент его чтения он может отличаться от текста по ссылке.

Читать дальше →
Total votes 26: ↑21 and ↓5 +16
Comments 12

Си должен умереть

Reading time 21 min
Views 106K
Information Security *Programming *System Programming *Compilers *C *
Sandbox

Язык Си - один из наиболее влиятельных языков программирования за всю историю. Он стал незаменимым инструментом разработки операционных систем, сместив с этого пьедестала языки ассемблера. Изучение Си обязательно для любого уважающего себя программиста. Этот язык любим за свою внешнюю простоту и ненавидим за беспощадность к ошибкам. Благодаря нему у нас есть ядро Linux и тысячи уязвимостей в нём же в придачу.

Попробуем понять, что же такое этот противоречивый язык Си - благословение или проклятие?

Читать далее
Total votes 232: ↑194 and ↓38 +156
Comments 643