почему освобождение выделенной памяти приведет к сбою моего проекта VC6?
-
03-07-2019 - |
Вопрос
Сравните эти две во многом идентичные функции.Во-первых, память о buff
выделяется с помощью _alloca.Это работает нормально.Во втором вместо _alloca используются calloc и free.Это дает сбой.
Странно то, что я использую технику calloc/free почти во всех других функциях упаковки GMP, которые у меня есть, и все они работают.Здесь этого не происходит.Есть идеи?
1:
#define Z(x) mpz_t (x); mpz_init( (x) );
#define BUFF_SIZE (1024 * 32)
BSTR __stdcall IBIGDIV(BSTR p1, BSTR p2 ) {
USES_CONVERSION;
Z(n1);
Z(n2);
Z(res);
char * buff = (char *) _alloca( mpz_sizeinbase( res, 10 ) + 2 );
LPSTR sNum1 = W2A( p1 );
LPSTR sNum2 = W2A( p2 );
mpz_set_str( n1, sNum1, 10 );
mpz_set_str( n2, sNum2, 10 );
if ( mpz_sgn( n2 ) != 0 ) {
mpz_div( res, n1, n2 );
mpz_get_str(buff, 10, res);
} else {
strcpy( buff, "-0" );
}
BSTR bResult = _com_util::ConvertStringToBSTR( buff );
return bResult;
}
2:
#define Z(x) mpz_t (x); mpz_init( (x) );
#define BUFF_SIZE (1024 * 32)
BSTR __stdcall IBIGDIV(BSTR p1, BSTR p2 ) {
USES_CONVERSION;
Z(n1);
Z(n2);
Z(res);
char * buff = (char *) calloc( mpz_sizeinbase( res, 10 ) + 2, sizeof( char ) );
LPSTR sNum1 = W2A( p1 );
LPSTR sNum2 = W2A( p2 );
mpz_set_str( n1, sNum1, 10 );
mpz_set_str( n2, sNum2, 10 );
if ( mpz_sgn( n2 ) != 0 ) {
mpz_div( res, n1, n2 );
mpz_get_str(buff, 10, res);
} else {
strcpy( buff, "-0" );
}
BSTR bResult = _com_util::ConvertStringToBSTR( buff );
free( buff );
return bResult;
}
Решение
Добавьте ведение журнала и сбрасывайте все по пути, чтобы найти, что пошло не так.Обычно это более эффективно, чем пытаться угадать.
Другие советы
Это может быть не связано, но этот тип «работает в одну сторону, но не в другую» часто указывает на ошибку, которая просто появляется в одной ситуации, но вызывает фатальную ошибку в другой.
Если вы подозреваете, что может произойти перезапись памяти, вы можете попробовать выделить дополнительные 8 байтов в буфере и записать 4-байтовые начальные и конечные датчики, которые затем проверить перед освобождением.
Однажды я провел неделю, пытаясь выяснить подобную вещь.Это было переполнение буфера, из-за которого указатель был настолько свободен, что улетел в лес.Rational Purify обнаружил проблему за минуту.
calloc потенциально может вернуть NULL в случае ошибки (например, нехватки памяти).Я бы рекомендовал проверить результат любой функции распределения памяти на NULL.Если оно равно NULL, выведите сообщение и затем выйдите (1).
_alloca
возвращает память стека, поэтому прохождение мимо ее конца не обязательно перезапишет что-то важное.Запись после окончания выделения памяти в куче, скорее всего, перезапишет что-то важное.
Ваш код не делает ничего, чтобы гарантировать, что буфер будет по крайней мере такого же размера, как res
будет отформатирован после деления n1 на n2 (или наоборот, поскольку я не знаю, что делает фактическая функция);он только гарантирует, что у него достаточно памяти для инициализированного res
, что, вероятно, равно 1.Если n1/n2
в нем больше цифр, добро пожаловать в Крашвилл.
@johnny указал на что-то довольно неловкое, что потребовало переписать код.(Здесь будет полезна возможность отметить комментарий.)
BSTR __stdcall IBIGDIV(BSTR p1, BSTR p2 ) {
USES_CONVERSION;
Z(n1);
Z(n2);
Z(res);
char * buff;
LPSTR sNum1 = W2A( p1 );
LPSTR sNum2 = W2A( p2 );
mpz_set_str( n1, sNum1, 10 );
mpz_set_str( n2, sNum2, 10 );
if ( mpz_sgn( n2 ) != 0 ) {
mpz_div( res, n1, n2 );
buff = (char *) calloc( mpz_sizeinbase( res, 10 ) + 2, sizeof( char ) );
mpz_get_str(buff, 10, res);
} else {
buff = (char *) calloc( 3, sizeof( char ) );
strcpy( buff, "-0" );
}
BSTR bResult = _com_util::ConvertStringToBSTR( buff );
free( buff );
return bResult;
}
В предыдущих воплощениях память распределялась в соответствии со значением res
в том месте кода, где он содержал ноль.Таким образом, я пытался вызвать нулевые байты, и бесплатно это не понравилось.В приведенном выше коде res
на самом деле содержит что-то, что mpz_sizeinbase
может работать с.