内部 realloc() 上的未定义行为

Undefined Behavior on inner realloc()

提问人:smellyourbooks 提问时间:6/22/2023 最后编辑:chqrliesmellyourbooks 更新时间:6/22/2023 访问量:55

问:

我正在尝试编写一个 PE 解析器,我的程序包含两个循环,如下所示:

    size_t i = 0;
    while (condition_1) {
        struct _IMAGE_IMPORT_DESCRIPTOR64 *importDescriptorArray = malloc(sizeof(struct _IMAGE_IMPORT_DESCRIPTOR64));

        struct _IMAGE_THUNK_DATA64 *originalFirstThunkArray = malloc(sizeof(struct _IMAGE_THUNK_DATA64));

        size_t originalFirstThunkArrayIndex = 0;

        originalFirstThunkArray[originalFirstThunkArrayIndex].u1.ordinal = some_value; //set to a computed value

        while (condition_2) {
            originalFirstThunkArrayIndex++;

            originalFirstThunkArray = realloc(originalFirstThunkArray, originalFirstThunkArrayIndex * sizeof(struct _IMAGE_THUNK_DATA64));

            originalFirstThunkArrayOffset += sizeof(QWORD); //each element has its address stored as a QWORD, so I have to iterate QWORD-at-a-time.
            originalFirstThunkArray[originalFirstThunkArrayIndex].u1.ordinal = reverse_endianess_u_int64_t(readQWord(file, originalFirstThunkArrayOffset, QWORD_Buffer));
        }

        i++;
        importDescriptorArray = realloc(importDescriptorArray, i * sizeof(struct _IMAGE_IMPORT_DESCRIPTOR64));
    }

我可以执行多次外部循环,它总是会给我正确的输出。然而,内部循环随机给我正确的答案或通过错误消息退出。nmalloc: Incorrect checksum for freed object

我的代码库无法复制/粘贴,但以下是结构的定义:

struct _IMAGE_IMPORT_DESCRIPTOR64 {
    union {
        DWORD Characteristics;
        IMAGE_THUNK_DATA32 OriginalFirstThunk;
    } u;
    DWORD timeDateStamp;
    DWORD forwarderChain;
    DWORD name;
    IMAGE_THUNK_DATA32 FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR64;

typedef struct _IMAGE_THUNK_DATA64 {
    union {
        QWORD forwarderString;
        QWORD function;
        QWORD ordinal;
        QWORD addressOfData;
    } u1;
} IMAGE_THUNK_DATA64;

我已经缩小了导致内部循环函数错误的行,但我不明白为什么 - 是因为我在重新分配后立即访问数组(但我正在更改索引以便编辑新分配空间的数据而不是其他内容)?realloc()

我试图做的是一次分配一个结构(以节省内存),因为除非在满足特定条件之前读取结构,否则没有其他方法可以知道它们存在多少个。

c malloc realloc

评论

1赞 smellyourbooks 6/22/2023
好吧,我是个白痴。我用零初始化,递增,然后越界访问。只需将 realloc 的索引值更改为 (index+1) 即可解决此问题,如下所示: originalFirstThunkArray = realloc(originalFirstThunkArray, (originalFirstThunkArrayIndex+1)*sizeof(struct _IMAGE_THUNK_DATA64));importDescriptorArray = realloc(importDescriptorArray, (i+1)*sizeof(struct _IMAGE_IMPORT_DESCRIPTOR64));
1赞 Lundin 6/22/2023
在表单中使用简单、可读的循环往往会自动修复很多这样的错误。forfor(size_t i=0; i<n; i++)
0赞 Jonathan Leffler 6/22/2023
请注意,该成语是初始内存泄漏。如果重新分配失败,您将无法再访问旧数据。使用或关于此。old_data = realloc(old_data, new_size);void *new_data = realloc(old_data, new_size); if (new_data == NULL) { …deal with error… } old_data = new_data; old_size = new_size;

答:

2赞 chqrlie 6/22/2023 #1

originalFirstThunkArrayIndex是数组最后一个元素的索引,而不是数组的长度。您应该在循环中使用一个额外的元素进行重新分配:

    originalFirstThunkArray = realloc(originalFirstThunkArray,
                                      (originalFirstThunkArrayIndex + 1) *
                                      sizeof(struct _IMAGE_THUNK_DATA64));

请注意,您的标识符很长,使代码难以阅读。

和...iimportDescriptorArray

最后,一个更重要的问题:在外部循环体中本地定义,因此在每次迭代时都会丢失其值。importDescriptorArraywhile

评论

1赞 smellyourbooks 6/22/2023
是的,谢谢,我想我们同时意识到了索引错误!而且我错误地将外部 while 循环放入内部 - 为复制/粘贴错误道歉 - 正如您正确指出的那样,这很可能是由于我这边的命名实践不佳。吸取了教训!importDescriptorArray