我目前正在学习搜索C源代码中的漏洞。下面的代码片段是用于查找漏洞的一大段代码的一部分。尽管我不喜欢破坏者,但我想知道是否有人可以首先阐明代码的实际作用,因为我无法全神贯注!
函数是:
int writeSock(int sock, char *buf, size_t len)
{
ssize_t byteswrote = 0;
ssize_t ret = 0;
while (byteswrote < len)
{
ret = send(sock, buf + byteswrote, len - byteswrote, 0);
if (ret < 0)
{
return -1;
}
if (ret == 0)
{
break;
}
byteswrote += ret;
}
return byteswrote;
}
如果在while循环的第一次迭代中,它是从缓冲区的开始复制到缓冲区+(len-byteswrote)(我们要复制的数量-0)的开始,那么我们是否没有复制所有内容那一点?我们为什么要在这里迭代,因为它肯定可以一次迭代地处理所有事情?
也许我正在以一种非常愚蠢的方式看待这个问题,但是由于某种原因,我正在为此苦苦挣扎。
答案 0 :(得分:4)
答案很明显-send()
不保证将发送所有数据,因此它返回实际发送到套接字的数量,类似于文件操作中的write()
函数。 / p>
离我这边只有2美分:如果您的代码中send()
返回零,则会破坏循环。但是,这不被视为错误。例如,如果缓冲区已满,可能会发生这种情况。但是我不记得我曾经经历过。
摘录自man send
:
返回值
成功时,这些调用将返回发送的字节数。错误时,返回-1,并正确设置errno。
答案 1 :(得分:2)
send()
是POSIX函数。根据{{3}}:
描述
send()
函数应启动来自以下设备的消息传输 指定的套接字到其对等方。 ......
返回值
成功完成后,
send()
将返回字节数 已发送。否则,应返回-1并设置errno以指示 错误。...
应用用法
如果socket参数引用连接模式套接字,则
send()
函数等效于sendto()
(对于dest_addr
和dest_len
参数,因为它们在此被忽略 案件)。如果套接字参数引用套接字和标志 参数为0,则send()
函数等效于the POSIX documentation。
请注意,如何说明如果flags
参数为零,则send()
会像write()
那样。这正是您发布的代码使用send()
的方式。因此,它的工作方式就像write()
一样,而write()
文档也很重要。 write()
指出:
描述
write()
函数应尝试写入nbyte
个字节......
返回值
成功完成后,这些功能应返回 实际写入的字节数 ...
如果操作系统的手册页没有指出send()
可能会部分发送请求的数据,则说明操作系统文档不足。
答案 2 :(得分:2)
如果在while循环的第一次迭代中,它是从 缓冲区的开始到缓冲区的开始+(len-byteswrote)(多少 我们要复制-0)然后我们还没有复制所有内容吗?
不一定。
我们为什么要在这里进行迭代,因为它肯定会处理 一次迭代?
因为不一定一次调用就可以处理所有内容,尽管我可以从its Linux manual page中的send()
文档中了解到这一点,或者its POSIX specification。
在Linux手册中更加清楚,但是POSIX也记录了send()
的行为是根据write()
行为的变化来指定的,并由标志指示(如果有的话),传递给send()
。 write()
的文档明确指出可能会发生短写:
write()
从buf
开始写入缓冲区中的计数字节 到文件描述符fd
所引用的文件。例如,如果写入的字节数可能少于
count
, 基础物理介质上没有足够的空间,或者 遇到RLIMIT_FSIZE
个资源限制(请参阅setrlimit
(2)
),否则呼叫被信号处理程序中断 写入少于count
个字节后。
(Linux manual page for write()
)
POSIX具有基本相同的规定,但IMO并没有以明确的术语将其记录在文档中。
为支持此行为,send()
和write()
返回实际发送的字节数。还要注意,这时不能保证发送的字节已被接收-当函数返回时,发送的字节可能甚至还没有从机器中移出(即它们可能会被缓冲)。
因此,将send()
和write()
调用放入循环中是绝对正确且非冗余的,例如您希望确保实际上指定的全部字节数确实存在于您的问题中已发送。否则,这是一个可悲的普遍缺陷。