/* The memccpy() call below will cause a segmentation fault on ia64 systems: It tries to read beyond the end of srcbuf and hits an unreadable page. Is this a bug? Note that we're deliberately indicating a size of SIZE+8 characters to memccpy even though srcbuf is only SIZE characters long. One point of view is that memccpy should never attempt to read more than SIZE characters: It should see the 0 character at srcbuf[SIZE-1] and stop there. memccpy() is supposed to stop after it copies n characters or after it copies the character specified by the argument c, whichever comes first, so obviously it's ok for the source string to be shorter than n characters. Another point of view is that just because it only copies SIZE characters, that doesn't mean it will only try to access SIZE characters from the source string. The length of the source string is allowed to be less than n characters, but the size of the object containing the source string isn't. The C standard contains some explicit language which comes down on the side of the latter point of view. Section 7.21.1 paragraph 2 (I'm quoting from C99 since that's what I have handy, but C89/C90 has the same requirements): ----- | Where an argument declared as size_t n specifies the length of the | array for a function, n can have the value zero on a call to that | function. Unless explicitly stated otherwise in the description of a | particular function in this subclause, pointer arguments on such a | call shall still have valid values, as described in 7.1.4. ----- Section 7.1.4 states: ----- | If a function argument is described as being an array, the pointer | actually passed to the function shall have a value such that all | address computations and accesses to objects (that would be valid if | the pointer did point to the first element of such an array) are in | fact valid. ----- So if memccpy were a standard C function, we'd clearly be invoking undefined behavior by doing what we're doing. memccpy is not part of the standard C library however. One point which has caused some consternation is that these two statements are expected to behave identically: memccpy(dstbuf, srcbuf, 0, SIZE+8); strncpy(dstbuf, srcbuf, SIZE+8); Yet the memccpy call causes a segfault while the strncpy call does not. */ #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <string.h> #include <assert.h> #define SIZE 32768 int main(void) { int fd; char *srcbuf; char dstbuf[2*SIZE]; char *protected; fd = open("/dev/zero", O_RDONLY); if(fd == -1) { perror("open"); exit(EXIT_FAILURE); } srcbuf = mmap(0, SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if(srcbuf == (char *)-1) { perror("mmap"); exit(EXIT_FAILURE); } protected = mmap(srcbuf+SIZE, SIZE, PROT_NONE, MAP_FIXED|MAP_PRIVATE, fd, SIZE); if(protected == (char *)-1) { perror("mmap"); exit(EXIT_FAILURE); } assert(protected == srcbuf+SIZE); memset(srcbuf, 'x', SIZE-1); srcbuf[SIZE-1]='\0'; #if 1 memccpy(dstbuf, srcbuf, 0, SIZE+8); #else strncpy(dstbuf, srcbuf, SIZE+8); #endif return 0; }
An errata has been issued which should help the problem described in this bug report. This report is therefore being closed with a resolution of ERRATA. For more information on the solution and/or where to find the updated files, please follow the link below. You may reopen this bug report if the solution does not work for you. http://rhn.redhat.com/errata/RHSA-2003-090.html