por que liberar memória calloc'ed bater meu projeto VC6?
-
03-07-2019 - |
Pergunta
Compare estas duas funções em grande parte idênticos. No primeiro, a memória para buff
é alocada usando _alloca. Isso funciona bem. Na segunda, calloc e livre são usados ??em vez de _alloca. Esta falha.
O estranho é que eu uso a técnica calloc / livre em quase todas as outras funções GMP embrulho que tenho e todos eles trabalham. Aqui eles não. Alguma idéia?
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;
}
Solução
Adicionar um registro e tudo o despejo ao longo do caminho para encontrar o que está errado. Isso geralmente é mais eficiente do que tentar adivinhar.
Outras dicas
Pode ser independentes, mas este tipo de "trabalha de uma maneira, mas não a outra", muitas vezes indica um bug que só acontece de guincho por numa situação, mas causa um erro fatal em outro.
Se você suspeitar de uma substituição de memória pode estar ocorrendo você pode tentar alocar um extra de 8-bytes no buffer e escrever sentinelas de início e fim de 4 bytes que você então verificam antes de liberar.
Uma vez eu passei uma semana tentando descobrir uma coisa semelhante. Foi uma saturação de buffer que Trashed o ponteiro tão livre ia para dentro da floresta. Purify Rational encontrei o problema em um minuto.
calloc poderia retornar NULL se há um erro (como a falta de memória). Eu recomendaria verificar o resultado de qualquer função de alocação de memória contra NULL. Se for NULL, imprimir uma mensagem e, em seguida, exit (1).
_alloca
retornos pilha, de modo pisando passado o fim de alguma coisa pode não necessariamente de substituição importante. Escrevendo após o final de uma alocação de memória heap será mais provável sobrescrever algo importante.
Seu código não faz nada para garantir que o buffer é pelo menos tão grande quanto res
iria ser formatado para depois de dividir n1 por n2 (ou vice-versa, como eu não sei o que a função real faz); ele só garante que ele tem memória suficiente para um res
initialiazed, que é provavelmente 1. Se n1/n2
tem mais dígitos do que isso, bem-vindo ao crashville.
@johnny apontou algo bastante embaraçoso, que exigiu uma reescrita do código. (Aqui é onde ser capaz de assinalar um comentário seria útil.)
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;
}
Nos encarnações anteriores, a memória estava sendo alocados de acordo com o valor de res
no ponto no código onde ele continha zero. Assim eu estava tentando calloc zero bytes e livre não gostou dele. No código acima, res
realmente contém algo que mpz_sizeinbase
pode trabalhar com ele.