C/C++統計內存泄漏問題和代碼覆蓋率的方法

1.C/C++統計內存泄漏問題

對於查找代碼中存在的內存泄漏問題,我們可以使用valgrind工具來檢查是否存在內存泄漏問題。比如下面的程序,在堆空間分配20個字節後,程序結束以前並沒有釋放掉這部分內存。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char** argv) {
  char * output = (char *)malloc(sizeof(char) * 20);
  char * src = "check memory";
  if(!output) {
    fprintf(stderr, "alloc memory failed.");
  }
  memcpy(output, src, strlen(src));
  printf("Output:%s\n",output);
  return 0;
}

在使用下面指令編譯生成可執行文件運行後,代碼中並沒有出現任何異常。

gcc main.c -o main

yongli.tong@tj06009pcu:~/code/slog/test$ ./main 
Output:check memory

我們可以使用valgrind運行後,能夠看到如下問題,從輸出來看,提示有20bytes的內存泄漏,但是提示如果查看完整信息,需要增加--leak-check=full的字段。

yongli.tong@tj06009pcu:~/code/slog/test$ valgrind ./main

==14314== LEAK SUMMARY:
==14314==    definitely lost: 20 bytes in 1 blocks
==14314==    indirectly lost: 0 bytes in 0 blocks
==14314==      possibly lost: 0 bytes in 0 blocks
==14314==    still reachable: 0 bytes in 0 blocks
==14314==         suppressed: 0 bytes in 0 blocks
==14314== Rerun with --leak-check=full to see details of leaked memory

接下來,我們在valgrind命令中增加--leak-check=full字段,最終,可以看到內存泄漏發生的位置。

yongli.tong@tj06009pcu:~/code/slog/test$ valgrind --leak-check=full ./main

==14365== 20 bytes in 1 blocks are definitely lost in loss record 1 of 1
==14365==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14365==    by 0x4006AA: main (in /home/yongli.tong/code/slog/test/main)

2.統計代碼覆蓋率的方法

我們在開發階段,需要統計代碼覆蓋率,一方面爲了在單元測試中能夠發現代碼中的邏輯漏洞;另一方面,也將測試前移,提前發現代碼中的問題;最後,對於統計代碼覆蓋率還可以發現代碼中是否存在無效的代碼。對於工具,我這邊使用的是gcov。

在開始之前,我們需要先在系統中安裝該工具,命令如下:

sudo apt-get install ggcov

下面,我編寫了兩個文件,分別爲main.c(充當測試用例的作用):

#include <stdio.h>
#include <assert.h>
#include "test.h"

#define START_NEW_TEST(test_num) \
    fprintf(stderr, "Test %d...", (++test_num));

#define END_TEST(test_num) \
    fprintf(stderr, "pass.\n");

int main(int argc, char** argv) {
  int test_num = 0;
  START_NEW_TEST(test_num);
  assert(test_case(2)==TRUE);
  END_TEST(test_num);

  START_NEW_TEST(test_num);
  assert(test_case(-1)==TRUE);
  END_TEST(test_num);

  START_NEW_TEST(test_num);
  assert(test_case(0)==FALSE);
  END_TEST(test_num);
  return 0;
}

test.c:充當被測試文件,統計裏面test_case函數的覆蓋率。

#include "test.h"

int test_case(int para) {
  if(para != 0) {
    return TRUE;
  } else {
    return FALSE;
  }
}

覆蓋率,可以在gcc中加入--coverage字段,編譯的全部命令如下:

 2087  gcc -c main.c -o main-gcov.o
 2088  gcc --coverage -c test.c -o test-gcov.o
 2089  gcc -o main-gcov --coverage main-gcov.o test-gcov.o
 2091  ./main-gcov 
 2092  gcov -o test-gcov.o test.c

最終運行gcov結果後,會生成統計覆蓋率的數據(100%)。

yongli.tong@tj06009pcu:~/code/slog/test$ gcov -o test-gcov.o test.c
File 'test.c'
Lines executed:100.00% of 4
test.c:creating 'test.c.gcov'

然後,可以根據.gcno .gcda文件生成圖形化報告,命令如下:

yongli.tong@tj06009pcu:~/code/slog/test$ lcov -c -d . -o test_gcov.info
yongli.tong@tj06009pcu:~/code/slog/test$ genhtml -o 111 test_gcov.info

上面的兩條命令執行以後,可以在工程目錄(我這裏是~/code/slog/test)中生成111目錄,裏面會有html文件。

最後,說明在執行gcov時,我這邊出現瞭如下的一個錯誤,主要是/usr/bin/gcov連接的版本不匹配。解決方案是,修改一下/usr/bin/gcov對應的軟連接再執行gcov就沒有這個問題了。

.gcno:version '404*', prefer '408*'

yongli.tong@tj06009pcu:~/code/slog/test$ ls /usr/bin/gcov*
/usr/bin/gcov  /usr/bin/gcov-4.4  /usr/bin/gcov-4.6  /usr/bin/gcov-4.8

yongli.tong@tj06009pcu:~/code/slog/test$ sudo ln -sf /usr/bin/gcov-4.4 /usr/bin/gcov
yongli.tong@tj06009pcu:~/code/slog/test$ ls -al /usr/bin/gcov
lrwxrwxrwx 1 root root 17 Mar 17 18:04 /usr/bin/gcov -> /usr/bin/gcov-4.4

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章