glibc 2.10 has added a new test for memchr() in stratcliff. This new test fails on ia64, which has its own assembly version in sysdeps/ia64/memchr.S. It looks like this assembly version does some prefetch, and crosses the page boundary, causing the segfault. It should be possible to do prefetching while not triggering page faults on ia64, but I don't know enough ia64 assembly to be able to modify this code myself.
stratcliff.c has int size = sysconf (_SC_PAGESIZE); int nchars = size / sizeof (CHAR); ... adr = (CHAR *) mmap (NULL, 3 * size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); ... mprotect (adr, size, PROT_NONE); mprotect (adr + 2 * nchars, size, PROT_NONE); adr += nchars; ... CHAR *cp = MEMCHR (&adr[outer], L('V'), 3 * size); memchr is called with size which contains unreadable pages. How does it work on any arch?
The problem is software pipeline doesn't take page boundary into account.
(In reply to comment #1) > stratcliff.c has > > int size = sysconf (_SC_PAGESIZE); > int nchars = size / sizeof (CHAR); > ... > adr = (CHAR *) mmap (NULL, 3 * size, PROT_READ | PROT_WRITE, > MAP_PRIVATE | MAP_ANON, -1, 0); > ... > mprotect (adr, size, PROT_NONE); > mprotect (adr + 2 * nchars, size, PROT_NONE); > adr += nchars; > ... > CHAR *cp = MEMCHR (&adr[outer], L('V'), 3 * size); > > memchr is called with size which contains unreadable pages. How > does it work on any arch? The looked up char is now to be before the page boundary, that is before the unreadable pages. This test actually checks that in such condition theses pages are not accessed.
A patch is posted at http://sourceware.org/ml/libc-alpha/2009-05/msg00110.html
(In reply to comment #4) > A patch is posted at > > http://sourceware.org/ml/libc-alpha/2009-05/msg00110.html Oops. Wrong patch. I will upload the patch here.
Created attachment 3955 [details] A patch
I confirm it works well, thanks a lot! Could someone apply this patch?
Fixed in current git version.
Unfortunately, this seems to break when calling memchr() on a shared mmap()ed buffer - this crashes now: #include<sys/mman.h> #include<string.h> #include<unistd.h> #include<fcntl.h> int main() { void *m = mmap(NULL, 53, PROT_READ, MAP_SHARED, open("/etc/passwd", O_RDONLY ), 0); volatile void *q = memchr(m, ':', 53); } since memchr() tries to access m-8. I have only very little idea IA64, I think it is because the kernel cannot fill p[] in time, causing the speculative load to fail, and the assumption that speculative load fails only if the mapping is inaccessible is invalid?
A patch is posted at http://sourceware.org/ml/libc-alpha/2009-11/msg00032.html
Fixed in git.
(In reply to comment #10) > A patch is posted at > > http://sourceware.org/ml/libc-alpha/2009-11/msg00032.html Please use the patch above. It handles reading beyond memory properly, regardless memory size.
Applied.