项目中使用了基于CGIEx构建的CGI,并且通过CGI调用Protobuf API来完成一些动态解析proto定义之类的功能,上线前使用Valgrind的memcheck工具检测CGI是否存在内存泄漏的风险。
Valgrind的使用十分简单,通过设置一定的参数启动二进制可执行程序,并且在执行结束之后收集结果输出即可。但是我们的CGI是通过Apache运行的,不能直接使用Valgrind启动,Google一圈之后没有找到相关的实践,只好自己动手。
首先,直接执行CGI二进制可执行程序,可以看到进入了交互模式(Intractive Mode),并且提示等待用户输入(如下图)。不过如何输入参数?如何确定GET和POST的调用方法?以及如何区分两种方法的参数,却仍是未知数。

继续深入研究,全局搜索”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&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&endtime=2017-07-31%2015%3A59%3A31&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两种方式的脚本: