Комментарии 18
Я считаю, что система, в которой варнинги надо "подавлять" является деструктивной для производственной культуры. Если стандартной реакций на варнинг является не "поправить", а "заткнуть", то люди быстро привыкают, что надо просто затыкать.
Ситуация совершенно аналогичная мониторингу. Чем больше красных лампочек надо игнорировать, тем ниже его польза. См ядерную аварию на 3 miles island, где была именно ситуация "100 лампочек красные и их надо игнорировать, 101ая — признак аварии реактора".
Я считаю, что система, в которой варнинги надо «подавлять» является деструктивной для производственной культуры.Вроде как мысль правильная и я с ней согласен. Но только она мимо :). Вот возьмём, например, проверки ошибок в Microsoft Word. Он тоже иногда подчёркивает не то, что нужно. Повод ли это отключить проверку текста? Нет конечно. С ней, текст будет более качественный, несмотря на ложные срабатывания.
Тоже самое и со статическим анализом кода. Да, если ложный срабатываний слишком много, то пользоваться анализатором нельзя. Но ведь и нет этого огромного количества ложных срабатываний. Это придуманная проблема. И статья как раз про это.
Потому что ошибки все равно будут, но выбирая между ошибками первого рода или второго, в таких случаях лучше выбирать ошибки первого рода, как мне кажется.
С другой стороны, шлифовать анализатор от ложных срабатываний тоже надо, но мне кажется, упрекнуть pvs-studio в том, что они этого не делают сложно.
У меня ощущение, что статический анализатор для С/С++ — это как попытка заложить прорвавшуюся плотину мешками с песком.
UB без варнингов в стандарте языка — это всё. Можно закапывать. Никакие сторонние иструменты эту проблему уже не решат.
Не решат, но сгладят, причем, скорее всего, значительно. Так почему бы и нет?
Причем статические анализаторы не только по UB, они еще могут быть про все, что угодно от неочевидных мест языка до стилестических ошибок.
LD r26, X+
LD r27, X+
LD r26, -X
LD r27, -X
— тоже аналогично является UB. C/C++, как языки, максимально приближенные к «железу», и максимально оптимизируемые, используют UB в своих целях, рассчитывая на то, что в корректно написанной программе не нужно будет делать на каждый чих кучу неявных runtime-проверок на NULL, на переполнение знаковых типов, на выход за границы массива, и так далее, и тому подобное. Варнинги тут не помогут просто потому, что компилятор не способен отловить такие ситуации на этапе собственно компиляции — как, например, отловить signed overflow на этапе компиляции? Да никак — только runtime checks, только хардкор. C/C++ предполагают, что разработчик позаботится об этом сам в тех местах и в той степени, в которой посчитает нужным.
Например, на x86 попытка выполнить инструкцию BSF над нулевым source operand — это UB в том смысле, что содержимое destination operand может оказаться абсолютно любым
Нет, это не undefined behavior, а всего лишь unspecified. Undefined behavior тут бы бы, если бы некорректная команда, к примеру, повреждала память микропрограмм. Ну или одновременное обращение к одной и той же области памяти из разных ядер без барьеров — но это "привычное" UB, его обычно в недостатки языка не записывают.
Unspecified behavior в терминах C/C++ в данном случае был бы, если бы, скажем, в зависимости от конкретной модели процессора значение destination operand было бы разным, но отнюдь не произвольным (each unspecified behavior results in one of a set of valid results). То есть, например, unspecified behavior — это операция foo() + boo(), результат которой в конце концов строго определён (результат foo() плюс результат boo()), но в каком порядке будут вызваны foo и boo — не определено. Документация Intel же никакого set of valid results не очерчивает.
В данном случае важно что в регистре в принципе будет хоть какое-то значение, которое, несмотря на бессмысленность, все же можно обработать и получить непротиворечивый результат.
UB — это когда, например, выражение i >= 0 ? i : 0
выдаёт -1.
Ну так и в вашем случае будет "хоть какое-то значение, которое можно обработать" :) Главное отличие unspecified behavior от undefined ведь именно что в наличии описанного в документации set of valid results. Ну это опять же в терминах C/C++ если говорить, в документации от Intel своя терминология (там, кстати, прямо употребляется термин undefined).
Ну и какое значение в моём примере у переменной i?
Ну и какое значение в моём примере у переменной i?
unsigned i = 0xFFFFFFFF;
int result = i >= 0 ? i : 0;
Это вы написали вариант, при котором в самом выражении i >= 0 ? i : 0
происходит UB. А я писал про вариант, когда UB уже произошло до этой строчки.
Например, что-то вроде такого:
int foo = внешняяФункцияЧтоВернётIntMax();
if (foo < 0) {
return;
}
int i = foo*2 + 1;
if (i >= 0) {
printf("%d >= 0", i); // -1 >= 0
}
Можно ли считать, что в переменной i
тут вообще находится хоть какое-то значение?
это я понял как о скомпилированном коде (runtime). Там всё детерминированно
Так именно об этом я и говорю! В рантайме всё детерминировано (по крайней мере, на одном ядре). Некорректно говорить, что какая-то там инструкция процессора приводит к UB в том смысле, который вкладывается в это понятие языком C++ (по тех пор, пока эта инструкция не портит железо).
Кстати, если бы на том атомном блоке постоянно горящие красные лампочки закрывали заглушками — было бы аналогично: нормально не видим красных, одна появилась — ой, надо что-то делать.
Работа с возражениями: статический анализ будет отнимать часть рабочего времени