Как определить неопределенное поведение

Там какой-либо путь состоит в том, чтобы знать, программируете ли Вы, имеет неопределенное поведение в C++ (или даже C), за исключением запоминания всей спецификации?

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

12
задан Community 23 May 2017 в 12:01
поделиться

10 ответов

Хорошие стандарты кодирования. Защищают вас от самих себя. Вот некоторые идеи:

  1. Код должен компилироваться на самом высоком уровне предупреждений... without warnings. (Другими словами, ваш код не должен вызывать никаких предупреждений при установке на самый высокий уровень). Включите флаг error on warning для всех проектов.

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

  2. Всегда используйте RAII.

  3. Никогда не используйте касты в стиле C! Никогда! - Я думаю, есть пара редких случаев, когда вам придется нарушить это, но вы, вероятно, никогда не найдете их.

  4. Если вы должны reinterpret_cast или приводить к void, то используйте обертку, чтобы убедиться, что вы всегда приводите к/от одного и того же типа. Другими словами, оберните указатель/объект в boost::any и приведите указатель на него к тому типу, который вам нужен, а на другой стороне сделайте то же самое. Почему? Потому что вы всегда будете знать, от какого типа нужно reinterpret_cast, а boost::any после этого будет следить за тем, что вы привели к правильному типу. Это самое безопасное, что вы можете получить.

  5. Всегда инициализируйте свои переменные в точке объявления (или в инициализаторах конструктора, когда вы находитесь в классе).

Есть и другие, но эти очень важны для начала.

Никто не может запомнить стандарт. Что мы, программисты среднего и продвинутого уровня, делаем в C++, так это используем конструкции, которые, как мы знаем, безопасны, и защищаем себя от нашей человеческой природы... и мы не используем конструкции, которые небезопасны, если только мы не должны это делать, и тогда мы принимаем дополнительные меры, чтобы убедиться, что опасность завернута в хороший безопасный интерфейс, который протестирован до чертиков и обратно.

Важно помнить одну важную вещь, которая универсальна для всех языков:

делайте ваши конструкции легкими для правильного использования и трудными для неправильного

16
ответ дан 2 December 2019 в 05:26
поделиться

Невозможно обнаружить неопределенное поведение во всех случаях. Например, рассмотрим x = x ++ + 1; . Если вы знакомы с языком, вы знаете, что это UB. Итак, * p = (* p) ++ + 1; , очевидно, тоже UB, но как насчет * q = (* p) ++ + 1; ? Это UB, если q == p , но кроме этого он определен (если выглядит неудобно). В данной программе вполне возможно доказать, что p и q никогда не будут равны при достижении этой линии, но в целом это невозможно.

Чтобы помочь обнаружить UB, используйте все имеющиеся у вас инструменты. Хорошие компиляторы будут предупреждать, по крайней мере, в наиболее очевидных случаях, хотя вам, возможно, придется использовать некоторые параметры компилятора для лучшего охвата. Если у вас есть дополнительные инструменты статического анализа, воспользуйтесь ими.

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

5
ответ дан 2 December 2019 в 05:26
поделиться

Ну, эта статья охватывает большинство аспектов ..

2
ответ дан 2 December 2019 в 05:26
поделиться

Инструменты статического анализа кода, такие как PC-Lint , могут здесь очень помочь

3
ответ дан 2 December 2019 в 05:26
поделиться

Думаю, вы можете использовать один инструмент из coverity для обнаружения ошибок, которые могут привести к неопределенному поведению.

Думаю, вы могли бы использовать средство доказательства теорем (я знаю только Coq), чтобы быть уверенным, что ваша программа делает то, что вы хотите.

2
ответ дан 2 December 2019 в 05:26
поделиться

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

2
ответ дан 2 December 2019 в 05:26
поделиться

Я не знаю ни одного программного инструмента для обнаружения всех форм ПБ. Очевидно, что использование предупреждений вашего компилятора и, возможно, lint или другой статической программы проверки кода может сильно помочь.

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

1
ответ дан 2 December 2019 в 05:26
поделиться

Просто: Не делайте того, в чем вы не уверены.

  • Когда вы не уверены или чувствуете неладное, проверьте ссылку
0
ответ дан 2 December 2019 в 05:26
поделиться

К сожалению, не существует способа обнаружить все UB. Для этого вам придется решить проблему остановки.

Лучшее, что вы можете сделать, это знать как можно больше правил, смотреть их, когда сомневаетесь, и проверять у других программистов (через парное программирование, обзоры кода или просто вопросы SO)

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

Но в конечном итоге ни один инструмент не сможет обнаружить все.

Дополнительная проблема заключается в том, что многие программы фактически вынуждены полагаться на UB. Некоторые API требуют его, и просто предполагают, что "он работает на всех вменяемых компиляторах". OpenGL делает это в одном или двух случаях. Win32 API не компилируется даже в компиляторе, соответствующем стандартам.

Так что даже если бы у вас был волшебный инструмент для обнаружения UB, он бы все равно сбился из-за случаев, которые вам не подвластны.

0
ответ дан 2 December 2019 в 05:26
поделиться

Хороший компилятор, такой как компилятор Intel C ++, должен уметь обнаруживать 99% случаев неопределенного поведения. Вам нужно будет изучить флаги и переключатели, которые нужно использовать. Как всегда, читайте инструкцию.

-3
ответ дан 2 December 2019 в 05:26
поделиться