Calloc의 메모리를 해제하는 이유는 왜 내 VC6 프로젝트가 충돌합니까?
-
03-07-2019 - |
문제
이 두 가지 크게 동일한 기능을 비교하십시오. 첫 번째로, 메모리 buff
_alloca를 사용하여 할당됩니다. 이것은 잘 작동합니다. 두 번째로, 콜록과 무료는 _alloca 대신 사용됩니다. 이것은 충돌합니다.
이상한 점은 내가 가지고있는 거의 모든 GMP 랩핑 기능에서 Calloc/Free 기술을 사용하고 모두 작동한다는 것입니다. 여기 그들은 그렇지 않습니다. 어떤 아이디어?
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 바이트 시작 및 종료 센티넬을 작성하여 자유롭게하기 전에 확인할 수 있습니다.
나는 한 번 비슷한 것을 알아 내려고 일주일을 보냈다. 포인터를 쓰레기를 버린 것은 버퍼 오버런이었다. 합리적 정수는 1 분 안에이 문제를 발견했습니다.
오류가 있으면 (예 : 메모리 부족) Calloc은 잠재적으로 NULL을 반환 할 수 있습니다. NULL에 대한 메모리 할당 함수의 결과를 확인하는 것이 좋습니다. NULL 인 경우 메시지를 인쇄 한 다음 (1)을 종료하십시오.
_alloca
스택 메모리를 반환하므로 끝을 지나서 중요한 것을 덮어 쓰는 것은 아닙니다. 힙 메모리 할당 끝을 지나서 쓰면 중요한 것을 덮어 쓸 가능성이 높습니다.
코드는 버퍼가 최소한 res
N1을 N2로 나눈 후 형식화됩니다 (또는 실제 함수가 무엇을하는지 모르기 때문에 그 반대도 마찬가지). 그것은 초기의 메모리에 충분한 메모리를 보장합니다. res
, 아마도 1 일 것입니다 n1/n2
그보다 더 많은 자리가 있습니다. Crashville에 오신 것을 환영합니다.
@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
코드의 지점에서 0이 포함되어 있습니다. 그래서 나는 제로 제로 바이트를 부르려고했고 무료는 그것을 좋아하지 않았다. 위 코드에서 res
실제로 무언가가 들어 있습니다 mpz_sizeinbase
함께 일할 수 있습니다.