Может ли UB заставить несколько однопоточных приложений работать с разными выходами? - PullRequest
1 голос
/ 22 августа 2010

Возможно ли, чтобы код, удовлетворяющий следующим условиям, выдавал разные выходные данные для каждого запуска для одного и того же ввода?

  • Код однопоточный, хотя он связывается с безопасным для потока рабочим временембиблиотека.
  • Нет явных вызовов rand () или time () или их друзей.
  • Есть некоторые выделения памяти в куче.
  • Может быть некоторый (глючный) код, который приводит к неопределенному поведению.

Ответы [ 6 ]

8 голосов
/ 22 августа 2010

«Неопределенное поведение» означает, что может произойти все что угодно.Это также включает в себя то, что разные вещи могут происходить при каждом запуске программы.

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

Простой пример:

int main() {
  char s[1024];
  s[1023] = '\0';
  std::cout << s << std::endl;
}

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

Другой пример: new может возвращать разные адреса напри каждом запуске программы (здесь также нет UB):

int main(void) {
   std::cout << new int << std::endl;
}

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

1 голос
/ 22 августа 2010

Вы получите много ответов «все может случиться с неопределенным поведением», поэтому я не буду обсуждать эту тему. Я предполагаю, что у вас есть программа, которую вы не написали сами, она должна быть детерминированной, и вы должны отладить ее или что-то в этом роде.

  • современные ОС имеют рандомизацию адресов , поэтому неопределенное поведение, использующее адреса в качестве целых чисел, может быть недетерминированным

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

Это все, что я могу думать сейчас.

0 голосов
/ 22 августа 2010

В дополнение к тому, что уже сказали другие люди:

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

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

0 голосов
/ 22 августа 2010

Конечно.

Многие вещи по-прежнему различаются между исполнениями, даже если вы не вызываете rand или time.

Например:

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

И, конечно, ваш последний пункт отвечает на это.Если ваш код содержит неизвестные ошибки, вы не можете принять что-нибудь об этом.Что если одна из этих ошибок заключается в том, что она вызывает rand, хотя вы думали, что это не так?

Лучше не пытаться быть умным в UB.Если оно не определено, оно не определено, и вы просто копаете яму для себя, если пытаетесь понять, что «в этом случае все не так плохо».Потому что это может быть.

0 голосов
/ 22 августа 2010

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


Просто дляnitpick следующая программа отвечает вашим требованиям.

#include <time.h>
#include <iostream>
int main() 
{
    std::cout << time(NULL);
}
0 голосов
/ 22 августа 2010

Похоже, последнее условие является ответом на этот вопрос.Кроме этого, я могу подумать, например, о вызове time () и использовании его результата в некоторых вычислениях.

...