Рубрика «неопределённое поведение»

В статье исследуются возможные проявления неопределённого поведения, возникающего в c++ при завершении не-void функции без вызова return с подходящим значением. Статья носит больше научно-развлекательный характер, чем практический.
Кому не нравится весело скакать по граблям — проходим мимо, не задерживаемся.
Читать полностью »

Неопределённое поведение с устаревшими объявлениями функций в ANSI C - 1

Стандарт ANSI C определяет понятие прототипа функции, представляющее собой подмножество объявления функции, которое указывает типы входных параметров. Прототипы были введены с целью устранить недостатки, которыми обладают обычные объявления функций.

Таким образом, указание списка типов параметров в круглых скобках прототипа функции обязательно, иначе такое выражение будет признаваться компилятором как устаревшее объявление функции, что может привести к неоднозначным ситуациям, описанным в данной статье.

Читать полностью »

Магические трансформации типов данных в Rust: Интринсика mem::transmute<T, U> - 1

Введение

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

Одной из них является наш сегодняшний экземпляр — интринсика mem::transmute<T, U>, предназначенная для того и другого понемногу, пригождаясь в крайне необычных ситтуациях.

Читать полностью »

Термином «неопределённое поведение» в языке C и C++ обозначают ситуацию, в которой буквально «чего только не бывает». Исторически, к неопределённому поведению относили случаи, когда прежние компиляторы для C (и архитектуры на нём) вели себя несовместимым образом, и комитет по разработке стандарта, в своей безграничной мудрости, решил ничего не решать по этому поводу (т.е. не отдавать предпочтение какой-то одной из конкурирующих реализаций). Неопределённым поведением также называли возможные ситуации, в которых стандарт, обычно столь исчерпывающий, не предписывал никакого конкретного поведения. У этого термина есть и третье значение, которое в наше время становится всё более актуальным: неопределённое поведение — это возможности для оптимизации. А разработчики на C и C++ обожают оптимизации; они настойчиво требуют, чтобы компиляторы прикладывали все усилия для ускорения работы кода.

Данная статья была впервые опубликована на сайте Cryptography Services. Перевод публикуется с разрешения автора Томаса Порнина (Thomas Pornin).
Читать полностью »

Началось все, как водится, с ошибки. Я первый раз работал с 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++) с вариативными шаблонами.
Читать полностью »

Эта статья посвящена неопределённому поведению и оптимизациям компилятора, особенно в контексте знакового целочисленного переполнения.

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

Компиляторы языка C (и C++) в своей работе всё чаще руководствуются понятием неопределённого поведения — представлением о том, что поведение программы при некоторых операциях не регламентировано стандартом и что, генерируя объектный код, компилятор вправе исходить из предположения, что программа таких операций не производит. Немало программистов возражало против такого подхода, поскольку сгенерированный код в этом случае может вести себя не так, как задумывал автор программы. Эта проблема становится всё острее, так как компиляторы применяют всё более хитроумные методы оптимизации, которые наверняка будут опираться на понятие неопределённого поведения.
Читать полностью »

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

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

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

Кроме подводных камней типа псевдонимов указателей, у языка C фундаментальные неисправленные ошибки, которые ждут своих жертв. Именно эти уязвимости Кейс Кук, инженер по безопасности ядра Google Linux, рассмотрел на конференции по безопасности Linux в Ванкувере.
Читать полностью »

Ад ближе чем кажетсяМногие считают, что неопределённое поведение программы возникает из-за грубых ошибок (например, запись за границы массива) или на неадекватных конструкциях (например, i = i++ + ++i). Поэтому для многих является неожиданностью, когда неопределенное поведение вдруг проявляет себя во вполне привычном и ничем не настораживающем коде. Рассмотрим один из таких примеров. Программируя на C/C++ никогда нельзя терять бдительность. Ад ближе чем кажется.

Читать полностью »

                                             — У нас дыра в безопасности.
                                             — Ну, хоть что-то у нас в безопасности.
                                                                                  Анекдот

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

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

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

Читать полностью »

Silent NULL (Разыменовывание нулевого указателя приводит к неопределённому поведению)
Ненароком я породил большую дискуссию, касающуюся того, допустимо ли использовать в Си/Си++ выражение &P->m_foo, если P является нулевым указателем. Программисты разделились на два лагеря. Одни уверенно доказывали, что так писать нельзя, другие столь же уверенно утверждали, что можно. Приводились различные аргументы и ссылки. И я понял, что нужно внести окончательную ясность в этот вопрос. Для этого я обратился к экспертам Microsoft MVP и разработчикам Visual C++, общающимся через закрытый список рассылки. Они помогли подготовить эту статью, и я представляю её всем желающим. Для нетерпеливых: этот код не корректен.
Читать полностью »


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js