edit: Я понял это с помощью комментаторов.Чтобы ответить на вопрос, поставленный в моем заголовке: Нет, это не повреждение стека, его GDB сообщает неверные значения.Программа на самом деле ведет себя как ожидалось и имеет правильный указатель this
.Фактическое поведение с ошибками, которое побудило меня опубликовать этот вопрос, вероятно, совершенно не связано с проблемой, которую я описываю здесь.
Сначала предупреждение.Я полагаю, что это проблема повреждения памяти, и я, как правило, не ожидаю ответа, за исключением «тщательно проверить свой код», но я неоднократно видел это поведение и надеялся, что некоторые из вас поняли проблему и как яМожно найти его источник.
В настоящее время я реализую статический анализ интервалов, который отслеживает возможный диапазон переменных в программе на Си.Конструктор копирования для моего базового интервала выглядит следующим образом:
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, я обнаружил, что вызов конструктора, по-видимому, не создает объект «result»:
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.
Я благодарен за любые советы или советы, которые вы можете предложить.
edit: Вот соответствующий фрагмент класса 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;
[...]
};