网络编程中,基础接口read的使用要格外注意,先上有问题的代码:
int socketTCP::readn(char *buf,size_t len){
int ret = 0;
size_t left = len;
while(left>0){
ret = ::read(sock_,buf,len);
if(ret<0){
return -1;
}
if(ret==0){
break;
}
buf += ret;
left -= ret;
}
return len-left;
}
崩溃现象:
崩溃的地址每次不一样,崩溃地址随机。
复现方法:
客户端每次给服务端发送的包字节大小是32B:
32B,32B,32B,
正常情况下,read接收的包字节大小是:
32B,32B,32B,...
异常情况下,read接收的包字节大小是:
32B,16B,32B,...
分析:
一旦read返回的ret值为16,那么上述代码即陷入“死循环”中,直到buf越界,出现Segmentation Fault.
之所以每次崩溃地址随机,是因为buf每次越界的地址随机。
为什么会"死循环呢"?举例分析下:
(1) readn->32B left=32,ret=32,left=32-32=0 退出循环
(2) readn->32B left=32,ret=16,left=32-16=16
ret=32,left=16-32=-16 //read还是会读len个字节,ret=32
因为left是size_t类型,而size_t是unsigned int类型,left=-16时left>0为true!!!所以之后会发生死循环.
ret=32,left=-16-32=-48
......
解决:
修改的话有两种方式:
(1)size_t left=len;改为int left=len;
目的是要当left<0时退出循环。
(2)read(sock_,buf,len);改为read(sock_,buf,left);
目的是保证left会==0,退出循环。