diff --git a/ChangeLog b/ChangeLog index 4e39b0112a..fee7a5ea2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2000-01-02 Ulrich Drepper + * posix/Makefile (tests): Add tst-mmap. + * posix/tst-mmap.c: New file. + + * sysdeps/unix/sysv/linux/i386/mmap64.S: Pop registers after mmap2 + call before handling error. + * sysdeps/unix/sysv/linux/i386/mmap64.S: Handle unaligned offsets. * sysdeps/unix/sysv/linux/i386/mmap.S: Likewise. diff --git a/posix/Makefile b/posix/Makefile index 7861bdf5f3..96c73933e5 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc. +# Copyright (C) 1991-1999, 2000 Free Software Foundation, Inc. # This file is part of the GNU C Library. # The GNU C Library is free software; you can redistribute it and/or @@ -57,7 +57,7 @@ include ../Makeconfig aux := init-posix environ tests := tstgetopt testfnm runtests runptests \ - tst-preadwrite test-vfork regexbug1 tst-getlogin + tst-preadwrite test-vfork regexbug1 tst-getlogin tst-mmap ifeq (yes,$(build-shared)) test-srcs := globtest tests += wordexp-test diff --git a/posix/tst-mmap.c b/posix/tst-mmap.c new file mode 100644 index 0000000000..0332828723 --- /dev/null +++ b/posix/tst-mmap.c @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include + + +int +main (void) +{ + int result = 0; + FILE *fp; + int c; + char buf[1000]; + int fd; + char *ptr; + size_t ps = sysconf (_SC_PAGESIZE); + void *mem; + + /* Create a file and put some data in it. */ + fp = tmpfile (); + if (fp == NULL) + { + printf ("Cannot create temporary file: %m\n"); + return 1; + } + fd = fileno (fp); + + for (c = 0; c < sizeof (buf); ++c) + buf[c] = '0' + (c % 10); + + for (c = 0; c < 20; ++c) + if (fwrite (buf, 1, sizeof (buf), fp) != sizeof (buf)) + { + printf ("`fwrite' failed: %m\n"); + return 1; + } + assert (ps + 1000 < c * sizeof (buf)); + + /* First try something which is not allowed: map at an offset which is + not module the pagesize. */ + ptr = mmap (NULL, 1000, PROT_READ, MAP_SHARED, fd, ps - 1); + if (ptr != MAP_FAILED) + { + puts ("mapping at offset with mod pagesize != 0 succeeded!"); + result = 1; + } + else if (errno != EINVAL && errno != ENOSYS) + { + puts ("wrong error value for mapping at offset with mod pagesize != 0: %m (should be EINVAL)"); + result = 1; + } + + /* Try the same for mmap64. */ + ptr = mmap64 (NULL, 1000, PROT_READ, MAP_SHARED, fd, ps - 1); + if (ptr != MAP_FAILED) + { + puts ("mapping at offset with mod pagesize != 0 succeeded!"); + result = 1; + } + else if (errno != EINVAL && errno != ENOSYS) + { + puts ("wrong error value for mapping at offset with mod pagesize != 0: %m (should be EINVAL)"); + result = 1; + } + + /* And the same for private mapping. */ + ptr = mmap (NULL, 1000, PROT_READ, MAP_PRIVATE, fd, ps - 1); + if (ptr != MAP_FAILED) + { + puts ("mapping at offset with mod pagesize != 0 succeeded!"); + result = 1; + } + else if (errno != EINVAL && errno != ENOSYS) + { + puts ("wrong error value for mapping at offset with mod pagesize != 0: %m (should be EINVAL)"); + result = 1; + } + + /* Try the same for mmap64. */ + ptr = mmap64 (NULL, 1000, PROT_READ, MAP_PRIVATE, fd, ps - 1); + if (ptr != MAP_FAILED) + { + puts ("mapping at offset with mod pagesize != 0 succeeded!"); + result = 1; + } + else if (errno != EINVAL && errno != ENOSYS) + { + puts ("wrong error value for mapping at offset with mod pagesize != 0: %m (should be EINVAL)"); + result = 1; + } + + /* Get a valid address. */ + mem = malloc (2 * ps); + if (mem != NULL) + { + /* Now we map at an address which is not mod pagesize. */ + ptr = mmap (mem + 1, 1000, PROT_READ, MAP_SHARED | MAP_FIXED, fd, ps); + if (ptr != MAP_FAILED) + { + puts ("mapping at address with mod pagesize != 0 succeeded!"); + result = 1; + } + else if (errno != EINVAL && errno != ENOSYS) + { + puts ("wrong error value for mapping at address with mod pagesize != 0: %m (should be EINVAL)"); + result = 1; + } + + /* Try the same for mmap64. */ + ptr = mmap64 (mem + 1, 1000, PROT_READ, MAP_SHARED | MAP_FIXED, fd, ps); + if (ptr != MAP_FAILED) + { + puts ("mapping at address with mod pagesize != 0 succeeded!"); + result = 1; + } + else if (errno != EINVAL && errno != ENOSYS) + { + puts ("wrong error value for mapping at address with mod pagesize != 0: %m (should be EINVAL)"); + result = 1; + } + + /* And again for MAP_PRIVATE. */ + ptr = mmap (mem + 1, 1000, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ps); + if (ptr != MAP_FAILED) + { + puts ("mapping at address with mod pagesize != 0 succeeded!"); + result = 1; + } + else if (errno != EINVAL && errno != ENOSYS) + { + puts ("wrong error value for mapping at address with mod pagesize != 0: %m (should be EINVAL)"); + result = 1; + } + + /* Try the same for mmap64. */ + ptr = mmap64 (mem + 1, 1000, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ps); + if (ptr != MAP_FAILED) + { + puts ("mapping at address with mod pagesize != 0 succeeded!"); + result = 1; + } + else if (errno != EINVAL && errno != ENOSYS) + { + puts ("wrong error value for mapping at address with mod pagesize != 0: %m (should be EINVAL)"); + result = 1; + } + + free (mem); + } + + /* Now map the memory and see whether the content of the mapped area + is correct. */ + ptr = mmap (NULL, 1000, PROT_READ, MAP_SHARED, fd, ps); + if (ptr == MAP_FAILED) + { + if (errno != ENOSYS) + { + printf ("cannot mmap file: %m\n"); + result = 1; + } + } + else + { + for (c = ps; c < ps + 1000; ++c) + if (ptr[c - ps] != '0' + (c % 10)) + { + printf ("wrong data mapped at offset %d\n", c); + result = 1; + } + } + + /* And for mmap64. */ + ptr = mmap64 (NULL, 1000, PROT_READ, MAP_SHARED, fd, ps); + if (ptr == MAP_FAILED) + { + if (errno != ENOSYS) + { + printf ("cannot mmap file: %m\n"); + result = 1; + } + } + else + { + for (c = ps; c < ps + 1000; ++c) + if (ptr[c - ps] != '0' + (c % 10)) + { + printf ("wrong data mapped at offset %d\n", c); + result = 1; + } + } + + /* That's it. */ + return result; +} diff --git a/sysdeps/unix/sysv/linux/i386/mmap64.S b/sysdeps/unix/sysv/linux/i386/mmap64.S index 346bb52b5f..0785bce783 100644 --- a/sysdeps/unix/sysv/linux/i386/mmap64.S +++ b/sysdeps/unix/sysv/linux/i386/mmap64.S @@ -56,16 +56,16 @@ ENTRY (__mmap64) L(do_syscall): int $0x80 - /* If 0 > %eax > -4096 there was an error. */ - cmpl $-4096, %eax - ja SYSCALL_ERROR_LABEL - /* Restore registers. */ popl %edi popl %esi popl %ebx popl %ebp + /* If 0 > %eax > -4096 there was an error. */ + cmpl $-4096, %eax + ja SYSCALL_ERROR_LABEL + /* Successful; return the syscall's value. */ L(pseudo_end): ret