mmap checks by blacklist, not fragile AC_TRY_RUN test

Zack Weinberg zack@codesourcery.com
Mon Jun 2 04:45:00 GMT 2003


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.

zw

>         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
 



More information about the Gcc-patches mailing list