链表内存释放触发ntdll!RtlIsZeroMemory错误c0000374求助
链表内存释放函数导致堆损坏错误的问题分析与修复
问题场景
实现链表节点内存申请后,编写释放函数时程序崩溃,调试提示堆损坏错误(c0000374),即使释放前检查了节点不为NULL。
相关代码
test.h
typedef struct snPng_block { uint8_t size[4]; size_t dataSize; uint8_t *data; uint8_t crc[4]; struct snPng_block *next; } snPng_block; int snPng_new(snPng_block **obj, size_t length) { if(!length) { return snErr_ErrNullData; } snPng_block *head = NULL; snPng_block *ptr = NULL; size_t index; for(index = 0; index < length; ++index) { if(head == NULL) { if(!(head = (snPng_block *)malloc(sizeof(snPng_block)))) { return snErr_Memory; } ptr = head; } else { if(!(ptr->next = (snPng_block *)malloc(sizeof(snPng_block)))) { return snErr_Memory; } ptr = ptr->next; } } ptr->next = NULL; (*obj) = head; return snErr_OK; } int snPng_release(snPng_block **obj) { snPng_block *ptr = NULL; for(ptr = (*obj); ptr; ptr = ptr->next) { free(ptr); } return snErr_OK; }
test.c
int main(int argc, char **argv) { snPng_block *block = NULL; snPng_new(&block, 9); snPng_block *ptr = NULL; snSize index; for(index = 0, ptr = block; ptr != NULL; ++index, ptr = ptr->next) { printf("%"PRIu64" node: %p\n", index + 1, ptr); } snPng_release(&block); return 0; }
GDB调试结果
Reading symbols from #output\main.exe... (gdb) r Starting program: E:\Projects\Shark_Coast\#output\main.exe [New Thread 13724.0x8ac] 1 node: 00000244171955F0 2 node: 0000024417195830 3 node: 0000024417195890 4 node: 000002441719ADA0 5 node: 000002441719AE00 6 node: 000002441719AE60 7 node: 000002441719AEC0 8 node: 000002441719AF20 9 node: 00000244171994F0 warning: Critical error detected c0000374 Thread 1 received signal SIGTRAP, Trace/breakpoint trap. 0x00007fff7ab2f633 in ntdll!RtlIsZeroMemory () from C:\WINDOWS\SYSTEM32\ntdll.dll (gdb) backtrace #0 0x00007fff7ab2f633 in ntdll!RtlIsZeroMemory () from C:\WINDOWS\SYSTEM32\ntdll.dll #1 0x00007fff7ab383f2 in ntdll!RtlpNtSetValueKey () from C:\WINDOWS\SYSTEM32\ntdll.dll #2 0x00007fff7ab386da in ntdll!RtlpNtSetValueKey () from C:\WINDOWS\SYSTEM32\ntdll.dll #3 0x00007fff7ab3e361 in ntdll!RtlpNtSetValueKey () from C:\WINDOWS\SYSTEM32\ntdll.dll #4 0x00007fff7aa55b43 in ntdll!RtlGetCurrentServiceSessionId () from C:\WINDOWS\SYSTEM32\ntdll.dll #5 0x00007fff7aa547b1 in ntdll!RtlFreeHeap () from C:\WINDOWS\SYSTEM32\ntdll.dll #6 0x00007fff781bf05b in ucrtbase!_free_base () from C:\WINDOWS\System32\ucrtbase.dll #7 0x00007ff7f3653480 in snPng_release (obj=<optimized out>) at includes/image/test.h:53 #8 main (argc=<optimized out>, argv=<optimized out>) at test\test.c:29
错误原因
snPng_release函数的循环逻辑存在致命问题:
- 执行
free(ptr)后,ptr指向的内存已被回收,成为野指针 - 后续循环中尝试访问
ptr->next,本质是访问已释放的内存,破坏了堆结构,触发系统内存保护错误(c0000374)
修复方案
修正snPng_release函数
释放当前节点前,先保存下一个节点的地址,避免访问已释放内存:
int snPng_release(snPng_block **obj) { if (!obj || !(*obj)) { return snErr_OK; } snPng_block *current = *obj; snPng_block *next_node = NULL; while (current != NULL) { next_node = current->next; // 提前保存下一个节点 free(current); // 释放当前节点 current = next_node; // 切换到下一个节点 } *obj = NULL; // 将原指针置空,避免后续误用野指针 return snErr_OK; }
修复snPng_new的内存泄漏问题
原snPng_new如果在循环中malloc失败,已申请的节点不会被释放,造成内存泄漏。补充失败时的清理逻辑:
int snPng_new(snPng_block **obj, size_t length) { if(!length) { return snErr_ErrNullData; } snPng_block *head = NULL; snPng_block *ptr = NULL; size_t index; for(index = 0; index < length; ++index) { snPng_block *new_node = (snPng_block *)malloc(sizeof(snPng_block)); if (!new_node) { // 申请失败,释放已创建的所有节点 snPng_release(&head); return snErr_Memory; } if(head == NULL) { head = new_node; ptr = head; } else { ptr->next = new_node; ptr = ptr->next; } } if (ptr) { ptr->next = NULL; } *obj = head; return snErr_OK; }
内容的提问来源于stack exchange,提问作者S-N
相关产品推荐
相关产品推荐

