为什么释放calloc'ed内存崩溃我的VC6项目?

时间:2009-03-04 04:55:04

标签: visual-c++ memory-management vc6 gmp

比较这两个基本相同的功能。在第一个中,使用_alloca分配buff的内存。这很好用。在第二种情况下,使用calloc和free代替_alloca。这崩溃了。

奇怪的是,我在几乎所有其他GMP包装函数中使用calloc / free技术,它们都有效。他们在这里没有。有什么想法吗?

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

6 个答案:

答案 0 :(得分:1)

它可能是无关的,但是这种“单向工作而不是另一种方式”通常表示在一种情况下恰好发出吱吱声但在另一种情况下导致致命错误的错误。

如果您怀疑可能正在发生内存覆盖,您可以尝试在缓冲区中分配额外的8个字节并写入4字节的开始和结束标记,然后在释放之前检查它们。

答案 1 :(得分:1)

我曾经花了一周的时间试图弄清楚类似的事情。这是一个缓冲区溢出,破坏了指针所以自由进入了树林。 Rational purify在一分钟内发现了这个问题。

答案 2 :(得分:1)

添加日志记录并转发所有内容以找出问题所在。这通常比尝试猜测更有效。

答案 3 :(得分:1)

如果出现错误(例如内存不足),

calloc可能会返回NULL。我建议检查任何内存分配函数的结果对NULL。如果为NULL,则打印一条消息,然后退出(1)。

答案 4 :(得分:0)

_alloca返回堆栈内存,因此在它结束时踩踏可能不一定会覆盖重要的东西。在堆内存分配结束时写入更有可能覆盖重要内容。

你的代码没有做任何事情来确保缓冲区至少与{n = n}之后格式化为res一样大(反之亦然,因为我不知道实际函数的作用);它只能确保它有足够的内存用于初始化res,这可能是1.如果n1/n2的数字多于那个,欢迎来到crashville。

答案 5 :(得分:0)

@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的值进行分配的。因此,我试图calloc零字节和free不喜欢它。在上面的代码中,res实际上包含mpz_sizeinbase可以使用的内容。