天天看點

使用 Valgrind 檢測 CGI 記憶體洩漏的簡易方法

項目中使用了基于CGIEx建構的CGI,并且通過CGI調用Protobuf API來完成一些動态解析proto定義之類的功能,上線前使用Valgrind的memcheck工具檢測CGI是否存在記憶體洩漏的風險。

Valgrind的使用十分簡單,通過設定一定的參數啟動二進制可執行程式,并且在執行結束之後收集結果輸出即可。但是我們的CGI是通過Apache運作的,不能直接使用Valgrind啟動,Google一圈之後沒有找到相關的實踐,隻好自己動手。

首先,直接執行CGI二進制可執行程式,可以看到進入了互動模式(Intractive Mode),并且提示等待使用者輸入(如下圖)。不過如何輸入參數?如何确定GET和POST的調用方法?以及如何區分兩種方法的參數,卻仍是未知數。

使用 Valgrind 檢測 CGI 記憶體洩漏的簡易方法

繼續深入研究,全局搜尋”cgihtml Interactive Mode”後找到了線索,在cgi-lib.c檔案中找到了get_DEBUG函數定義如下:

繼續搜尋get_DEBUG的調用之處,發現隻有一處調用,如下:

檢視read_cgi_input函數,可以看到是通過宏REQUEST_METHOD來擷取調用模式,宏REQUEST_METHOD的作用是擷取環境變量“REQUEST_METHOD”。同時,還看到除了get_DEBUG函數之外,還定義了get_POST以及get_GET函數來分别處理POST和GET請求。

其中get_DEBUG和get_GET函數的輸出結果input都直接作為參數傳遞給parse_CGI_encoded函數進一步處理,是以DEBUG模式應該跟GET模式的輸入參數是一緻的。

來看POST接口的調用方式,read_cgi_input函數首先通過CONTENT_TYPE環境變量确定輸入參數的格式(text/json等),然後通過REQUEST_METHOD環境變量的取值(POST)進入調用get_POST函數的分支,并且在get_POST函數中通過CONTENT_LENGTH環境變量擷取輸出參數字元串的長度。

分析到這裡,現在大緻可以确定如何直接啟動CGI二進制檔案并輸入參數了。

CGI Interactive模式下,輸入的參數就是通過GET方式調用時,URL後部所帶的參數,形如:

<code>param1=val1&amp;param2=val2</code>,是以對于GET接口的測試的步驟很簡單

使用valgrind啟動CGI二進制檔案進入Intractive模式<code>valgrind --tool=memcheck --log-file=./valgrind_report.log --leak-check=full --show-reachable=yes --track-origins=yes ./cgi_get_sample</code>

輸入參數清單,并以回車結束。如果參數中有需要urlencode的字元請自行轉換。<code>starttime=2017-07-31%2014%3A59%3A31&amp;endtime=2017-07-31%2015%3A59%3A31&amp;id=1024</code>

檢視valgrind_report.log中的結果輸出

POST接口的調用方式稍微複雜一些。

設定環境變量<code>export REQUEST_METHOD=POST export CONTENT_LENGTH=381 export CONTENT_TYPE="application/json"</code>

valgrind啟動cgi,進入get_POST分支,等待使用者輸入,隻是沒有提示資訊<code>valgrind --tool=memcheck --log-file=./valgrind_report.log --leak-check=full --show-reachable=yes --track-origins=yes ./cgi_post_sample</code>

輸入json格式字元串參數<code>{"id":1024,"name":"calvin"}</code>

測試完成後,将環境變量恢複

<code>unset REQUEST_METHOD unset CONTENT_LENGTH unset CONTENT_TYPE</code>

最後,貼一個內建POST/GET兩種方式的腳本: