This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: mmap checks by blacklist, not fragile AC_TRY_RUN test
- From: Christopher Faylor <cgf at redhat dot com>
- To: Zack Weinberg <zack at codesourcery dot com>
- Cc: gcc-patches at gcc dot gnu dot org, Eric Botcazou <ebotcazou at libertysurf dot fr>, Greg Schafer <gschafer at zip dot com dot au>
- Date: Wed, 4 Jun 2003 23:45:17 -0400
- Subject: Re: mmap checks by blacklist, not fragile AC_TRY_RUN test
- References: <877k85focv.fsf@egil.codesourcery.com> <87d6hxdr5c.fsf@egil.codesourcery.com>
On Sun, Jun 01, 2003 at 09:45:03PM -0700, Zack Weinberg wrote:
>Zack Weinberg <zack@codesourcery.com> writes:
>
>> i686-linux bootstrap running; testing would be appreciated on
>> blacklisted systems, and/or under the conditions that prompted the
>> original bug reports.
>
>The original patch had a pair of typos which made it think /dev/zero
>and MAP_ANON never worked. That caused an entertaining failure of
>PCH; I suspect the fallback-to-fread logic has never been tested.
>This patch has been corrected.
>
>I am going to check in the change to ggc-page.c, which is independent,
>but wait another 24 hours for more feedback on the configure changes.
>This diff includes only the configure changes.
I'm not sure that blacklisting cygwin re /dev/zero is correct. It might
have been correct at one point but recent versions may work correctly.
Did you determine this from direct testing?
cgf
>> PR bootstrap/3163
>> * aclocal.m4 (AC_FUNC_MMAP_ANYWHERE, AC_FUNC_MMAP_FILE): Delete.
>> (gcc_AC_FUNC_MMAP_BLACKLIST): New.
>> * configure.in: Check for sys/mman.h and mmap in AC_CHECK_HEADERS
>> and AC_CHECK_FUNCS lists, respectively. Use
>> gcc_AC_FUNC_MMAP_BLACKLIST, not AC_FUNC_MMAP_ANYWHERE nor
>> AC_FUNC_MMAP_FILE.
>> * configure, config.in: Regenerate.
>
>===================================================================
>Index: aclocal.m4
>--- aclocal.m4 21 Mar 2003 17:19:32 -0000 1.67
>+++ aclocal.m4 2 Jun 2003 04:42:46 -0000
>@@ -398,356 +398,92 @@ fi
> AC_SUBST($1)dnl
> ])
>
>-# Check whether mmap can map an arbitrary page from /dev/zero or with
>-# MAP_ANONYMOUS, without MAP_FIXED.
>-AC_DEFUN([AC_FUNC_MMAP_ANYWHERE],
>-[AC_CHECK_FUNCS(getpagesize)
>-# The test program for the next two tests is the same except for one
>-# set of ifdefs.
>-changequote({{{,}}})dnl
>-{{{cat >ct-mmap.inc <<'EOF'
>-#include <sys/types.h>
>+# mmap(2) blacklisting. Some platforms provide the mmap library routine
>+# but don't support all of the features we need from it.
>+AC_DEFUN([gcc_AC_FUNC_MMAP_BLACKLIST],
>+[if test $ac_cv_header_sys_mman_h != yes \
>+ || test $ac_cv_func_mmap != yes; then
>+ gcc_cv_func_mmap_file=no
>+ gcc_cv_func_mmap_dev_zero=no
>+ gcc_cv_func_mmap_anon=no
>+else
>+ AC_CACHE_CHECK([whether read-only mmap of a plain file works],
>+ gcc_cv_func_mmap_file,
>+ [# Add a system to this blacklist if
>+ # mmap(0, stat_size, PROT_READ, MAP_PRIVATE, fd, 0) doesn't return a
>+ # memory area containing the same data that you'd get if you applied
>+ # read() to the same fd. The only system known to have a problem here
>+ # is VMS, where text files have record structure.
>+ case "$host_os" in
>+ vms*)
>+ gcc_cv_func_mmap_file=no ;;
>+ *)
>+ gcc_cv_func_mmap_file=yes;;
>+ esac])
>+ AC_CACHE_CHECK([whether mmap from /dev/zero works],
>+ gcc_cv_func_mmap_dev_zero,
>+ [# Add a system to this blacklist if it has mmap() but /dev/zero
>+ # does not exist, or if mmapping /dev/zero does not give anonymous
>+ # zeroed pages with both the following properties:
>+ # 1. If you map N consecutive pages in with one call, and then
>+ # unmap any subset of those pages, the pages that were not
>+ # explicitly unmapped remain accessible.
>+ # 2. If you map two adjacent blocks of memory and then unmap them
>+ # both at once, they must both go away.
>+ # Systems known to be in this category are Windows (all variants),
>+ # VMS, and Darwin.
>+ case "$host_os" in
>+ vms* | cygwin* | pe | mingw* | darwin*)
>+ gcc_cv_func_mmap_dev_zero=no ;;
>+ *)
>+ gcc_cv_func_mmap_dev_zero=yes;;
>+ esac])
>+
>+ # Unlike /dev/zero, the MAP_ANON(YMOUS) defines can be probed for.
>+ AC_CACHE_CHECK([for MAP_ANON(YMOUS)], gcc_cv_decl_map_anon,
>+ [AC_TRY_COMPILE(
>+[#include <sys/types.h>
> #include <sys/mman.h>
>-#include <fcntl.h>
>-#include <signal.h>
>-#include <setjmp.h>
>-#include <stdio.h>
>+#include <unistd.h>
>
>-#if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
>-# define MAP_ANONYMOUS MAP_ANON
>+#ifndef MAP_ANONYMOUS
>+#define MAP_ANONYMOUS MAP_ANON
> #endif
>-
>-/* This mess was copied from the GNU getpagesize.h. */
>-#ifndef HAVE_GETPAGESIZE
>-# ifdef HAVE_UNISTD_H
>-# include <unistd.h>
>-# endif
>-
>-/* Assume that all systems that can run configure have sys/param.h. */
>-# ifndef HAVE_SYS_PARAM_H
>-# define HAVE_SYS_PARAM_H 1
>-# endif
>-
>-# ifdef _SC_PAGESIZE
>-# define getpagesize() sysconf(_SC_PAGESIZE)
>-# else /* no _SC_PAGESIZE */
>-# ifdef HAVE_SYS_PARAM_H
>-# include <sys/param.h>
>-# ifdef EXEC_PAGESIZE
>-# define getpagesize() EXEC_PAGESIZE
>-# else /* no EXEC_PAGESIZE */
>-# ifdef NBPG
>-# define getpagesize() NBPG * CLSIZE
>-# ifndef CLSIZE
>-# define CLSIZE 1
>-# endif /* no CLSIZE */
>-# else /* no NBPG */
>-# ifdef NBPC
>-# define getpagesize() NBPC
>-# else /* no NBPC */
>-# ifdef PAGESIZE
>-# define getpagesize() PAGESIZE
>-# endif /* PAGESIZE */
>-# endif /* no NBPC */
>-# endif /* no NBPG */
>-# endif /* no EXEC_PAGESIZE */
>-# else /* no HAVE_SYS_PARAM_H */
>-# define getpagesize() 8192 /* punt totally */
>-# endif /* no HAVE_SYS_PARAM_H */
>-# endif /* no _SC_PAGESIZE */
>-
>-#endif /* no HAVE_GETPAGESIZE */
>-
>-#ifndef MAP_FAILED
>-# define MAP_FAILED -1
>-#endif
>-
>-#undef perror_exit
>-#define perror_exit(str, val) \
>- do { perror(str); exit(val); } while (0)
>-
>-/* Some versions of cygwin mmap require that munmap is called with the
>- same parameters as mmap. GCC expects that this is not the case.
>- Test for various forms of this problem. Warning - icky signal games. */
>-
>-static sigset_t unblock_sigsegv;
>-static jmp_buf r;
>-static size_t pg;
>-static int devzero;
>-
>-static char *
>-anonmap (size)
>- size_t size;
>-{
>-#ifdef USE_MAP_ANON
>- return (char *) mmap (0, size, PROT_READ|PROT_WRITE,
>- MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
>-#else
>- return (char *) mmap (0, size, PROT_READ|PROT_WRITE,
>- MAP_PRIVATE, devzero, 0);
>-#endif
>-}
>-
>-static void
>-sigsegv (unused)
>- int unused;
>-{
>- sigprocmask (SIG_UNBLOCK, &unblock_sigsegv, 0);
>- longjmp (r, 1);
>-}
>-
>-/* Basic functionality test. */
>-void
>-test_0 ()
>-{
>- char *x = anonmap (pg);
>- if (x == (char *) MAP_FAILED)
>- perror_exit("test 0 mmap", 2);
>-
>- *(int *)x += 1;
>-
>- if (munmap(x, pg) < 0)
>- perror_exit("test 0 munmap", 3);
>-}
>-
>-/* 1. If we map a 2-page region and unmap its second page, the first page
>- must remain. */
>-static void
>-test_1 ()
>-{
>- char *x = anonmap (pg * 2);
>- if (x == (char *)MAP_FAILED)
>- perror_exit ("test 1 mmap", 4);
>-
>- signal (SIGSEGV, sigsegv);
>- if (setjmp (r))
>- perror_exit ("test 1 fault", 5);
>-
>- x[0] = 1;
>- x[pg] = 1;
>-
>- if (munmap (x + pg, pg) < 0)
>- perror_exit ("test 1 munmap 1", 6);
>- x[0] = 2;
>-
>- if (setjmp (r) == 0)
>- {
>- x[pg] = 1;
>- perror_exit ("test 1 no fault", 7);
>- }
>- if (munmap (x, pg) < 0)
>- perror_exit ("test 1 munmap 2", 8);
>-}
>-
>-/* 2. If we map a 2-page region and unmap its first page, the second
>- page must remain. */
>-static void
>-test_2 ()
>-{
>- char *x = anonmap (pg * 2);
>- if (x == (char *)MAP_FAILED)
>- perror_exit ("test 2 mmap", 9);
>-
>- signal (SIGSEGV, sigsegv);
>- if (setjmp (r))
>- perror_exit ("test 2 fault", 10);
>-
>- x[0] = 1;
>- x[pg] = 1;
>-
>- if (munmap (x, pg) < 0)
>- perror_exit ("test 2 munmap 1", 11);
>-
>- x[pg] = 2;
>-
>- if (setjmp (r) == 0)
>- {
>- x[0] = 1;
>- perror_exit ("test 2 no fault", 12);
>- }
>-
>- if (munmap (x+pg, pg) < 0)
>- perror_exit ("test 2 munmap 2", 13);
>-}
>-
>-/* 3. If we map two adjacent 1-page regions and unmap them both with
>- one munmap, both must go away.
>-
>- Getting two adjacent 1-page regions with two mmap calls is slightly
>- tricky. All OS's tested skip over already-allocated blocks; therefore
>- we have been careful to unmap all allocated regions in previous tests.
>- HP/UX allocates pages backward in memory. No OS has yet been observed
>- to be so perverse as to leave unmapped space between consecutive calls
>- to mmap. */
>-
>-static void
>-test_3 ()
>-{
>- char *x, *y, *z;
>-
>- x = anonmap (pg);
>- if (x == (char *)MAP_FAILED)
>- perror_exit ("test 3 mmap 1", 14);
>- y = anonmap (pg);
>- if (y == (char *)MAP_FAILED)
>- perror_exit ("test 3 mmap 2", 15);
>-
>- if (y != x + pg)
>- {
>- if (y == x - pg)
>- z = y, y = x, x = z;
>- else
>- {
>- fprintf (stderr, "test 3 nonconsecutive pages - %lx, %lx\n",
>- (unsigned long)x, (unsigned long)y);
>- exit (16);
>- }
>- }
>-
>- signal (SIGSEGV, sigsegv);
>- if (setjmp (r))
>- perror_exit ("test 3 fault", 17);
>-
>- x[0] = 1;
>- y[0] = 1;
>-
>- if (munmap (x, pg*2) < 0)
>- perror_exit ("test 3 munmap", 18);
>-
>- if (setjmp (r) == 0)
>- {
>- x[0] = 1;
>- perror_exit ("test 3 no fault 1", 19);
>- }
>-
>- signal (SIGSEGV, sigsegv);
>- if (setjmp (r) == 0)
>- {
>- y[0] = 1;
>- perror_exit ("test 3 no fault 2", 20);
>- }
>-}
>-
>-int
>-main ()
>-{
>- sigemptyset (&unblock_sigsegv);
>- sigaddset (&unblock_sigsegv, SIGSEGV);
>- pg = getpagesize ();
>-#ifndef USE_MAP_ANON
>- devzero = open ("/dev/zero", O_RDWR);
>- if (devzero < 0)
>- perror_exit ("open /dev/zero", 1);
>-#endif
>-
>- test_0();
>- test_1();
>- test_2();
>- test_3();
>-
>- exit(0);
>-}
>-EOF}}}
>-changequote([,])dnl
>-
>-AC_CACHE_CHECK(for working mmap from /dev/zero,
>- ac_cv_func_mmap_dev_zero,
>-[AC_TRY_RUN(
>- [#include "ct-mmap.inc"],
>- ac_cv_func_mmap_dev_zero=yes,
>- [if test $? -lt 4
>- then ac_cv_func_mmap_dev_zero=no
>- else ac_cv_func_mmap_dev_zero=buggy
>- fi],
>- # When cross-building, assume that this works, unless we know it
>- # doesn't. Of course, we have no way of knowing if there even is a /dev/zero
>- # on the host, let alone whether mmap will work on it.
>- [case "$host_os" in
>- cygwin* | win32 | pe | mingw* ) ac_cv_func_mmap_dev_zero=buggy ;;
>- darwin* ) ac_cv_func_mmap_dev_zero=no ;;
>- * ) ac_cv_func_mmap_dev_zero=yes ;;
>- esac])
>-])
>-if test $ac_cv_func_mmap_dev_zero = yes; then
>- AC_DEFINE(HAVE_MMAP_DEV_ZERO, 1,
>- [Define if mmap can get us zeroed pages from /dev/zero.])
>+],
>+[int n = MAP_ANONYMOUS;],
>+ gcc_cv_decl_map_anon=yes,
>+ gcc_cv_decl_map_anon=no)])
>+
>+ if test $gcc_cv_decl_map_anon = no; then
>+ gcc_cv_func_mmap_anon=no
>+ else
>+ AC_CACHE_CHECK([whether mmap with MAP_ANON(YMOUS) works],
>+ gcc_cv_func_mmap_anon,
>+ [# Add a system to this blacklist if it has mmap() and MAP_ANON or
>+ # MAP_ANONYMOUS, but using mmap(..., MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
>+ # doesn't give anonymous zeroed pages with the same properties listed
>+ # above for use of /dev/zero.
>+ # Systems known to be in this category are Windows, VMS, and SCO Unix.
>+ case "$host_os" in
>+ vms* | cygwin* | pe | mingw* | sco* | udk* )
>+ gcc_cv_func_mmap_anon=no ;;
>+ *)
>+ gcc_cv_func_mmap_anon=yes;;
>+ esac])
>+ fi
> fi
>
>-AC_CACHE_CHECK([for working mmap with MAP_ANON(YMOUS)],
>- ac_cv_func_mmap_anon,
>-[AC_TRY_RUN(
>- [#define USE_MAP_ANON
>-#include "ct-mmap.inc"],
>- ac_cv_func_mmap_anon=yes,
>- [if test $? -lt 4
>- then ac_cv_func_mmap_anon=no
>- else ac_cv_func_mmap_anon=buggy
>- fi],
>- # Unlike /dev/zero, it is not safe to assume MAP_ANON(YMOUS) works
>- # just because it's there. Some SCO Un*xen define it but don't implement it.
>- [case "$host_os" in
>- darwin* ) ac_cv_func_mmap_anon=yes ;;
>- * ) ac_cv_func_mmap_anon=no ;;
>- esac])
>-])
>-if test $ac_cv_func_mmap_anon = yes; then
>- AC_DEFINE(HAVE_MMAP_ANON, 1,
>- [Define if mmap can get us zeroed pages using MAP_ANON(YMOUS).])
>-fi
>-rm -f ct-mmap.inc
>-])
>-
>-# Check whether mmap can map a plain file, without MAP_FIXED.
>-AC_DEFUN([AC_FUNC_MMAP_FILE],
>-[AC_CACHE_CHECK(for working mmap of a file, ac_cv_func_mmap_file,
>-[# Create a file one thousand bytes long.
>-for i in 1 2 3 4 5 6 7 8 9 0
>-do for j in 1 2 3 4 5 6 7 8 9 0
>-do echo $i $j xxxxx
>-done
>-done > conftestdata$$
>-
>-AC_TRY_RUN([
>-/* Test by Zack Weinberg. Modified from MMAP_ANYWHERE test by
>- Richard Henderson and Alexandre Oliva.
>- Check whether read-only mmap of a plain file works. */
>-#include <sys/types.h>
>-#include <sys/stat.h>
>-#include <fcntl.h>
>-#include <sys/mman.h>
>-
>-int main()
>-{
>- char *x;
>- int fd;
>- struct stat st;
>-
>- fd = open("conftestdata$$", O_RDONLY);
>- if (fd < 0)
>- exit(1);
>-
>- if (fstat (fd, &st))
>- exit(2);
>-
>- x = (char*)mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
>- if (x == (char *) -1)
>- exit(3);
>-
>- if (x[0] != '1' || x[1] != ' ' || x[2] != '1' || x[3] != ' ')
>- exit(4);
>-
>- if (munmap(x, st.st_size) < 0)
>- exit(5);
>-
>- exit(0);
>-}], ac_cv_func_mmap_file=yes, ac_cv_func_mmap_file=no,
>- [case "$host_os" in
>- darwin* ) ac_cv_func_mmap_file=yes ;;
>- * ) ac_cv_func_mmap_file=no ;;
>- esac])])
>-if test $ac_cv_func_mmap_file = yes; then
>+if test $gcc_cv_func_mmap_file = yes; then
> AC_DEFINE(HAVE_MMAP_FILE, 1,
> [Define if read-only mmap of a plain file works.])
>+fi
>+if test $gcc_cv_func_mmap_dev_zero = yes; then
>+ AC_DEFINE(HAVE_MMAP_DEV_ZERO, 1,
>+ [Define if mmap of /dev/zero works.])
>+fi
>+if test $gcc_cv_func_mmap_anon = yes; then
>+ AC_DEFINE(HAVE_MMAP_ANON, 1,
>+ [Define if mmap with MAP_ANON(YMOUS) works.])
> fi
> ])
>
>===================================================================
>Index: configure.in
>--- configure.in 12 May 2003 22:30:24 -0000 1.668
>+++ configure.in 2 Jun 2003 04:42:47 -0000
>@@ -706,7 +706,7 @@ gcc_AC_HEADER_STDBOOL
> gcc_AC_HEADER_STRING
> AC_HEADER_SYS_WAIT
> AC_CHECK_HEADERS(limits.h stddef.h string.h strings.h stdlib.h time.h \
>- fcntl.h unistd.h sys/file.h sys/time.h \
>+ fcntl.h unistd.h sys/file.h sys/time.h sys/mman.h \
> sys/resource.h sys/param.h sys/times.h sys/stat.h \
> direct.h malloc.h langinfo.h ldfcn.h wchar.h)
>
>@@ -807,7 +807,7 @@ dnl gcc_AC_C_ENUM_BF_UNSIGNED
> AC_CHECK_FUNCS(times clock dup2 kill getrlimit setrlimit atoll atoq \
> sysconf strsignal putc_unlocked fputc_unlocked fputs_unlocked \
> fwrite_unlocked fprintf_unlocked getrusage nl_langinfo lstat \
>- scandir alphasort gettimeofday mbstowcs wcswidth)
>+ scandir alphasort gettimeofday mbstowcs wcswidth mmap)
>
> if test x$ac_cv_func_mbstowcs = xyes; then
> AC_CACHE_CHECK(whether mbstowcs works, gcc_cv_func_mbstowcs_works,
>@@ -850,6 +850,7 @@ fi
> AC_SUBST(TARGET_GETGROUPS_T)
>
> gcc_AC_FUNC_PRINTF_PTR
>+gcc_AC_FUNC_MMAP_BLACKLIST
>
> case "${host}" in
> *-*-uwin*)
>@@ -865,8 +866,6 @@ case "${host}" in
> ;;
> esac
> AC_FUNC_VFORK
>-AC_FUNC_MMAP_ANYWHERE
>-AC_FUNC_MMAP_FILE
>
> AM_ICONV
>