Хабы: Компиляторы, C++, Программирование
Недавно у нас в команде зашла дискуссия о неопределённом поведении (UB) в C. Напомню для тех, кто не знает: если мы пишем такой код, эффект от выполнения которого (и события в процессе его выполнения) строго не определён в спецификации языка, то возникает неопределённое поведение. Таким образом, встретив такой код, компилятор может действовать по собственному усмотрению, и нет никаких гарантий, что выполнение этого кода пойдёт по предсказуемому пути. Следовательно, нужно избегать неопределённого поведения любой ценой, поскольку мало того, что оно может приводить к глюкам программы, но и часто становится источником уязвимостей и угрозой безопасности. Примеры кода, в котором проявляется неопределённое поведение: выход за границы массива при его индексировании, целочисленное переполнение, деление на ноль, разыменование указателя на null [1].
Компиляторы нередко пользуются неопределённой семантикой языка, чтобы делать те или иные допущения о программе. Например, если написать что-то вроде int x = y/z
, компилятор может предположить, что z не может быть равно нулю, так как деление на ноль приводит к неопределённому поведению, а программист явно не собирался писать такой код. На основе этой информации он может попытаться далее оптимизировать программу так:
Читать далее