Question

Comparez ces deux fonctions en grande partie identiques. Dans le premier cas, la mémoire pour buff est allouée à l'aide de _alloca. Cela fonctionne bien. Dans le second, calloc et free sont utilisés à la place de _alloca. Cela se bloque.

Ce qui est étrange, c’est que j’utilise la technique calloc / free dans presque toutes les autres fonctions de wrapping GMP que j’ai et qu’elles fonctionnent toutes. Ici, ils ne le font pas. Des idées?

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;
}
Était-ce utile?

La solution

Ajoutez une journalisation et videz tout le long du chemin pour trouver ce qui ne va pas. C’est généralement plus efficace que d’essayer de deviner.

Autres conseils

Cela n’est peut-être pas lié, mais ce type de "fonctionne dans un sens mais pas dans l’autre" indique souvent un bogue qui survient dans une situation mais provoque une erreur fatale dans une autre.

Si vous pensez que la mémoire est susceptible d’être écrasée, vous pouvez essayer d’attribuer 8 octets supplémentaires dans la mémoire tampon et d’écrire des sentinelles de début et de fin de 4 octets que vous devez ensuite vérifier avant de les libérer.

Une fois, j'ai passé une semaine à essayer de résoudre un problème similaire. C'était un débordement de mémoire tampon qui a détruit le pointeur de manière à ce que Free se rende dans les bois. Rational purify a trouvé le problème en une minute.

calloc pourrait éventuellement renvoyer NULL en cas d'erreur (manque de mémoire, par exemple). Je recommanderais de vérifier le résultat de toute fonction d'allocation de mémoire contre NULL. S'il s'agit de NULL, imprimez un message puis quittez (1).

_alloca renvoie la mémoire de pile. Par conséquent, écraser après la fin de celle-ci ne remplace pas nécessairement un élément important. Écrire au-delà de la fin d'une allocation de mémoire vive remplacera probablement quelque chose d'important.

Votre code ne fait rien pour garantir que le tampon est au moins aussi grand que res serait mis en forme après la division de n1 par n2 (ou l'inverse, car je ne sais pas quelle est la fonction réelle Est-ce que); cela garantit seulement qu'il dispose de suffisamment de mémoire pour un res initialisé, ce qui est probablement 1. Si n1 / n2 a plus de chiffres que cela, bienvenue dans crashville.

@johnny a signalé quelque chose d'assez embarrassant, ce qui a nécessité une réécriture du code. (Voici où il serait utile de cocher un commentaire.)

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

Dans les incarnations précédentes, la mémoire était allouée en fonction de la valeur de res au niveau du code où elle contenait zéro. Ainsi, j'essayais d'appeler zéro octets en calloc et free ne l'aimait pas. Dans le code ci-dessus, res contient en réalité quelque chose avec lequel mpz_sizeinbase peut fonctionner.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top