Повреждение стека отладки - PullRequest
11 голосов
/ 03 сентября 2011

Теперь я отлаживаю большой проект с повреждением стека: приложение не работает.

Я хотел бы знать, как найти (отладить) такой код повреждения стека в Visual Studio 2010?

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

void foo()
{
    int i = 10;
    int *p = &i;
    p[-2] = 100;
}

Обновление

Обратите внимание, что это простопример.Мне нужно найти такой плохой код в текущем проекте.

Ответы [ 3 ]

5 голосов
/ 03 сентября 2011

Есть одна техника, которая может быть очень эффективна с такими ошибками, но она будет работать только на подмножестве их, которые имеют несколько характеристик:

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

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

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

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

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

2 голосов
/ 03 сентября 2011

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

Если это так, то происходит сбой, потому что он создает Неопределенное поведение , поскольку индекс -2 указывает на неизвестное место в памяти.

Чтобы ответить на вопрос о профилировании вашей заявки:
Вы можете использовать Rational Purify Plus для Visual Studio для проверки переопределений памяти и ошибок доступа.

0 голосов
/ 03 сентября 2011

Это UB: p[-2] = 100;

Вы можете получить доступ к p с помощью operator[] таким (p[i]) способом, но в этом случае i является недопустимым значением. Таким образом, p[-2] указывает на недопустимое расположение в памяти и вызывает неопределенное поведение.

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

...