0%

使用valgrind分析jansson memory leak

使用三方库 Jansson 造成 memory leak,使用 valgrind 分析如下:

$ gcc -O0 -g -ggdb main.c -ljansson                                      
$ valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./a.out

==21533== 4,752 bytes in 1 blocks are definitely lost in loss record 4 of 4
==21533==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x4E3F3C4: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3C9F7: json_dumps (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x40155F: ipc_db_save (main.c:153)
==21533==    by 0x401C29: main (main.c:287)
==21533== 
==21533== LEAK SUMMARY:
==21533==    definitely lost: 18,480 bytes in 4 blocks
==21533==    indirectly lost: 0 bytes in 0 blocks
==21533==      possibly lost: 0 bytes in 0 blocks
==21533==    still reachable: 0 bytes in 0 blocks
==21533==         suppressed: 0 bytes in 0 blocks
==21533== 
==21533== For counts of detected and suppressed errors, rerun with: -v
==21533== ERROR SUMMARY: 8 errors from 8 contexts (suppressed: 0 from 0)

source code

int ipc_db_save(int index, AppIPCInfoClass *ipc_info)
{
    json_t *root = NULL;
    json_t *new_ipc = NULL;
    json_error_t error;

    if (NULL == ipc_info) {
        return 1;
    }

    if(access("ipcamera.dat", 0))
    {
        _new_db("ipcamera.dat");
    }

    root = json_load_file("ipcamera.dat", 0, &error);
    printf("[%s]source %s\n", __func__, error.source);
    printf("[%s]text %s\n", __func__, error.text);

    if (!json_is_array(root)) {
        json_decref(root);
    }

    if ((new_ipc = json_object()) == NULL) {
        json_decref(root);
    }
    printf("[%s]%d: obj type = %d\n", __func__, __LINE__, json_typeof(root));

    char *result = json_dumps(root, JSON_PRESERVE_ORDER);
    printf("[%s]%d: result %s\n", __func__, __LINE__, result);
    //free(result);

    _object_integer(new_ipc, CAMERA_TYPE_KEY, ipc_info->type);
    _object_string(new_ipc, CAMERA_NAME_KEY, ipc_info->name);
    _object_string(new_ipc, CAMERA_IP_KEY, ipc_info->ip);
    _object_integer(new_ipc, CAMERA_PORT_KEY, ipc_info->port);
    _object_string(new_ipc, CAMERA_USER_KEY, ipc_info->user);
    _object_integer(new_ipc, CAMERA_CHANNEL_KEY, ipc_info->channel);
    _object_string(new_ipc, CAMERA_PASSWD_KEY, ipc_info->passwd);
    _object_string(new_ipc, CAMERA_STREAM_KEY, ipc_info->stream);

    if (index == -1) { //add mode
        json_array_append(root, new_ipc);
    }
    else { //edit mode
        json_array_set(root, index, new_ipc);
    }

    result = json_dumps(root, JSON_PRESERVE_ORDER);
    printf("[%s]%d: result %s\n", __func__, __LINE__, result);
    free(result);

    json_dump_file(root, "ipcamera.dat", 0);
    json_decref(new_ipc);
    json_decref(root);

    return 0;
}

int ipc_db_get(int index, AppIPCInfoClass *ipc_info)
{
    json_t *root = NULL;
    json_t *info_obj = NULL;
    json_t *obj_value = NULL;
    json_error_t error;
    const char *obj_key = NULL;

    if (ipc_info == NULL) {
        return 1;
    }

    root = json_load_file("ipcamera.dat", 0, &error);
    if (!json_is_array(root)) {
        json_decref(root);
        return 1;
    }

    info_obj = json_array_get(root, index);
    if (!json_is_object(info_obj)) {
        json_decref(info_obj);
        json_decref(root);
        return 1;
    }

    json_object_foreach(info_obj, obj_key, obj_value) {
        _parse_info(obj_key, obj_value, ipc_info);
    }

    json_decref(info_obj);
    json_decref(root);

    return 0;
}

valgrind memcheck

$ gcc -O0 -g -ggdb main.c -ljansson
$ valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./a.out

==21533== Memcheck, a memory error detector
==21533== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==21533== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==21533== Command: ./a.out
==21533== 
==21533== Invalid read of size 8
==21533==    at 0x4E42009: json_delete (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x400EFA: json_decref (jansson.h:106)
==21533==    by 0x40186F: ipc_db_get (main.c:213)
==21533==    by 0x401C44: main (main.c:293)
==21533==  Address 0x54b09b8 is 8 bytes inside a block of size 72 free'd
==21533==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x400EFA: json_decref (jansson.h:106)
==21533==    by 0x401860: ipc_db_get (main.c:212)
==21533==    by 0x401C44: main (main.c:293)
==21533==  Block was alloc'd at
==21533==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x4E417BA: json_object (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3E8E4: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3EBB2: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3EDAD: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3F165: json_loadf (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3F1E7: json_load_file (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x40170F: ipc_db_get (main.c:195)
==21533==    by 0x401C44: main (main.c:293)
==21533== 
==21533== Invalid write of size 8
==21533==    at 0x4E4201A: json_delete (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x400EFA: json_decref (jansson.h:106)
==21533==    by 0x40186F: ipc_db_get (main.c:213)
==21533==    by 0x401C44: main (main.c:293)
==21533==  Address 0x54b09b8 is 8 bytes inside a block of size 72 free'd
==21533==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x400EFA: json_decref (jansson.h:106)
==21533==    by 0x401860: ipc_db_get (main.c:212)
==21533==    by 0x401C44: main (main.c:293)
==21533==  Block was alloc'd at
==21533==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x4E417BA: json_object (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3E8E4: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3EBB2: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3EDAD: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3F165: json_loadf (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3F1E7: json_load_file (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x40170F: ipc_db_get (main.c:195)
==21533==    by 0x401C44: main (main.c:293)
==21533== 
==21533== Invalid read of size 8
==21533==    at 0x4E42009: json_delete (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x400EFA: json_decref (jansson.h:106)
==21533==    by 0x40186F: ipc_db_get (main.c:213)
==21533==    by 0x401C55: main (main.c:294)
==21533==  Address 0x54c4918 is 8 bytes inside a block of size 72 free'd
==21533==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x400EFA: json_decref (jansson.h:106)
==21533==    by 0x401860: ipc_db_get (main.c:212)
==21533==    by 0x401C55: main (main.c:294)
==21533==  Block was alloc'd at
==21533==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x4E417BA: json_object (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3E8E4: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3EBB2: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3EDAD: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3F165: json_loadf (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3F1E7: json_load_file (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x40170F: ipc_db_get (main.c:195)
==21533==    by 0x401C55: main (main.c:294)
==21533== 
==21533== Invalid write of size 8
==21533==    at 0x4E4201A: json_delete (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x400EFA: json_decref (jansson.h:106)
==21533==    by 0x40186F: ipc_db_get (main.c:213)
==21533==    by 0x401C55: main (main.c:294)
==21533==  Address 0x54c4918 is 8 bytes inside a block of size 72 free'd
==21533==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x400EFA: json_decref (jansson.h:106)
==21533==    by 0x401860: ipc_db_get (main.c:212)
==21533==    by 0x401C55: main (main.c:294)
==21533==  Block was alloc'd at
==21533==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x4E417BA: json_object (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3E8E4: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3EBB2: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3EDAD: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3F165: json_loadf (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3F1E7: json_load_file (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x40170F: ipc_db_get (main.c:195)
==21533==    by 0x401C55: main (main.c:294)
==21533== 
==21533== 
==21533== HEAP SUMMARY:
==21533==     in use at exit: 18,480 bytes in 4 blocks
==21533==   total heap usage: 5,525 allocs, 5,521 frees, 425,812 bytes allocated
==21533== 
==21533== 4,409 bytes in 1 blocks are definitely lost in loss record 1 of 4
==21533==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x4E3F3C4: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3C9F7: json_dumps (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x40155F: ipc_db_save (main.c:153)
==21533==    by 0x401A2C: main (main.c:251)
==21533== 
==21533== 4,577 bytes in 1 blocks are definitely lost in loss record 2 of 4
==21533==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x4E3F3C4: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3C9F7: json_dumps (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x40155F: ipc_db_save (main.c:153)
==21533==    by 0x401AD5: main (main.c:263)
==21533== 
==21533== 4,742 bytes in 1 blocks are definitely lost in loss record 3 of 4
==21533==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x4E3F3C4: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3C9F7: json_dumps (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x40155F: ipc_db_save (main.c:153)
==21533==    by 0x401B74: main (main.c:275)
==21533== 
==21533== 4,752 bytes in 1 blocks are definitely lost in loss record 4 of 4
==21533==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x4E3F3C4: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3C9F7: json_dumps (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x40155F: ipc_db_save (main.c:153)
==21533==    by 0x401C29: main (main.c:287)
==21533== 
==21533== LEAK SUMMARY:
==21533==    definitely lost: 18,480 bytes in 4 blocks
==21533==    indirectly lost: 0 bytes in 0 blocks
==21533==      possibly lost: 0 bytes in 0 blocks
==21533==    still reachable: 0 bytes in 0 blocks
==21533==         suppressed: 0 bytes in 0 blocks
==21533== 
==21533== For counts of detected and suppressed errors, rerun with: -v
==21533== ERROR SUMMARY: 8 errors from 8 contexts (suppressed: 0 from 0)

Invalid read of size 8

==21533== Invalid read of size 8
==21533==    at 0x4E42009: json_delete (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x400EFA: json_decref (jansson.h:106)
==21533==    by 0x40186F: ipc_db_get (main.c:213)
==21533==    by 0x401C44: main (main.c:293)
==21533==  Address 0x54b09b8 is 8 bytes inside a block of size 72 free'd
==21533==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x400EFA: json_decref (jansson.h:106)
==21533==    by 0x401860: ipc_db_get (main.c:212)
==21533==    by 0x401C44: main (main.c:293)
==21533==  Block was alloc'd at
==21533==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x4E417BA: json_object (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3E8E4: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3EBB2: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3EDAD: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3F165: json_loadf (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3F1E7: json_load_file (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x40170F: ipc_db_get (main.c:195)
==21533==    by 0x401C44: main (main.c:293)

重复释放,将main.c:212注释掉

memory leak

==21533== 4,577 bytes in 1 blocks are definitely lost in loss record 2 of 4
==21533==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21533==    by 0x4E3F3C4: ??? (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x4E3C9F7: json_dumps (in /usr/lib/x86_64-linux-gnu/libjansson.so.4.7.0)
==21533==    by 0x40155F: ipc_db_save (main.c:153)
==21533==    by 0x401AD5: main (main.c:263)

main.c:153处申请内存没有释放,添加 free 解决此问题

正常结果

$ gcc -O0 -g -ggdb main.c -ljansson                                      
$ valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./a.out
==21929== Memcheck, a memory error detector
==21929== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==21929== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==21929== Command: ./a.out
==21929== 
==21929== 
==21929== HEAP SUMMARY:
==21929==     in use at exit: 0 bytes in 0 blocks
==21929==   total heap usage: 5,919 allocs, 5,919 frees, 443,103 bytes allocated
==21929== 
==21929== All heap blocks were freed -- no leaks are possible
==21929== 
==21929== For counts of detected and suppressed errors, rerun with: -v
==21929== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)