Почему происходит сбой моей функции после изменения версий Visual Studio? - PullRequest
1 голос
/ 10 апреля 2019

У меня есть старое 32-разрядное приложение MFC на C ++, написанное для Visual Studio 2010. Оно работало без проблем. Теперь мне пришлось обновиться до Visual Studio 2017, и он довольно часто вылетает, когда я нажимаю в окне древовидной структуры. У меня есть файл DMP, и когда я открываю его, я вижу, что он падает здесь:

 BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
 {
     ENSURE(this != NULL);
     // it better be in valid memory, at least for CObject size
     ASSERT(AfxIsValidAddress(this, sizeof(CObject)));

     // simple SI case
         CRuntimeClass* pClassThis = GetRuntimeClass(); //---->HERE Crash 

     ENSURE(pClassThis);
     return pClassThis->IsDerivedFrom(pClass);
 }

Когда я возвращаюсь к списку вызовов, я заканчиваю здесь:

//m_pTheModel is initialized with NULL
if (bValidValue == true)
    m_pTheModel = GetModel((WORD)lHint);

if (m_pTheModel == NULL || !AfxIsValidAddress(m_pTheModel, sizeof(m_pTheModel)))
{
   lock.Unlock();
   return;
}

try
{
    if ((m_pTheModel->IsKindOf(RUNTIME_CLASS(CMyClassModel))))
    ...
}
catch (...)
{
}

m_pTheModel не NULL, но когда я смотрю на значения в отладчике, для некоторых значений память не читается.

В чем может быть проблема? Со старой версией visual studio у меня не было этой проблемы. Я только перекомпилировал этот проект, и мне пришлось установить целевую операционную систему на Windows XP.

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

Я также не понимаю, почему я не могу уловить это нарушение доступа с помощью своего try-catch вокруг этого.

Обновление: Я нашел причину. Это был strcpy, который переписывает мой указатель.

1 Ответ

2 голосов
/ 10 апреля 2019

Использование AfxIsValidAddress очень актуально.

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

Хуже того, он работает только в отладочных сборках .

В сборках без отладки - ненулевое значение, если lp не равен NULL; в противном случае 0.

Это не обещает, что это то, что вы хотите вообще. Если вы удалите объект, память, вероятно, все еще находится внутри приложения, готовая к повторному использованию, не возвращена в операционную систему, и такие вещи, как AfxIsValidAddress, вернут true. Хуже того, когда ваш распределитель действительно использует эту память, он все равно будет возвращать true, тогда как указатель фактически теперь ссылается на какой-то совершенно другой, неизвестный объект, что приводит к повреждению кучи.

Это относится ко всем подобным функциям, таким как IsBadReadPtr. У Раймонда Чена есть запись в блоге Microsoft IsBadXxxPtr действительно должен называться CrashProgramRandomly .

Возможно, вам придется отладить это в IDE и найти конкретную проблему, это почти наверняка использование после освобождения или более серьезная проблема в других местах программы, перезаписывающей объект. Можете ли вы создать его непосредственно в IDE вместо получения файла дампа?

Я также не понимаю, почему я не могу поймать это нарушение доступа с помощью своего try-catch вокруг этого

Нарушения доступа, и такие на разных платформах не являются исключениями C ++. А поскольку они обычно происходят только после повреждения памяти программ, восстановить их практически невозможно. Как правило, существуют специальные средства взаимодействия с ними.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...