Конструктор вызван с неправильным указателем this. Это повреждение стека?

редактировать: Разобрался с помощью комментаторов. Чтобы ответить на вопрос, поставленный в моем заголовке: Нет, это не повреждение стека, его gdb сообщает неправильные значения. Программа на самом деле ведет себя так, как ожидалось, и имеет правильный указатель this . Фактическое ошибочное поведение, которое побудило меня опубликовать этот вопрос, вероятно, полностью не связано с проблемой, которую я описываю здесь.

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

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

itvt::itvt(const itvt& i)
  : _i(i.type == INTBV ? new intbv_intervalt(i.i()) : NULL),
    _f(i.type == FLOAT ? new float_intervalt(i.f()) : NULL),
    type(i.type), other_bottom(i.other_bottom) 
{ }

Теперь я обнаружил ошибку повреждения памяти и смог отследить ее до следующего фрагмента кода:

itvt itvt::get_split(bool le) const
{
   itvt result(*this);
   [...]
}

Используя gdb, я обнаружил, что вызов конструктора делает Похоже, что не создается объект «результат»:

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517
517   itvt result(*this);
(gdb) n
519   if(is_singleton() || is_bot())
(gdb) print result
$3 = {
  _i = {
    _M_ptr = 0x7fff5fbfe100
  }, 
  _f = {
    _M_ptr = 0x7fff5fbfed60
  }, 
  type = 1606410016, 
  other_bottom = 255
}
(gdb) print *this
$4 = {
  _i = {
    _M_ptr = 0x1020833a0
  }, 
  _f = {
    _M_ptr = 0x0
  }, 
  type = itvt::INTBV, 
  other_bottom = false
}

Посмотрев глубже, я обнаружил, что внутри конструктора копирования указатель «this» указывает на неправильный объект:

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517
517   itvt result(*this);
(gdb) print &result
$5 = (itvt *) 0x7fff5fbfdee0
(gdb) s     
itvt::itvt (this=0x7fff5fbfdf80, i=@0x1016af560) at itv.cpp:500
500     type(i.type), other_bottom(i.other_bottom)
(gdb) print this
$6 = (itvt * const) 0x7fff5fbfdf80

Поскольку «результат» размещен в стеке по адресу 0x7fff5fbfdee0 , Я бы ожидал, что указатель this внутри конструктора копирования будет указывать на тот же адрес. Вместо этого он указывает на 0x7fff5fbfdf80.

Похоже, что конструктор копирования инициализирует что-то , но не объект «результат» в стеке, в котором он вызывается. Фактически, я могу получить доступ к той области памяти, которую конструктор отлично инициализировал:

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517
517   itvt result(*this);
(gdb) s    
itvt::itvt (this=0x7fff5fbfdf80, i=@0x1016af560) at itv.cpp:500
500     type(i.type), other_bottom(i.other_bottom)
(gdb) finish
Run till exit from #0  itvt::itvt (this=0x7fff5fbfdf80, i=@0x1016af560) at itv.cpp:500
itvt::get_split (this=0x1016af560, le=false) at itv.cpp:519
519   if(is_singleton() || is_bot())
(gdb) print *((const itvt*) (0x7fff5fbfdf80))
$7 = {
  _i = {
    _M_ptr = 0x1016b6d10
  }, 
  _f = {
    _M_ptr = 0x0
  }, 
  type = itvt::INTBV, 
  other_bottom = false
}

Мой первый вопрос: Можно ли объяснить нормальным поведением тот факт, что указатель this указывает на неправильный объект? Кажется, какая-то странная проблема с повреждением памяти, но, возможно, я что-то упускаю.

Я компилирую с флагами g ++ и "-O0 -ggdb" и, кстати, сделал новую перекомпиляцию всего.Вот моя версия g ++:

leo@scythe ai$ g++ --version
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

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

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

Я благодарен за любой совет или понимание, которое вы можете предложить.

редактировать: Вот соответствующий фрагмент класса itvt:

class itvt
{
protected:
  typedef std::auto_ptr<intbv_intervalt> iptrt;
  typedef std::auto_ptr<float_intervalt> fptrt;
  iptrt _i;
  fptrt _f;
public:
  typedef enum {INTBV, FLOAT, OTHER} itv_typet;
  itv_typet type;

  bool other_bottom;

  //copy constr
  itvt(const itvt& i);

  inline intbv_intervalt& i() { return *_i; }
  inline float_intervalt& f() { return *_f; }
  inline const intbv_intervalt& i() const { return *_i; }
  inline const float_intervalt& f() const { return *_f; }

  itvt get_split(bool le) const;

  [...]
};
6
задан leo 1 March 2012 в 14:20
поделиться