realloc因堆大小受限触发SIGABRT的复现及堆限制方法咨询
问题分析与示例代码
1. 报错原因纠正
你触发的错误是glibc malloc的安全校验失败,抛出realloc(): invalid pointer错误后主动触发SIGABRT,并非堆空间不足导致:
- 堆空间不足时realloc只会返回NULL,不会直接终止程序
- 该校验失败的常见原因:传入realloc的指针不是动态分配返回的合法指针、指针已被提前释放、堆上的元数据被越界写等操作篡改。
你定位到的glibc 2.27 malloc.c 3174行的代码逻辑就是校验传入的oldp指针是否符合堆chunk的对齐规则、地址是否合法,校验不通过就直接抛出错误终止进程。
2. 限制堆大小的示例代码
可以通过setrlimit的RLIMIT_DATA参数限制进程的堆区域最大大小,注意:受操作系统页对齐规则、glibc malloc本身的元数据开销限制,设置10字节限制后实际可分配的用户内存会远小于常规4KB页的大小,示例代码如下:
#include <stdio.h> #include <stdlib.h> #include <sys/resource.h> #include <errno.h> int main() { // 设置堆最大限制为10字节 struct rlimit rl = { .rlim_cur = 10, .rlim_max = 10 }; if (setrlimit(RLIMIT_DATA, &rl) != 0) { perror("setrlimit failed"); return 1; } // 尝试分配内存复现问题 void* ptr = calloc(1, 2); if (!ptr) { perror("calloc failed"); return 1; } printf("calloc success, ptr = %p\n", ptr); // 尝试扩容触发错误 void* new_ptr = realloc(ptr, 8); if (!new_ptr) { perror("realloc failed"); free(ptr); return 1; } printf("realloc success, new_ptr = %p\n", new_ptr); free(new_ptr); return 0; }
编译运行命令:gcc test.c -o test && ./test
如果想要更精准的控制堆分配行为,还可以配合mallopt调整glibc malloc的参数,关闭mmap分配大内存的 fallback 逻辑,避免超出堆限制时malloc改用mmap分配内存。
内容的提问来源于stack exchange,提问作者Learner09
相关产品推荐
相关产品推荐

