Как стать автором
Обновить

Комментарии 5

Для варианта «Windows MSVC 2019 16.5.4, усложнённый пример, /O1, /O2» первого примера логика работы описана неправильно.
— копирует это же значение в ebx (строка 11);

Нет. Там же не mov, а cmove — условное копирование, если ZF=1. Поэтому вывод
В stream выводится единица.

неверен. В stream выводится 1, если rand() вернул 0, а в противном случае выводится младший байт значения EBX, установленного в строке 6 командой «movzx ebx,byte ptr [rsp+30h]» — т.е. первый байт стека над адресом возврата.
Спасибо, в самом деле, моя ошибка.
Исправил статью.
И дополнил в соответствии с возможностью поуправлять ещё одним возвращаемым значением.
Плюсик Вам в карму.
Спасибо!

Интересный анализ, практически небольшой детектив. Озвучу пару заметок:


  • Как видно из примеров (фактически, это наброски и демонстрации простых эксплоитов), данное UB вполне может использоваться в качестве потенциальной уязвимости в составной атаке.
  • Даже на высоких уровнях предупреждений и с максимальным количеством включенных флагов-warning'ов компиляторы не всегда способны определить наличие ошибочного пути выполнения, на котором не происходит возврата значения (и предупредить программиста). Особенно легко получить такую ситуацию в сложном шаблонном коде: буквально неделю назад пришлось 2 часа дебажить с gdb превращение памяти в неотлаживаемое месиво из за тупого пропуска слова return в функции-однострочнике.
Странно. Почему оптимизирующий компилятор не превратил код
bool bad()
{
if (rand() == 0) {
return true;
}
}

в

bool bad()
{
rand();
return true;
}

Функция rand() имеет побочный эффект, поэтому выбросить её вызов нельзя, а вот возврат true — это разрешённый стандартом вариант неопределённого поведения. И результирующий код короче, и известное возвращаемое значение позволяет дальнейшую оптимизацию.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации