(Visual C++) Память динамического выделения не является допустимым указателем после удаления указателя
-
27-10-2019 - |
Вопрос
У меня есть программа, когда я нажимаю кнопку «Загрузить», программа создает новый поток для загрузки веб-страниц и сохраняет его в динамическом размещении. char*
переменная.
Но теперь я нажимаю «Загрузить», программа показывает следующую информацию:
---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Assertion Failed!
Program: d:\dev\debug\test.exe
File: dbgheap.c
Line: 1279
Expression: _CrtIsValidHeapPointer(pUserData)
Кажется, проблема связана с проблемой выделения или освобождения кучи.
void SomeClass::get()
{
buf = this->download(url);
while (some condition)
{
......
......
bufContent = this->download(url);
......
......
sql = new char[sqlSize];
ZeroMemory(sql,sqlSize);
sql_utf8 = new char[sqlSize*2];
ZeroMemory(sql_utf8,sqlSize*2);
......
......
delete[] bufContent;bufContent=NULL;
delete[] sql;
delete[] sql_utf8;
}
delete[] buf; buf=NULL;//debug run to here, get Assertion Failed error
}
download
функция:
char* SomeClass::download(TCHAR* url)
{
char * pBuf = NULL ;
int nBufLen = 0 ;
TRY
{
// connection
CInternetSession sess ;
sess.SetOption (INTERNET_OPTION_CONNECT_TIMEOUT, 30 * 1000) ;
sess.SetOption (INTERNET_OPTION_CONNECT_BACKOFF, 1000) ;
sess.SetOption (INTERNET_OPTION_CONNECT_RETRIES, 1) ;
DWORD dwFlag = INTERNET_FLAG_TRANSFER_BINARY|INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_RELOAD ;
CHttpFile * pF = (CHttpFile*)sess.OpenURL(url, 1, dwFlag); ASSERT(pF);
if (!pF)
{AfxThrowInternetException(1);}
// connection status
CString str ;
pF->QueryInfo (HTTP_QUERY_STATUS_CODE, str) ;
if (str != _T("200"))
{
pF->Close() ;
delete pF ;
AfxThrowInternetException(1);
}
// start QzoneBlog
int nLen,nLenCopy;
pF->QueryInfo (HTTP_QUERY_CONTENT_LENGTH, str) ; // file's length
if (_ttoi(str))
{
// know file's size
nLenCopy = nLen = (nBufLen = _ttoi(str)) ;
char * p = (pBuf = new char[nLen+8]) ;
ZeroMemory (p, nLen+8) ;
while (TRUE)
{
int n = pF->Read (p, (nLen < 1024) ? nLen : 1024) ;
if (n <= 0)
break ; // success exit
p += n ; nLen -= n ;
}
// interrupted
if (nLen != 0)
{
//delete[] pBuf; pBuf=NULL;
nBufLen = 0 ;
}
}
pF->Close() ;
delete pF ;
return pBuf;
}
CATCH_ALL(e) {
return 0;
}
END_CATCH_ALL
}
Решение
Следующие инструкции:
sql = new char[sqlSize];
ZeroMemory(sql,sizeof(sql));
Выделите количество байтов, а затем очистите первые четыре из них, поскольку Sizeof (SQL) равен 4. Так что, если SQLSize меньше 4, вы распределяете менее 4 байтов, а затем вы нуждаетесь в 4 байтах, таким образом, искажаясь. Память. Вам нужно:
ZeroMemory(sql,sqlSize);
Также: если _ttoi(str)
Выйдет из строя, вы не распределяете буфер, но вы возвращаете его, и я предполагаю, что вы приступите к тому, чтобы попытаться освободить его. Это, вероятно, причина неверного исключения указателя.
Другие советы
Это результат переполнения памяти.Вы записали часть памяти, которая находится за пределами выделенного диапазона.
Что-то вроде:
char *buf = new char[4];
buf[4]=23; // actual error
delete[] buf; // runtime error (Debug Assertion Fail)
вероятно, выдаст такую ошибку.
Это будет трудно обнаружить в большой программе, поскольку ошибка подтверждения отладки происходит тогда, когда возникает фактическая ошибка.Я бы предложил использовать некоторые инструменты, такие как Верификатор приложений чтобы следить за своей памятью, будет ли программа работать.Application Verifier остановит программу при возникновении неисправности памяти.