почему освобождение выделенной памяти приведет к сбою моего проекта VC6?

StackOverflow https://stackoverflow.com/questions/609279

Вопрос

Сравните эти две во многом идентичные функции.Во-первых, память о buff выделяется с помощью _alloca.Это работает нормально.Во втором вместо _alloca используются calloc и free.Это дает сбой.

Странно то, что я использую технику calloc/free почти во всех других функциях упаковки GMP, которые у меня есть, и все они работают.Здесь этого не происходит.Есть идеи?

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-байтовые начальные и конечные датчики, которые затем проверить перед освобождением.

Однажды я провел неделю, пытаясь выяснить подобную вещь.Это было переполнение буфера, из-за которого указатель был настолько свободен, что улетел в лес.Rational Purify обнаружил проблему за минуту.

calloc потенциально может вернуть NULL в случае ошибки (например, нехватки памяти).Я бы рекомендовал проверить результат любой функции распределения памяти на NULL.Если оно равно NULL, выведите сообщение и затем выйдите (1).

_alloca возвращает память стека, поэтому прохождение мимо ее конца не обязательно перезапишет что-то важное.Запись после окончания выделения памяти в куче, скорее всего, перезапишет что-то важное.

Ваш код не делает ничего, чтобы гарантировать, что буфер будет по крайней мере такого же размера, как res будет отформатирован после деления n1 на n2 (или наоборот, поскольку я не знаю, что делает фактическая функция);он только гарантирует, что у него достаточно памяти для инициализированного res, что, вероятно, равно 1.Если n1/n2 в нем больше цифр, добро пожаловать в Крашвилл.

@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 в том месте кода, где он содержал ноль.Таким образом, я пытался вызвать нулевые байты, и бесплатно это не понравилось.В приведенном выше коде res на самом деле содержит что-то, что mpz_sizeinbase может работать с.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top