Когда происходит UB и аннулирует ли он все ранее заключенные контракты? - PullRequest
0 голосов
/ 10 июня 2019

Семантика языка C или C ++ образует контраст с пользователем. Некоторые конструкции не имеют каких-либо ограничений на их поведение, либо из-за отсутствия определенного поведения в некоторых случаях (например, разыменование указателя, который не указывает на объект, например, нулевого указателя), либо из-за того, что оно сделано явно не определено. В любом случае не предоставляется никаких гарантий относительно поведения , следующего за .

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

Может ли неопределенное поведение быть предсказуемым, чтобы не возникали некоторые результаты? Например:

std::cout << "hello, world" << std::endl; // with a flush
float f = 1./0.; // UB: cancels previous syscall?

Не будет ли системный вызов write (при условии, что Unix) соответствовать здесь?

А как насчет модели памяти? Существует гарантия того, что все операции над атомарным объектом, мьютексом и всеми последовательно согласованными операциями имеют порядок (каждая соответствует потоку команд, но их объединение не обязательно); Когда применяется эта гарантия, если программа демонстрирует неопределенное поведение?

Может ли реализация использовать неопределенное поведение в какой-то момент выполнения программы в качестве предлога для несоблюдения требований к модели памяти? Другими словами, в какие моменты клиент контракта с языковой семантикой (пользователь) может ожидать выполнения этих требований (при операциях ввода-вывода, при выполнении команд)?

Уточнение: только правильно сформированные программы

(Я понимаю, что, возможно, я не был таким конкретным, как я хотел.)

Некоторые программы, исходный код которых нарушает правило согласованности или правильности:

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

описаны как полностью недействительные. Эти программы могут быть отклонены компилятором с помощью диагностики или скомпилированы, но в этом случае выполнение программы не имеет определенного поведения. Давайте назовем это « a priori UB».

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

Ответы [ 2 ]

13 голосов
/ 10 июня 2019

Может ли неопределенное поведение быть предсказуемым, чтобы не возникали некоторые результаты? Например: ... Не будет ли системный вызов write (при условии Unix) соответствовать здесь?

Да, это будет соответствовать. См. [Intro.execution] / 5:

Соответствующая реализация, выполняющая правильно сформированную программу, должна производить то же наблюдаемое поведение, что и одно из возможных исполнений соответствующего экземпляра абстрактной машины с той же программой и тот же вклад. Однако, если любое такое выполнение содержит неопределенную операцию, этот документ помещает нет требований к реализации, выполняющей эту программу с этим вкладом (даже в отношении операции, предшествующие первой неопределенной операции).

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

Обратите внимание, что в случаях, когда UB зависит от ввода, например:

int main() 
    double x;
    std::cout << "Please enter a number: ";
    std::cin >> x;
    std::cout << "The reciprocal of your number is: " << 1/x << std::endl;
};

применяется положение в [intro.execution] /7.3:

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

Таким образом, программе не разрешается, скажем, ожидать ввода ненулевого значения и только затем распечатывать сообщение Please enter a number:. Сначала он должен распечатать сообщение. Таким образом, в этом смысле область действия UB ограничена событиями, которые происходят после точки, в которую было введено достаточное количество входных данных, чтобы определить, что поведение не определено .

2 голосов
/ 11 июня 2019

Стандарт позволяет реализациям предлагать любые поведенческие гарантии, которые они считают нужными, помимо тех, которые он предписывает. Учитывая что-то вроде:

unsigned char ch = getc();
printf("Oh no %d\n", 1/ch + ((-ch)<<1));

Стандарт не распознает любую ситуацию, в которой выполнение может достичь getc(), не достигая также printf, и, таким образом, предъявляет какие-либо требования к поведению программы в случае возникновения такой ситуации. Реализации, в которых может возникнуть такая ситуация (например, из-за SIGINT, вызванного control-C), которые хотят позволить программистам использовать полученную семантику, могут и должны предлагать соответствующие гарантии помимо тех, которые предусмотрены Стандартом, но вопрос о том, когда предложение таких гарантий выходит за рамки юрисдикции Стандарта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...