Pregunta

Compara estas dos funciones en gran parte idénticas. En el primero, la memoria para buff se asigna usando _alloca. Esto funciona bien En el segundo, se usan calloc y free en lugar de _alloca. Esto se estrella.

Lo extraño es que uso la técnica calloc / free en casi todas las demás funciones de envoltura GMP que tengo y todas funcionan. Aquí no lo hacen. ¿Alguna idea?

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

Solución

Agregue el registro y descargue todo en el camino para encontrar lo que está mal. Esto suele ser más eficiente que intentar adivinar.

Otros consejos

Puede no estar relacionado, pero este tipo de " funciona de una manera pero no de la otra " a menudo indica un error que simplemente pasa por alto en una situación pero causa un error fatal en otra.

Si sospecha que se está produciendo una sobrescritura de memoria, puede intentar asignar 8 bytes adicionales en el búfer y escribir los centinelas de inicio y fin de 4 bytes que luego verifica antes de liberar.

Una vez pasé una semana tratando de descubrir algo similar. Fue un desbordamiento de búfer que destrozó el puntero tan libre que se iba al bosque. Rational Purify encontró el problema en un minuto.

calloc podría devolver NULL si hay un error (como falta de memoria). Recomendaría verificar el resultado de cualquier función de asignación de memoria contra NULL. Si es NULL, imprima un mensaje y luego salga (1).

_alloca devuelve memoria de pila, por lo que pisotear el final no necesariamente sobrescribe algo importante. Escribir más allá del final de una asignación de memoria del montón más probablemente sobrescribirá algo importante.

Su código no hace nada para garantizar que el búfer sea al menos tan grande como el formato de res después de dividir n1 por n2 (o viceversa, ya que no sé cuál es la función real hace); solo asegura que tiene suficiente memoria para una res inicializada, que probablemente sea 1. Si n1 / n2 tiene más dígitos que eso, bienvenido a crashville.

@johnny señaló algo bastante vergonzoso, que requirió una reescritura del código. (Aquí es útil poder marcar un comentario).

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;
}

En las encarnaciones anteriores, la memoria se asignaba de acuerdo con el valor de res en el punto del código donde contenía cero. Por lo tanto, estaba tratando de calcular bytes cero y gratis no me gustó. En el código anterior, res en realidad contiene algo con lo que mpz_sizeinbase puede funcionar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top