使用以下代码:
#define MIN(a,b) ({ typeof (a) _a = (a); typeof (b) _b = (b); _a < _b ? _a : _b; })
...
size_t const recvBufLength = 50*1024*1024;
char * const recvBuf = malloc(recvBufLength);
...
while ((r = read(sockfd, recvBuf, MIN(recvLength-received, recvBufLength))) > 0) {
...
}
我收到了这个错误:
/usr/include/x86_64-linux-gnu/bits/unistd.h: In function ‘main’:
/usr/include/x86_64-linux-gnu/bits/unistd.h:39:2: error: call to ‘__read_chk_warn’ declared with attribute warning: read called with bigger length than size of the destination buffer [-Werror]
return __read_chk (__fd, __buf, __nbytes, __bos0 (__buf));
^
lto1: all warnings being treated as errors
lto-wrapper: gcc returned 1 exit status
/usr/bin/ld: lto-wrapper failed
collect2: error: ld returned 1 exit status
如果我删除MIN
并将读取更改为read(sockfd, recvBuf, recvBufLength)
,那么它会毫无怨言地编译。
这是我的错误,还是GCC,还是glibc?
如果不是前者,那么我该如何规避有缺陷的长度检查?
修改
即使将MIN宏扩展为简单的三元运算仍然会出错。
read(sockfd, recvBuf, (recvLength-received)<recvBufLength?(recvLength-received):recvBufLength)
这一切都在GCC 4.8.2中,我很快就会尝试其他版本。
答案 0 :(得分:3)
我认为这是因为MIN宏扩展为块而不是表达式(宏中有{})。我不认为每个C标准都允许这样做(见C block becomes expression: ( {int a = 1; int b = 2; a+b;} ) equals 3)。
也许尝试将MIN的结果放在变量中
val=MIN(recvLength-received, recvBufLength));
while ((r = read(sockfd, recvBuf, val) > 0) {
...
val=MIN(recvLength-received, recvBufLength));
}
有趣的是,我刚刚学到了一些东西!
答案 1 :(得分:0)
我在 GCC 5.4 for x64 中发现了类似的 read() 问题。缓冲区是:
uint8_t msg[4096];
readBytes = read(fd, &msg[0], size);
大小是 uint16_t 变量中的一个可变数量。 _FORTIFY_SOURCE 宏 (__bos0) 以某种方式检测到目标缓冲区小于大小。鉴于其运行条件,我的程序不能以这种方式运行。错误是:
unistd.h:39:58: error: call to ‘__read_chk_warn’ declared with attribute warning: read called with bigger length than size of the destination buffer [-Werror]
因此,我在二进制文件的链接阶段通过禁用保护来修复它:
CCFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0
也可以在编译 .o 文件时完成,以防有人需要仅在给定文件中禁用该问题。