Что может вызвать порядок инициализации, чтобы повредить стек? - PullRequest
1 голос
/ 01 февраля 2012

Вопрос выделен жирным шрифтом ниже:

Это прекрасно работает:

void process_batch( 
  string_vector & v
) 
{

  training_entry te;
  entry_vector sv; 
  assert(sv.size() == 0);
...
}

Однако это приводит к сбою подтверждения:

   void process_batch( 
      string_vector & v
    ) 
    {
      entry_vector sv; 
      training_entry te;
      assert(sv.size() == 0);
      ...
   }

Теперь я знаю этопроблема не заключена в термоусадочную пленку, поэтому я ограничу свой вопрос следующим образом: какие условия могут вызвать такую ​​проблему?В частности: инициализация переменной будет повреждена в зависимости от порядка появления в кадре стека.В моем коде нет malloc или free, и нет небезопасных функций, таких как strcpy, memcpy и т.д ... это современный c ++.Используемые компиляторы: gcc и clang.

Для краткости ниже приведены типы

struct line_string
{
  boost::uint32_t line_no;
  std::string     line;
};

typedef  std::vector<boost::uint32_t> line_vector;
typedef std::vector<line_vector> entry_vector;
typedef std::vector<line_string> string_vector;

struct training_body
{
  boost::uint32_t url_id;
  bool relevant;
};

struct training_entry
{
  boost::uint32_t session_id;
  boost::uint32_t region_id;
  std::vector< training_body> urls;
};

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

edit

последовал предложению nim и прошел следующий цикл

  1. сжимаем код в соответствии с тем, что я здесь показал, скомпилируйте и протестируйте, без проблем.
  2. #if 0 #endif для сжатия основной программы.
  3. удаление заголовков до тех пор, пока они не будут скомпилированы в сжатой форме.
  4. удаление ссылок библиотеки до компиляции в сжатой форме.

Решение: удаление ссылки на буферы протокола избавляет от проблемы

Ответы [ 4 ]

4 голосов
/ 01 февраля 2012

Стандарт C ++ гарантирует, что следующее утверждение выполнится успешно:

std::vector<anything> Default; 
//in your case anything is line_vector and Default is sv
assert(Default.size() == 0);

Итак, либо вы не рассказываете всю историю, либо у вас испорченная реализация STL.

ИЛИ: В вашем коде неопределенное поведение . Стандарт C ++ не дает никаких гарантий о поведении программы, имеющей конструкцию, ведущую к UB, даже до достижения этой конструкции.

3 голосов
/ 01 февраля 2012

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

1 голос
/ 01 февраля 2012

Есть ли у вас верная версия библиотек Boost, подходящая для вашей платформы?(64 бит / 32 бит)?Я спрашиваю, так как объект entry_vector, кажется, имеет пару переменных-членов типа boost :: uint32_t.Я не уверен, каково может быть поведение, если ваш исполняемый файл создан для одной платформы, а загруженная библиотека повышения - для другой платформы.

1 голос
/ 01 февраля 2012

Что может вызвать вид проблемы, которую вы видите, это пользовательский тип с некорректно работающим конструктором;

class BrokenType {
  public:
  int i;
  BrokenType() { this[1].i = 9999; } // Bug!
};

void process_batch( 
  string_vector & v
) 
{

  training_entry te;
  BrokenType b;  // bug in BrokenType shows up as assert fail in std::vector
  entry_vector sv; 
  assert(sv.size() < 100);
...
}
...