LINUX.ORG.RU

Хрупкие программы

 


0

2

Почему так бывает, что при -O0 программа работает нормально, а например при -O3 начинает падать, но не всегда. Чей тут косяк, программиста или gcc? Может ли использование static_cast и запрет неявных преобразований типов избежать такого поведения?


Ответ на: комментарий от I-Love-Microsoft

такое с первой попытки бы увидели unit тесты. Но кому нужно писать надёжные программы, TDD - это забытые знания из начала 2000…

fsb4000 ★★★★ ()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от monk

constexpr unit тесты с любыми флагами можно запускать.

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

constexpr unit тесты я считаю правильной реализацией концепции if it compiles it works

constexpr everything, также это учит правильной работе с side эффектами…

А так да, флаги важны.

fsb4000 ★★★★ ()
Ответ на: комментарий от I-Love-Microsoft

Ну а что-то вроде такого:

int a[10];
int b[10];

int test_n(int n)
{
  for(int i = 1; i<=10; i++)
    if(a[i] == n) return 1;
  return 0;
}

тоже address sanitizer и valgrind увидели бы?

Оптимизатор превращает в эквивалент int test_n(int n) { return 1; }

monk ★★★★★ ()
Ответ на: комментарий от monk

И из constexpr обычные функции нельзя использовать. Тот же printf как?

Как-то так: https://gcc.godbolt.org/z/sj1WG1

Заменяем IO функции своими constexpr заглушками…

fsb4000 ★★★★ ()
Последнее исправление: fsb4000 (всего исправлений: 2)
Ответ на: комментарий от monk

Выход за границы массива 0..9 - AS увидит. Разве оптимизатор имеет право так поступить, если задача проверить содержимого элементов массива? Нужны тесты и решительно уходить от неочевидных конструкций

Надо мной смеются что я не использую продвинутые фишки языков, потому что написать железобетонный очевидный код - не сильно дольше

Часто натыкаюсь на ошибки, которые выявляет AS по недосмотру, но ни разу еще не вляпался в UB или что-то странное

I-Love-Microsoft ★★★★★ ()
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от I-Love-Microsoft

Чтобы не использовать «продвинутые фишки», скоро придётся ставить какой-нибудь древний gcc 5 и компилировать им. Потому что фишки идут за тобой, хочешь ты этого или нет.

Эти учёные головы научили компилятор понимать алгоритмический смысл кода, чтобы он умел делать оптимизации. Но забыли про то, что человек оперирует прагматическим смыслом. И про то, что спецификация языка содержит UB, способные превратить алгоритмически понятный компилятору код в прагматически бессмысленный.

С точки зрения компилятора, он при обнаружении UB делает ровно то, что написано в спецификации: а именно, «что угодно, любой бред». Но человек ждёт от железки другого. Как минимум, диагностики ошибки, если она обнаружена.

wandrien ()
Последнее исправление: wandrien (всего исправлений: 1)
Ответ на: комментарий от I-Love-Microsoft

Нужны тесты

И только, и лучше пользоваться последними фишками языка.

Всё диагностируют компиляторы, даже без флагов предупреждений вовсе, и при агрессивной оптимизации:

https://gcc.godbolt.org/z/c9G7Kq

fsb4000 ★★★★ ()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от I-Love-Microsoft

Выход за границы массива 0..9 - AS увидит.

Так его в бинарнике не будет.

Разве оптимизатор имеет право так поступить, если задача проверить содержимого элементов массива?

Так он и проверяет. Если один из элементов совпадает, то return 1, иначе выход за границы UB, значит тоже return 1. Раз в любом случае return 1, то всё остальное можно выкинуть.

monk ★★★★★ ()
Ответ на: комментарий от wandrien

Но человек ждёт от железки другого. Как минимум, диагностики ошибки, если она обнаружена.

Тогда всюду вместо ассемблерного add придётся вкомпилировать проверку на переполнение. К массиву придётся прикреплять размер, чтобы можно было сделать проверку на выход за границы и на каждое чтение/запись его проверять.

В общем, тогда надо писать на Java или Lisp. Там всё именно так. В Common Lisp ещё и интерактивный отладчик с возможностью вызова любой функции на ошибку запустится.

monk ★★★★★ ()
Ответ на: комментарий от wandrien

при обнаружении UB делает ровно то, что написано в спецификации: а именно, «что угодно, любой бред»

Не совсем любой, а такой, который позволяет сделать программу быстрее. Вот что должно вернуть (a[10] == n), если в a всего 10 элементов? Если вернуть истину, программа будет работать быстрее, значит будет истина.

monk ★★★★★ ()
Ответ на: комментарий от monk

Так функциональность этого кода иная от исходного.
Это не оптимизация, а баг. Функция ведь и 0 может возвратить, а у оптимизатора всегда return 1;

Если оптимизатор такой умный, то вызов этой функции он должен просто заменять на 1.

Если «туплю», то в чем?

Владимир

anonymous ()
Ответ на: комментарий от anonymous

Это не оптимизация, а баг. Функция ведь и 0 может возвратить, а у оптимизатора всегда return 1;

Если между вызовами функции память за пределами массива будет меняться так, что её значение будет совпадать с переданным параметром, то будет всегда 1.

То есть баг есть независимо от наличия оптимизации. Но оптимизация может баг иногда заменить на баг всегда или баг никогда. Например, если код выглядит так:

int test_n(int n)
{
  for(int i = 1; i<=10; i++)
    if(a[i] == n) return i;
  return 0;
}

то оптимизатор уберёт выход за границы массива (и возможно убережёт от сегфолта).

monk ★★★★★ ()
Ответ на: комментарий от monk

то оптимизатор уберёт выход за границы массива

Точно!

Лучше бы компилятор подсказал, что этот «гад» /программист/, пытается сделать присвоение за пределами массива.

Да и у меня «паразита» иногда такое бывает …

Вот когда разрабатывал API для работы с Moxcel, то доверял описанию формата mxl, а оно то местами неправильное было.
Результат был «не ахти» пока не понял в чем причина.

Как говорил Мюллер

В этом мире никому нельзя верить.  
Только мне.

Владимир

anonymous ()
Ответ на: комментарий от fsb4000

Владимир пиши constexpr функции и тесты, и компилятор будет делиться с тобой всеми тайнами.

Программистам нельзя возражать /потом пожалеешь сто раз/.

Владимир

anonymous ()
Ответ на: комментарий от monk

Тогда всюду вместо ассемблерного add придётся вкомпилировать проверку на переполнение.

Ну а умный оптимизатор на что – понять, где переполнение точно есть (и не компилировать), где оно может быть (ставить проверку), а где его нет.

Заметь – такой режим компиляции не противоречит спецификации, где переполнение – UB. Потому что отказываться компилировать – точно такое же «делать что угодно», как и любое другое.

К массиву придётся прикреплять размер, чтобы можно было сделать проверку на выход за границы и на каждое чтение/запись его проверять.

В итоге имеем абсурдную ситуацию, когда компилятор, если не знает размер массива, генерирует прагматически верный код, а если знает – ерунду.

Логика? Не вижу её тут.

wandrien ()
Последнее исправление: wandrien (всего исправлений: 1)
Ответ на: комментарий от monk

В общем, тогда надо писать на Java или Lisp.

Почему в 70-х парни сделали пародию на Паскаль, и она стала промышленным стандартом – более менее ясно.

Но почему к 2020-му никто не почесался сделать нормальную интеграцию возможностей железа в системный язык, мне не ясно. И кивают на прикладную Java.

Что мешает ввести типы checked int, unchecked int, wrapped int, int with nan с ясно описанной семантикой? (UB только за unchecked int оставить.)

Или что мешает ввести спецификаторы для блоков кода наподобие:

checked {
   /// some math...
}
unchecked {
   /// some math...
}

Или даже:

try checked {
   /// some math...
} else {
   return ERANGE;
}

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

Приходится ссылаться на какую-нибудь маргинальщину типа zig. А хочешь писать на промышленном стандарте – твоя участь страдать.

Люди стали совсем дурные?

wandrien ()
Последнее исправление: wandrien (всего исправлений: 1)
Ответ на: комментарий от wandrien

Что мешает ввести типы checked int, unchecked int, wrapped int, int with nan с ясно описанной семантикой? (UB только за unchecked int оставить.)

Но почему к 2020-му никто не почесался сделать нормальную интеграцию возможностей железа в системный язык, мне не ясно. И кивают на прикладную Java.

https://www.boost.org/doc/libs/develop/libs/safe_numerics/doc/html/index.html

https://docs.rs/checked/0.5.0/checked/

полно и библиотек и языков…

fsb4000 ★★★★ ()
Ответ на: комментарий от fsb4000

полно и библиотек

Сделать int with nan я и сам могу, но вот вкрутить его в компилятор – нет. В данном случае я про Си, в крестах-то понятно, там всё просто.

и языков…

Маргинальщина не нужна.

wandrien ()
Ответ на: комментарий от anonymous

Вот когда разрабатывал API для работы с Moxcel, то доверял описанию формата mxl, а оно то местами неправильное было

Придется некоторые конфигурации на 8-ку переводить.
Сделаю так

 - Метаданные выгружу в xml, которые 8-ка принимает за "свои" и на основании которых может создать метаданные в конфигураторе;

 - Загрузка данных в базу 1С будет произведена из своей базы в которую будут "залиты" данные объектов 1С 7.7;

 - Что касаемо отчетов, то сделаю run-time, который на основании шаблонов отчетов может сформировать отчет;

 - Для исходных данных, для формирования отчетов, вместо ТЗ 1С будет использована своя ТЗ /с индексами, группировками, ..., .../;
 ...

Как-то так.
Кстати все это может функционировать и без 1С …

Владимир

anonymous ()
Ответ на: комментарий от anonymous

Кстати все это может функционировать и без 1С …

Нет у меня API, которое было бы привязано к 1С, Windows, Linux …, к какому-либо компилятору …

Есть API к которому можно сделать bindings к, …, …, и Метапрог в частности.

GUI вот ни как не получается начать разрабатывать /OpenGL/.
Эх, …

Эй вы там, QT и GTK!
От вас спасенья нет.
Не могу больше слушать
Я ваш кордебалет!

Владимир

anonymous ()