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

问题描述:

比较这两个基本相同的功能。首先,使用_alloca分配buff的内存。这工作正常。在第二个中,使用calloc和free来代替_alloca。这崩溃了。为什么释放calloc'ed内存会导致我的VC6项目崩溃?

奇怪的是,我用的是释放calloc /免费技术在几乎所有其他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; 
} 
+0

核心转储说什么?或者你没有得到一个? – hhafez 2009-03-04 05:00:27

+0

BTW,_alloca已过时,使用_malloca代替 – 2009-03-04 05:03:16

添加日志记录并转储所有内容以查找出错的地方。这通常比试图猜测更有效。

这可能是无关的,但这种“工作的一种方式而不是其他”往往预示着恰好由吱吱叫的错误在一种情况下,但在另一种情况下导致致命错误。

如果您怀疑内存覆盖可能发生,你可以尝试在缓冲区分配一个额外的8个字节,写4个字节的开始和结束的哨兵,你再释放前检查。

我曾经花了一个星期的时间试图找出类似的事情。这是一个缓冲区溢出,把指针扔到了树林里。理性净化在一分钟内找到了问题。

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

_alloca返回堆栈内存,所以跺脚过去它的结束未必覆盖重要的东西。写入超过堆内存分配的结尾将更可能覆盖重要的内容。

您的代码不会确保缓冲区至少与一样大,将n1除以n2后格式化(反之亦然,因为我不知道实际功能是什么)。它只能确保它有足够的内存用于初始化res,这可能是1.如果n1/n2的位数多于此值,欢迎致电crashville。

@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零字节,并且免费不喜欢它。在上面的代码中,res实际上包含mpz_sizeinbase可以使用的东西。