0

比较这两个基本相同的功能。首先,buff使用 _alloca 分配内存。这工作正常。第二种,使用 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;
}
4

6 回答 6

1

这可能是不相关的,但是这种类型的“以一种方式工作,但不能以另一种方式工作”通常表示一个错误,它恰好在一种情况下吱吱作响,但在另一种情况下会导致致命错误。

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

于 2009-03-04T05:01:24.210 回答
1

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

于 2009-03-04T05:05:53.217 回答
1

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

于 2009-03-04T05:13:49.547 回答
1

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

于 2009-03-04T05:17:15.793 回答
0

_alloca返回堆栈内存,因此踩到它的末尾可能不一定会覆盖重要的东西。在堆内存分配结束后写入将更有可能覆盖一些重要的东西。

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

于 2009-03-04T22:18:57.430 回答
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代码中包含零的点的值分配的。因此,我试图调用零字节并且 free 不喜欢它。在上面的代码中,res实际上包含了一些mpz_sizeinbase可以使用的东西。

于 2009-03-06T14:22:12.457 回答