有什么可以在通话中解释堆损坏给free()? [英] What can explain heap corruption on a call to free()?

查看:167
本文介绍了有什么可以在通话中解释堆损坏给free()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在调试,现在天大跌,与维护者的这里)。我花了一些时间来调查,所以我会尽力使这个问题有趣和翔实。

I have been debugging a crash for days now, that occurs in the depths of OpenSSL (discussion with the maintainers here). I took some time investigating so I'll try to make this question interesting and informative.

第一,给予一定的情况下,我国重现崩溃最小样本情况如下:

First and to give some context, my minimal-sample that reproduces the crash is as follow:

#include <openssl/crypto.h>
#include <openssl/ec.h>
#include <openssl/objects.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/engine.h>

int main()
{
    ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); 
    ENGINE_load_builtin_engines();

    EC_GROUP* group = EC_GROUP_new_by_curve_name(NID_sect571k1);
    EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
    EC_KEY* eckey = EC_KEY_new();
    EC_KEY_set_group(eckey, group);
    EC_KEY_generate_key(eckey);
    BIO* out = BIO_new(BIO_s_file());
    BIO_set_fp(out, stdout, BIO_NOCLOSE);
    PEM_write_bio_ECPrivateKey(out, eckey, NULL, NULL, 0, NULL, NULL); // <= CRASH.
}

基本上,这code生成一个椭圆曲线密钥,并试图将其输出到标准输出。类似code可以在 openssl.exe ecparam 发现和维基在线。它工作正常,在Linux(Valgrind的报告没有错误的话)。 它只崩溃在Windows(的Visual Studio 2013 - 64)我确信正确的运行时间分别链接到的( / MD 在我的情况,所有的依赖关系)。

Basically, this code generates an Elliptic Curve key and tries to output it to stdout. Similar code can be found in openssl.exe ecparam and on Wikis online. It works fine on Linux (valgrind reports no error at all). It only crashes on Windows (Visual Studio 2013 - x64). I made sure the proper runtimes were linked-to (/MD in my case, for all dependencies).

由于担心没有邪恶,我在x64的调试重新编译OpenSSL的(这时候连接一切<​​code> / MDD ),并通过code走到找到有问题的集指令。我的搜索使我这个code(在OpenSSL的 tasn_fre.c 文件):

Fearing no evil, I recompiled OpenSSL in x64-debug (this time linking everything in /MDd), and stepped through the code to find the offending set of instructions. My search led me to this code (in OpenSSL's tasn_fre.c file):

static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine)
{
    // ... some code, not really relevant.
    tt = it->templates + it->tcount - 1;

    for (i = 0; i < it->tcount; tt--, i++) {
        ASN1_VALUE **pseqval;
        seqtt = asn1_do_adb(pval, tt, 0);
        if (!seqtt) continue;

        pseqval = asn1_get_field_ptr(pval, seqtt);
        ASN1_template_free(pseqval, seqtt);
    }
    if (asn1_cb)
        asn1_cb(ASN1_OP_FREE_POST, pval, it, NULL);
    if (!combine) {
        OPENSSL_free(*pval); // <= CRASH OCCURS ON free()
        *pval = NULL;
    }
    // Some more code...
}

对于那些不太熟悉OpenSSL和它的ASN.1程序,基本上这是什么 -loop做的是,它进入低谷全部序列的元素(首发随着最后一个元素)和删除它们(稍后更多)。

For those not too familiar with OpenSSL and it's ASN.1 routines, basically what this for-loop does is that it goes trough all the elements of a sequence (starting with the last element) and "deletes" them (more on that later).

在崩溃发生权利之前,3个元素的顺序(在删除* PVAL ,这是 0x00000053379575E0 )。纵观内存,可以看到以下情况发生:

Right before the crash happens, a sequence of 3 elements is deleted (at *pval, which is 0x00000053379575E0). Looking at the memory, one can see the following things happen:

的序列是12个字节长,每个元素是4字节长(在此情况下, 2 5 10 )。在每个循环迭代,元素在这样的背景下删除的OpenSSL的(,既不删除免费分别称为:他们只是设置为特定值)。下面是内存的外观一次迭代后:

The sequence is 12 bytes long, each element being 4-bytes long (in this case, 2, 5, and 10). On each loop iteration, elements are "deleted" by OpenSSL (in this context, neither delete or free are called: they are just set to a specific value). Here is how the memory looks after one iteration:

最后一个元素在这里被设置为 FF FF FF 7F 我以为是当内存后未分配的OpenSSL的保证没有关键信息的方式泄漏。

The last element here was set to ff ff ff 7f which I assume is OpenSSL's way of ensuring no key information leaks when the memory is unallocated later.

在循环后右(和调用 OPENSSL_free()之前),内存为如下:

Right after the loop (and before the call to OPENSSL_free()), the memory is as follow:

所有的元素被设置为 FF FF FF 7F asn1_cb NULL 所以没有调用。即继续接下来的事情是调用 OPENSSL_free(* PVAL)

All elements were set to ff ff ff 7f, asn1_cb is NULL so no call is made. The next thing that goes on is the call to OPENSSL_free(*pval).

此调用免费()上似乎是一个有效的&安培;内存分配失败,并导致执行与消息中止:堆损坏检测出

This call to free() on what seems to be a valid & allocated memory fails and cause the execution to abort with a message: "HEAP CORRUPTION DETECTED".

好奇,我勾搭成的malloc 的realloc 免费(如OpenSSL的许可),以确保这不是一个双免费或从未分配的内存免费。原来,内存 0x00000053379575E0 真的是确实分配(和以前从未释放)一个12字节的块。

Curious about this, I hooked into malloc, realloc and free (as OpenSSL permits) to ensure this wasn't a double-free or a free on never-allocated memory. It turns out the memory at 0x00000053379575E0 really is a 12 bytes block that was indeed allocated (and never freed before).

我在亏损搞清楚这里会发生什么:从我的研究,似乎免费()上失败这是通常由<$ C $返回一个指针C>的malloc()。除此之外,此存储位置被写入到几个指令之前没有这些确认该存储器被正确分配的假设任何问题。

I'm at loss figuring out what happens here: from my research, it seems that free() fails on a pointer that was normally returned by malloc(). In addition to that, this memory location was being written to a couple of instructions before without any problem which confirms the hypothesis that the memory be correctly allocated.

我知道这很难,如果不是不可能的,没有所有的信息,远程调试,但我不知道我的下一个步骤应该是什么。

I know it's hard, if not impossible, to debug remotely without all the information but I have no idea what my next steps should be.

所以我的问题是:如何究竟是这个堆损坏由Visual Studio的调试器检测?什么是从呼叫始发时,免费()

So my question is: how exactly is this "HEAP CORRUPTION" detected by Visual Studio's debugger ? What are all the possible causes for it when originating from a call to free() ?

推荐答案

在一般的可能性包括:


  1. 复制免费的。

  2. 的复制免费的。

  3. (最有可能)您的code写超出分配的存储块的限制,无论是之前的开始或结束之后。 的malloc()和朋友把多余的记录信息在这里,如大小,可能是一个完整性检查,您将通过覆盖失败。

  4. 解放出来的东西,一直没的malloc() -ed。

  5. 继续写信给那些已经被一大块免费() -d。

  1. Duplicate free.
  2. Prior duplicate free.
  3. (Most probable) Your code wrote beyond the limits of the allocated chunk of memory, either before the beginning or after the end. malloc() and friends put extra bookkeeping information in here, such as the size, and probably a sanity-check, which you will fail by overwriting.
  4. Freeing something that hadn't been malloc()-ed.
  5. Continuing to write to a chunk that had already been free()-d.

这篇关于有什么可以在通话中解释堆损坏给free()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆