C语言无外部库提取HTML响应超链接时内存问题排查修复
问题诱因
- 核心问题1:
recv系统调用仅返回接收到的字节数,不会自动在缓冲区末尾追加字符串结束符\0。后续strdup、strtok等字符串处理函数都依赖\0判断字符串边界,未补结束符会导致函数越界访问非法内存,触发段错误。你看到的strlen.S无法打开的提示只是调试时gdb找不到glibc源码的附带现象,本质是代码触发了非法内存访问。 - 核心问题2:循环逻辑存在空指针访问风险。当
strtok遍历完所有片段返回NULL时,你仍会进入判断分支调用strlen(token),给strlen传入空指针直接触发段错误。 - 次要问题:使用
strncpy拷贝前5个字符到token_head后,没有手动追加\0,strcmp会越界读取token_head后面的栈内存,可能导致匹配逻辑异常,也存在内存访问风险。
修复方案
按如下步骤修改代码即可解决问题:
- 接收响应时保存recv返回值,手动给缓冲区加结束符:
// 注意定义response_buf时要预留1字节存结束符,比如 char response_buf[4096]; ssize_t recv_len = recv(tcpSocket, response_buf, sizeof(response_buf) - 1, 0); if(recv_len < 0){ printf("Error with recv()\n"); } else { response_buf[recv_len] = '\0'; // 手动补字符串结束符 printf("Successfully receive response\n"); }
- 修正循环逻辑,先判断token非空再做后续处理,同时用
strncmp替代临时拷贝逻辑简化代码:
char * const dupstr = strdup(response_buf); char* token = strtok(dupstr, " \n<>"); char last_token[2000]; const char a[] = "a"; const char href[] = "href="; while (token != NULL) { // 安全拷贝token到last_token,避免溢出 strncpy(last_token, token, sizeof(last_token) - 1); last_token[sizeof(last_token) - 1] = '\0'; token = strtok(NULL, " \n<>"); if(strcmp(last_token, a) == 0){ // 先判断token非空再访问 if (token == NULL) break; size_t len = strlen(token); if(len > 5){ // 直接用strncmp比对,不需要额外拷贝 if(strncmp(token, href, 5) == 0){ printf("%s\n", token); } } } } // 记得释放strdup申请的堆内存,避免内存泄漏 free(dupstr);
- 可选:如果调试时不想再看到
strlen.S缺失的提示,可以安装glibc调试符号包,Ubuntu下执行sudo apt install glibc-source glibc-dbg即可,该操作不影响代码运行逻辑。
内容的提问来源于stack exchange,提问作者Eric Yu
相关产品推荐
相关产品推荐

