У меня есть стек, выделенный std::vector
это переписывается неким мошенническим кодом. Это не данные перезаписывается, но внутреннее состояние. Я знаю это, потому что size()
Функция-член возвращает нежелательное значение некоторое время в программу. Инициализируется правильно. Я подозреваю общую ошибку указателя в другом месте в моем коде.
я использую Xcode 4.6.2. Я хочу установить аппаратную точку останова (с lldb) при доступе к памяти первой ячейки памяти вектора (самого вектора, а не данных), чтобы я мог видеть, что его перезаписывает. В соответствии с этот Мне нужно сначала найти адрес вектора. Обычно можно использовать &
оператор, чтобы получить адрес переменной, но по какой-то причине с lldb это не возвращает адрес, а вместо этого выводит какую-то итоговую строку.
class myClass {
public:
myClass() : myVector(4) {}
private:
std::vector<double> myVector;
double myDouble;
};
После разрыва в произвольной точке останова после того, как все построено:
(lldb) frame variable &myObject.myVector
(std::vector<double, std::allocator<double> > *) $7 = size=4
‘expr’ имеет тот же результат:
(lldb) expr &myObject.myVector;
(std::vector<double, std::allocator<double> > *) $8 = size=4
Обычно я ожидаю увидеть напечатанный адрес, например, с этим простым элементом данных:
(lldb) frame variable &myObject.myDouble
(double *) &myDouble = 0x0000000125589328
Я попытался присвоить адрес переменной с помощью ‘expr’, но это тоже не работает:
(lldb) expr std::vector<double, std::allocator<double> > * f = &myObject.myVector; f
(std::vector<double, std::allocator<double> > *) $12 = size=0
Возвращенный там нулевой размер (вместо 4) предполагает, что он все равно не выбрал правильный вектор.
Итак, как мне получить адрес этого вектора? Если я щелкну на нем правой кнопкой мыши в списке переменных кадра Xcode и выберу «Просмотр памяти» этого вектора, то откроется вид 0x0
что, конечно, неверно. Обратите внимание, что вектор расположен в стеке — он фактически находится внутри нескольких других объектов, но все они построены из стека.
Обратите внимание, что я не желая получить адрес данных в векторе — на самом деле это не перезаписывается. Это внутреннее хранилище выделенного стека векторного объекта, которое повреждено.
Ваш myObject
Объект, скорее всего, является локальной переменной и существует в стеке:
(lldb) p &myObject
(myClass *) $0 = 0x00007fff5fbffad8
(lldb) p $fp >= &myObject && &myObject >= $sp
(bool) $1 = true
Если вы хотите, чтобы lldb не печатал вектор красиво, используйте -R
/ --raw-output
возможность frame variable
:
(lldb) fr va -R myObject
(myClass) myObject = {
myVector = {
std::_Vector_base<double, std::allocator<double> > = {
_M_impl = {
_M_start = 0x00000001001008d0
_M_finish = 0x00000001001008f0
_M_end_of_storage = 0x00000001001008f0
}
}
}
myDouble = 6.95322297580907e-310
}
Вы заметите, что адреса на векторе — это куча адресов, то есть они были malloc
‘ed (new
‘, что угодно) вместо того, чтобы находиться внутри вашего myObject
непосредственно. Так что теперь вы должны решить, что вы хотите контролировать. Если вы хотите отслеживать вектор, чтобы увидеть, как новый элемент добавляется в конец вашего вектора, то вы хотите наблюдать указатель конца вектора,
(lldb) p &myObject.myVector._M_impl._M_finish
(double **) $4 = 0x00007fff5fbffae0
Если вы хотите контролировать содержимое одного из векторов, скажем первый, то вы хотите контролировать
(lldb) p myObject.myVector._M_impl._M_start
(double *) $6 = 0x00000001001008d0
Конечно, когда элементы добавляются к вектору, он может быть перемещен в новый диапазон адресов (если область памяти в куче не может быть увеличена для хранения нового элемента), так что это будет немного хрупким.
Обычно форматеры типа lldb (для std::vector
в этом случае) предпочтительнее, чем просмотр необработанной реализации, но если вы хотите работать с необработанной реализацией, в этом случае может быть проще отключить средства форматирования. например
(lldb) type category disable gnu-libstdc++
(lldb) p myObject
(myClass) $9 = {
(std::vector<double, std::allocator<double> >) myVector = {
(std::_Vector_base<double, std::allocator<double> >) std::_Vector_base<double, std::allocator<double> > = {
(std::_Vector_base<double, std::allocator<double> >::_Vector_impl) _M_impl = {
(double *) _M_start = 0x00000001001008d0
(double *) _M_finish = 0x00000001001008f0
(double *) _M_end_of_storage = 0x00000001001008f0
}
}
}
(double) myDouble = 6.95322297580907e-310
}
Вы можете увидеть все встроенные в lldb средства форматирования типов с помощью type summary list
команда.
Как дополнение, вы должны были сказать:
(lldb) выражение набора точек наблюдения &myVector
даже если вы не можете «увидеть» значение
Кроме того, вы увидели сводку для std :: vector — получается, что мы не указывали, чтобы сводка либо не применялась к указателям, ни для отображения значения.
Я исправил LLDB с открытым исходным кодом, который позволит вам увидеть числовое значение указателя.
Возможно, действительно правильным решением будет специальный сводный формат для указателей, который показывает ценность & резюме. Тем не менее, я не слишком рад этому пути, поскольку он дублировал бы количество форматеров регулярных выражений, которые мы имеем в LLDB, что, возможно, не лучшее решение для повышения производительности.