标签:
程序总是难以避免地会出现各种问题,严重时甚至崩溃退出。现在很多应用程序在出现崩溃时会收集相关错误信息,发送错误报告,方便开发人员定位并修复问题。
最近在实际工作中也遇到了类似的问题,客户端通过PLSQL等工具连接到远程数据库服务器做运维操作,出于安全性的考虑,这里客户端并不是直接连到服务器,而是先连到类似于跳板机的设备,再由跳板机连接真实的服务器,数据流向如下图所示。
现在需要在跳板机处将客户端输入的命令,即待执行的SQL语句提取出来。对通信过程抓包会发现,通信数据并非明文,但有一定的规律可循,由于oracle公司并未公开数据格式、不同版本的数据格式可能有差异等原因,想完全准确无误地从通信数据包中提取SQL语句并非易事,目前采用的做法是凭经验猜测解析。
事实证明,这个办法在大部分情况下能很好地工作,只有在极少数情况下,由于输入数据的某些特征以及解析过程没有做好保护措施,会出现内存越界读写问题,导致整个程序崩溃。可见,目前所掌握的经验还不足以百分之百覆盖所有的情况。
有一个办法可以不让程序异常退出,同时把会导致程序崩溃的数据收集起来,具体做法是在接收到输入数据后,生成子进程,由子进程负责解析,父进程等待结果。如果子进程正常退出,说明解析成功,无需额外处理;反之如果子进程异常退出,说明解析过程出了问题,这时父进程把输入数据记到磁盘文件中,供开发人员分析,以完善SQL语句解析经验。
以下给个例子,对上面的思路做简单说明。程序功能是输入一个字符串,如果字符串长度为奇数,则异常退出。
1 #include <stdio.h> 2 #include <string.h> 3 int main() 4 { 5 char buf[64]; 6 for (;;) { 7 scanf("%[^\n]%*c", buf); 8 if (strlen(buf) & 1) 9 memset(0, 0, 1); 10 } 11 return 0; 12 }
以下是改进做法。
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <unistd.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <wait.h> 7 #include <sys/stat.h> 8 #include <fcntl.h> 9 void SaveErr(const char *buf) 10 { 11 FILE *fp = fopen("err.log", "a+"); 12 fprintf(fp, "%s\n", buf); 13 fclose(fp); 14 } 15 int main() 16 { 17 int fd[2], status; 18 pid_t pid; 19 char buf[64], tmp[64]; 20 21 for (;;) { 22 scanf("%[^\n]%*c", buf); 23 pipe(fd); 24 pid = fork(); 25 if (pid > 0) { 26 close(fd[0]); 27 write(fd[1], buf, strlen(buf)); 28 waitpid(pid, &status, 0); 29 if (!WIFEXITED(status)) 30 SaveErr(buf); 31 } else if (0 == pid) { 32 close(fd[1]); 33 read(fd[0], tmp, sizeof(tmp)); 34 if (strlen(tmp) & 1) 35 memset(0, 0, 1); 36 return 0; 37 } 38 } 39 return 0; 40 }
标签:
原文地址:http://www.cnblogs.com/boyfaceone/p/4616620.html