使用malloc和realloc动态重分配结构体数组的技术求助
解决用malloc/realloc创建ELF节结构体数组的问题
我看你在尝试用malloc和realloc构建ELF节的结构体数组时遇到了瓶颈,从你给出的代码片段来看,核心问题是缺少动态分配数组的关键逻辑,同时结构体成员的指针处理也存在潜在的生命周期风险。下面我会一步步帮你梳理和修正这些问题:
1. 先搞定结构体数组的初始化(malloc)
在main函数里,你已经算出了sections_count,这时候首先要分配一块能装下sections_count个struct _section的内存:
// 拿到sections_count之后执行 struct _section *exe_sect_array = malloc(sections_count * sizeof(struct _section)); if (exe_sect_array == NULL) { perror("malloc failed"); // 记得先清理已打开的ELF资源、关闭文件再退出 exit(EXIT_FAILURE); }
2. 修正get_exe_sections函数,适配数组填充
你当前的get_exe_sections只能处理单个结构体,而且直接操作传入的指针,没有考虑数组的索引。更重要的是,直接赋值elf_strptr和data->d_buf的指针会有悬空风险——这些指针指向ELF库内部的内存,当你关闭ELF文件后,这块内存会被释放,导致你的结构体成员变成无效指针。
更安全的get_exe_sections版本
// 返回bool表示填充是否成功,方便上层做错误处理 bool get_exe_sections(struct _section *sect, Elf *elf, GElf_Ehdr *ehdr, GElf_Shdr *shdr, Elf_Data *data) { // 拷贝节名称:用strdup复制一份,避免依赖ELF内部的字符串表 char *name = elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name); if (name == NULL) return false; sect->sectName = strdup(name); if (sect->sectName == NULL) return false; sect->start_addr = shdr->sh_addr; sect->end_addr = shdr->sh_addr + shdr->sh_size; // 拷贝节的字节数据:malloc一块新内存,把data里的内容复制过去 sect->bytes = malloc(shdr->sh_size); if (sect->bytes == NULL) { free(sect->sectName); // 已经分配的名称要释放,避免内存泄漏 return false; } memcpy(sect->bytes, data->d_buf, shdr->sh_size); return true; }
在main里循环填充数组
接下来你需要遍历每个ELF节,把数据填充到数组的对应位置:
int i = 0; Elf_Scn *scn = NULL; // 遍历所有节 while ((scn = elf_nextscn(elf, scn)) != NULL && i < sections_count) { GElf_Shdr shdr; if (gelf_getshdr(scn, &shdr) == NULL) { fprintf(stderr, "Failed to get section header\n"); break; } Elf_Data *data = elf_getdata(scn, NULL); if (data == NULL) { fprintf(stderr, "Failed to get section data\n"); break; } // 填充数组的第i个元素 if (!get_exe_sections(&exe_sect_array[i], elf, ehdr, &shdr, data)) { // 填充失败,要清理已经分配的资源 for (int j = 0; j < i; j++) { free(exe_sect_array[j].sectName); free(exe_sect_array[j].bytes); } free(exe_sect_array); perror("Failed to populate section"); exit(EXIT_FAILURE); } i++; }
3. 如果需要动态扩展数组(用realloc)
要是你没办法提前准确获取节的数量,或者需要动态添加节,可以用realloc来扩展数组的容量:
// 初始化空数组,容量和当前元素数都设为0 struct _section *exe_sect_array = NULL; int current_capacity = 0; int current_count = 0; // 在遍历节的循环中: if (current_count >= current_capacity) { // 每次扩展容量,比如初始给4个位置,之后翻倍 int new_capacity = (current_capacity == 0) ? 4 : current_capacity * 2; struct _section *temp = realloc(exe_sect_array, new_capacity * sizeof(struct _section)); if (temp == NULL) { // 扩展失败,清理已分配的所有资源 for (int j = 0; j < current_count; j++) { free(exe_sect_array[j].sectName); free(exe_sect_array[j].bytes); } free(exe_sect_array); perror("realloc failed"); exit(EXIT_FAILURE); } exe_sect_array = temp; current_capacity = new_capacity; } // 填充当前位置的元素 if (get_exe_sections(&exe_sect_array[current_count], elf, ehdr, &shdr, data)) { current_count++; } else { fprintf(stderr, "Failed to add section\n"); break; }
4. 别忘了释放内存!
使用完数组后,一定要逐个释放结构体里的动态分配成员,最后再释放数组本身,避免内存泄漏:
// 假设sections_count是实际填充的节数量 for (int j = 0; j < sections_count; j++) { free(exe_sect_array[j].sectName); free(exe_sect_array[j].bytes); } free(exe_sect_array);
核心注意事项
- 指针生命周期:
elf_strptr和data->d_buf的指针都是ELF库内部的,一旦你调用elf_end(elf)或者关闭文件,这些内存就会被回收,直接赋值会导致悬空指针,必须手动拷贝。 - 错误处理:malloc、realloc、strdup都可能失败,一定要检查返回值,并且在失败时清理已经分配的资源,不然会留下内存泄漏。
- 数组越界:操作数组时要确保循环的边界正确,不要超出数组的容量或实际填充的元素数。
内容的提问来源于stack exchange,提问作者nice_remark
相关产品推荐
相关产品推荐

