This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

mmap checks by blacklist, not fragile AC_TRY_RUN test


We have these huge complicated tests that try to detect nuances of
mmap() semantics, and we have at least two bug reports saying they
don't work.  This patch rips it all out and substitutes blacklists
for the small set of host systems that have problems.

Comments, including especially additions or subtractions from the
blacklist sets, would be appreciated.  Note that I gave up on
detecting the existence of /dev/zero -- this is unlikely to cause
trouble, since ggc-page.c prefers MAP_ANON(YMOUS).  However, any
system that has mmap() in its library but has neither MAP_ANON nor
/dev/zero *must* get put in the /dev/zero blacklist, or we'll get
runtime failures.  (I've changed the abort() in init_ggc on failing to
open /dev/zero to an internal_error() which reports errno, which
should help with the bug reports at least.)

i686-linux bootstrap running; testing would be appreciated on
blacklisted systems, and/or under the conditions that prompted the
original bug reports.

zw

        PR bootstrap/8365
        PR bootstrap/10284
        * 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.
        * ggc-page.c (init_ggc): Give better diagnostics on failure to
        open /dev/zero.

===================================================================
Index: aclocal.m4
--- aclocal.m4	21 Mar 2003 17:19:32 -0000	1.67
+++ aclocal.m4	1 Jun 2003 21:54:01 -0000
@@ -398,353 +398,89 @@ 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_anon=no
+   gcc_cv_func_mmap_dev_zero=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
+],
+[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
 
-/* 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
+if test $gcc_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.])
+	    [Define if mmap of /dev/zero works.])
 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).])
+	    [Define if mmap with MAP_ANON(YMOUS) works.])
 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
   AC_DEFINE(HAVE_MMAP_FILE, 1,
 	    [Define if read-only mmap of a plain file works.])
===================================================================
Index: configure.in
--- configure.in	12 May 2003 22:30:24 -0000	1.668
+++ configure.in	1 Jun 2003 21:54:04 -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
 
===================================================================
Index: ggc-page.c
--- ggc-page.c	13 May 2003 18:06:46 -0000	1.66
+++ ggc-page.c	1 Jun 2003 21:58:49 -0000
@@ -1287,7 +1287,7 @@ init_ggc ()
 #ifdef HAVE_MMAP_DEV_ZERO
   G.dev_zero_fd = open ("/dev/zero", O_RDONLY);
   if (G.dev_zero_fd == -1)
-    abort ();
+    internal_error ("open /dev/zero: %m");
 #endif
 
 #if 0


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]