Max
Max

Reputation: 2859

read(3) "called with bigger length than size of the destination buffer"

With the following code:

#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) {
    ...
}

I'm getting this error:

/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

If I get rid of the MIN and change the read to read(sockfd, recvBuf, recvBufLength) then it compiles without complaint.

Is this my mistake, or GCC's, or glibc's?

If not the former, then how can I circumvent the flawed length checking?


Edit:

Even expanding the MIN macro to a simple ternary operation still gives the error.

read(sockfd, recvBuf, (recvLength-received)<recvBufLength?(recvLength-received):recvBufLength)

This is all in GCC 4.8.2, I'll try other versions shortly.

Upvotes: 2

Views: 1721

Answers (2)

Santiago Villafuerte
Santiago Villafuerte

Reputation: 783

I found a similar issue with read() in GCC 5.4 for x64. The buffer was:

uint8_t msg[4096];
readBytes = read(fd, &msg[0], size);

And the size was a variable amount inside a uint16_t variable. Somehow the _FORTIFY_SOURCE macro (__bos0) was detecting that the destination buffer was smaller than the size. My program cannot behave that way given the conditions of its operation. The error was:

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]

So, I fixed it in the linking stage of my binary by disabling the protections:

CCFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0

It can also be done when compiling the .o file in case somebody needs to disable the problem in a given file only.

Upvotes: 1

nlko
nlko

Reputation: 520

I think it is because the MIN macro expands as a block and not as an expression (there { } in the macro). I don't think it is allowed in every C standard (see C block becomes expression: ( {int a = 1; int b = 2; a+b;} ) equals 3).

Maybe try to put the result of MIN in a variable first

val=MIN(recvLength-received, recvBufLength));
while ((r = read(sockfd, recvBuf, val) > 0) {
    ...
    val=MIN(recvLength-received, recvBufLength));
}

Interesting, I just learned something!

Upvotes: 3

Related Questions