Search code examples
clinked-listdynamic-memory-allocationsingly-linked-listfree

ntdll!RtlIsZeroMemory releasing linked list memory in C [warning: Critical error detected c0000374]


I am trying to write data with a linked list structure. After writing the function used to apply memory for each node in the linked list, I started writing the function used to release memory for each node in the linked list, but it encountered an error.

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;
}

The following are the results of my debugging using GDB tools.
I don't quite understand why this program generates errors because I check if each node points to an NULL address before releasing it.

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

Solution

  • It seems the problem exists due to the incorrect function snPng_release

    int snPng_release(snPng_block **obj)
    {
        snPng_block *ptr = NULL;
        for(ptr = (*obj); ptr; ptr = ptr->next) {
            free(ptr);
        }
    
        return snErr_OK;
    }
    

    where there are used invalid pointers in the expression ptr = ptr->next after deleting memory pointed to by the pointers.

    Also after calling the function the original pointer referred to by the expression *obj will not be equal to NULL as it is required because the pointer is passed to the function by reference.

    Instead you need to write for example

    int snPng_release(snPng_block **obj)
    {
        while ( *obj )
        {
            snPng_block *ptr = *obj;
            *obj = ( *obj )->next;
            // free the memory pointed to by the data member data
            // if it also was dynamically allocated 
            // like free( ptr->data );
            free( ptr );
        } 
    
        return snErr_OK;
    }
    

    After calling the function the original pointer block declared in main will be equal to NULL as required.