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;
}
Foi útil?

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).

memória

_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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top