[GC] "map remapping failed" in long-running server

Boehm, Hans hans_boehm@hp.com
Thu, 13 Nov 2003 15:39:01 -0800


This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

------_=_NextPart_000_01C3AA3F.51060A3C
Content-Type: text/plain;
	charset="iso-8859-1"

Here's the diff between the 6.3alpha2 os_dep.c and my current version.  I think none of these
changes depend on another file, so they could all be applied.  You would also need to arrange
for USE_MMAP_ANON to be defined.  (I think I posted the changes at the beginning of the file
earlier.  They address different issues which you probably won't see.  You could also use 
just the changes beyond line 1500.)  

All of this could use more testing ...

Hans

> -----Original Message-----
> From: Kenneth C. Schalk [mailto:ken@xorian.net]
> > 3) Some 2.4.x kernels were known to have problems with properly
> > merging mappings.  This is probably also aggravated by the
> > collectors use of maps against /dev/zero instead of MAP_ANON (which
> > I just fixed).
> 
> Any chance you could send me a patch for that change?
> 


------_=_NextPart_000_01C3AA3F.51060A3C
Content-Type: application/octet-stream;
	name="os_dep.c.diff"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="os_dep.c.diff"

--- os_dep.c	2003-09-22 15:49:47.000000000 -0700=0A=
+++ /home/hboehm/gc_master/os_dep.c	2003-11-11 14:26:13.000000000 =
-0800=0A=
@@ -115,6 +115,7 @@=0A=
 # include <sys/types.h>=0A=
 # include <sys/mman.h>=0A=
 # include <sys/stat.h>=0A=
+# include <errno.h>=0A=
 #endif=0A=
 =0A=
 #ifdef UNIX_LIKE=0A=
@@ -183,45 +184,41 @@=0A=
 /*=0A=
  * Apply fn to a buffer containing the contents of /proc/self/maps.=0A=
  * Return the result of fn or, if we failed, 0.=0A=
+ * We currently do nothing to /proc/self/maps other than simply =
read=0A=
+ * it.  This code could be simplified if we could determine its =
size=0A=
+ * ahead of time.=0A=
  */=0A=
 =0A=
 word GC_apply_to_maps(word (*fn)(char *))=0A=
 {=0A=
     int f;=0A=
     int result;=0A=
-    int maps_size;=0A=
-    char maps_temp[32768];=0A=
-    char *maps_buf;=0A=
-=0A=
-    /* Read /proc/self/maps	*/=0A=
-        /* Note that we may not allocate, and thus can't use stdio.	=
*/=0A=
-        f =3D open("/proc/self/maps", O_RDONLY);=0A=
-        if (-1 =3D=3D f) return 0;=0A=
-	/* stat() doesn't work for /proc/self/maps, so we have to=0A=
-	   read it to find out how large it is... */=0A=
-	maps_size =3D 0;=0A=
+    size_t maps_size =3D 4000;  /* Initial guess. 	*/=0A=
+    static char init_buf[1];=0A=
+    static char *maps_buf =3D init_buf;=0A=
+    static size_t maps_buf_sz =3D 1;=0A=
+=0A=
+    /* Read /proc/self/maps, growing maps_buf as necessary.	*/=0A=
+        /* Note that we may not allocate conventionally, and	*/=0A=
+        /* thus can't use stdio.				*/=0A=
 	do {=0A=
-	    result =3D GC_repeat_read(f, maps_temp, sizeof(maps_temp));=0A=
-	    if (result <=3D 0) return 0;=0A=
-	    maps_size +=3D result;=0A=
-	} while (result =3D=3D sizeof(maps_temp));=0A=
-=0A=
-	if (maps_size > sizeof(maps_temp)) {=0A=
-	    /* If larger than our buffer, close and re-read it. */=0A=
-	    close(f);=0A=
+	    if (maps_size >=3D maps_buf_sz) {=0A=
+	      /* Grow only by powers of 2, since we leak "too small" buffers. =
*/=0A=
+	      while (maps_size >=3D maps_buf_sz) maps_buf_sz *=3D 2;=0A=
+	      maps_buf =3D GC_scratch_alloc(maps_buf_sz);=0A=
+	      if (maps_buf =3D=3D 0) return 0;=0A=
+	    }=0A=
 	    f =3D open("/proc/self/maps", O_RDONLY);=0A=
 	    if (-1 =3D=3D f) return 0;=0A=
-	    maps_buf =3D alloca(maps_size);=0A=
-	    if (NULL =3D=3D maps_buf) return 0;=0A=
-	    result =3D GC_repeat_read(f, maps_buf, maps_size);=0A=
-	    if (result <=3D 0) return 0;=0A=
-	} else {=0A=
-	    /* Otherwise use the fixed size buffer */=0A=
-	    maps_buf =3D maps_temp;=0A=
-	}=0A=
-=0A=
-	close(f);=0A=
-        maps_buf[result] =3D '\0';=0A=
+	    maps_size =3D 0;=0A=
+	    do {=0A=
+	        result =3D GC_repeat_read(f, maps_buf, maps_buf_sz-1);=0A=
+	        if (result <=3D 0) return 0;=0A=
+	        maps_size +=3D result;=0A=
+	    } while (result =3D=3D maps_buf_sz-1);=0A=
+	    close(f);=0A=
+	} while (maps_size >=3D maps_buf_sz);=0A=
+        maps_buf[maps_size] =3D '\0';=0A=
 	=0A=
     /* Apply fn to result. */=0A=
 	return fn(maps_buf);=0A=
@@ -1535,6 +1532,10 @@=0A=
 #   define HEAP_START 0=0A=
 #endif=0A=
 =0A=
+#ifndef USE_MMAP_ANON=0A=
+  static int zero_fd;=0A=
+#endif =0A=
+=0A=
 ptr_t GC_unix_get_mem(bytes)=0A=
 word bytes;=0A=
 {=0A=
@@ -1543,11 +1544,10 @@=0A=
 =0A=
 #   ifndef USE_MMAP_ANON=0A=
       static GC_bool initialized =3D FALSE;=0A=
-      static int fd;=0A=
 =0A=
       if (!initialized) {=0A=
-	  fd =3D open("/dev/zero", O_RDONLY);=0A=
-	  fcntl(fd, F_SETFD, FD_CLOEXEC);=0A=
+	  zero_fd =3D open("/dev/zero", O_RDONLY);=0A=
+	  fcntl(zero_fd, F_SETFD, FD_CLOEXEC);=0A=
 	  initialized =3D TRUE;=0A=
       }=0A=
 #   endif=0A=
@@ -1558,7 +1558,7 @@=0A=
 		    GC_MMAP_FLAGS | MAP_ANON, -1, 0/* offset */);=0A=
 #   else=0A=
       result =3D mmap(last_addr, bytes, PROT_READ | PROT_WRITE | =
OPT_PROT_EXEC,=0A=
-		    GC_MMAP_FLAGS, fd, 0/* offset */);=0A=
+		    GC_MMAP_FLAGS, zero_fd, 0/* offset */);=0A=
 #   endif=0A=
     if (result =3D=3D MAP_FAILED) return(0);=0A=
     last_addr =3D (ptr_t)result + bytes + GC_page_size - 1;=0A=
@@ -1817,7 +1817,19 @@=0A=
 	  len -=3D free_len;=0A=
       }=0A=
 #   else=0A=
-      if (munmap(start_addr, len) !=3D 0) ABORT("munmap failed");=0A=
+      /* We immediately remap it to prevent an intervening mmap from	=
*/=0A=
+      /* accidentally grabbing the same address space.			*/=0A=
+      {=0A=
+	void * result;=0A=
+#       ifdef USE_MMAP_ANON=0A=
+          result =3D mmap(start_addr, len, PROT_NONE,=0A=
+		        MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0/* offset */);=0A=
+#       else=0A=
+          result =3D mmap(start_addr, len, PROT_NONE,=0A=
+		        MAP_PRIVATE | MAP_FIXED, zero_fd, 0/* offset */);=0A=
+#       endif=0A=
+        if (result !=3D (void *)start_addr) =
ABORT("mmap(...PROT_NONE...) failed");=0A=
+      }=0A=
       GC_unmapped_bytes +=3D len;=0A=
 #   endif=0A=
 }=0A=
@@ -1825,13 +1837,13 @@=0A=
 =0A=
 void GC_remap(ptr_t start, word bytes)=0A=
 {=0A=
-    static int zero_descr =3D -1;=0A=
     ptr_t start_addr =3D GC_unmap_start(start, bytes);=0A=
     ptr_t end_addr =3D GC_unmap_end(start, bytes);=0A=
     word len =3D end_addr - start_addr;=0A=
-    ptr_t result;=0A=
 =0A=
 #   if defined(MSWIN32) || defined(MSWINCE)=0A=
+      ptr_t result;=0A=
+=0A=
       if (0 =3D=3D start_addr) return;=0A=
       while (len !=3D 0) {=0A=
           MEMORY_BASIC_INFORMATION mem_info;=0A=
@@ -1851,13 +1863,17 @@=0A=
 	  len -=3D alloc_len;=0A=
       }=0A=
 #   else=0A=
-      if (-1 =3D=3D zero_descr) zero_descr =3D open("/dev/zero", =
O_RDWR);=0A=
-      fcntl(zero_descr, F_SETFD, FD_CLOEXEC);=0A=
+      /* It was already remapped with PROT_NONE. */=0A=
+      int result; =0A=
+=0A=
       if (0 =3D=3D start_addr) return;=0A=
-      result =3D mmap(start_addr, len, PROT_READ | PROT_WRITE | =
OPT_PROT_EXEC,=0A=
-		    MAP_FIXED | MAP_PRIVATE, zero_descr, 0);=0A=
-      if (result !=3D start_addr) {=0A=
-	  ABORT("mmap remapping failed");=0A=
+      result =3D mprotect(start_addr, len,=0A=
+		        PROT_READ | PROT_WRITE | OPT_PROT_EXEC);=0A=
+      if (result !=3D 0) {=0A=
+	  GC_err_printf3(=0A=
+		"Mprotect failed at 0x%lx (length %ld) with errno %ld\n",=0A=
+	        start_addr, len, errno);=0A=
+	  ABORT("Mprotect remapping failed");=0A=
       }=0A=
       GC_unmapped_bytes -=3D len;=0A=
 #   endif=0A=

------_=_NextPart_000_01C3AA3F.51060A3C--