diff mbox

[libgo] Account for mmap ignoring addr arg without MAP_FIXED (PR go/48240)

Message ID ydd4o6ddhnh.fsf@manam.CeBiTec.Uni-Bielefeld.DE
State New
Headers show

Commit Message

Rainer Orth April 4, 2011, 5:56 p.m. UTC
As I had suspected, all the go and libgo testsuite failures on 64-bit
Solaris 10 were caused by mmap ignoring the addr argument without
MAP_FIXED.  That's the same problem already solved in
gcc/config/host-solaris.c.

The following code is inspired from mmap_fixed() there.  If this turns
out to be a license problem again (although iterating over an address
space range page by page is as obvious as it gets), I could recode it
along the lines of gcc/config/alpha/host-osf.c (mmap_fixed), but using
/proc/self/map and the corresponding ioctl instead.  This code is mine
(unlike the host-solaris.c one which originated with rth), so I'm free
to relicense as I please.  It's unfortunately far longer and harder to
read, but that might be the price to pay ;-(

Bootstrapped on i386-pc-solaris2.11 (where it is unnecessary since mmap
honors addr if possible) and i386-pc-solaris2.10 (where it's required
for the 64-bit tests).  There are several

panic: runtime error: invalid memory address or nil pointer dereference

for 64-bit Solaris 10 libgo tests, but all the 64-bit go tests pass
there, so the fundamental problem is gone.

	Rainer


2011-04-02  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>

	PR go/48240
	* configure.ac: Check for mincore.
	* configure: Regenerate.
	* config.h.in: Regenerate.
	* runtime/mem.c: Include unistd.h.
	(addrspace_free): New function.
	(runtime_SysMap): Retry 64-bit runtime_mmap with MAP_FIXED.

Comments

Ian Lance Taylor April 5, 2011, 12:02 a.m. UTC | #1
Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> writes:

> 2011-04-02  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
>
> 	PR go/48240
> 	* configure.ac: Check for mincore.
> 	* configure: Regenerate.
> 	* config.h.in: Regenerate.
> 	* runtime/mem.c: Include unistd.h.
> 	(addrspace_free): New function.
> 	(runtime_SysMap): Retry 64-bit runtime_mmap with MAP_FIXED.

Thanks for sorting this out.

Committed.

Ian
diff mbox

Patch

diff --git a/libgo/configure.ac b/libgo/configure.ac
--- a/libgo/configure.ac
+++ b/libgo/configure.ac
@@ -429,7 +429,7 @@  esac
 AC_CHECK_HEADERS(sys/mman.h syscall.h sys/epoll.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h)
 AM_CONDITIONAL(HAVE_SYS_MMAN_H, test "$ac_cv_header_sys_mman_h" = yes)
 
-AC_CHECK_FUNCS(srandom random strerror_r strsignal wait4)
+AC_CHECK_FUNCS(srandom random strerror_r strsignal wait4 mincore)
 AM_CONDITIONAL(HAVE_STRERROR_R, test "$ac_cv_func_strerror_r" = yes)
 AM_CONDITIONAL(HAVE_WAIT4, test "$ac_cv_func_wait4" = yes)
 
diff --git a/libgo/runtime/mem.c b/libgo/runtime/mem.c
--- a/libgo/runtime/mem.c
+++ b/libgo/runtime/mem.c
@@ -1,4 +1,5 @@ 
 #include <errno.h>
+#include <unistd.h>
 
 #include "runtime.h"
 #include "malloc.h"
@@ -16,6 +17,23 @@ 
 static int dev_zero = -1;
 #endif
 
+static _Bool
+addrspace_free(void *v __attribute__ ((unused)), uintptr n __attribute__ ((unused)))
+{
+#ifdef HAVE_MINCORE
+	size_t page_size = getpagesize();
+	size_t off;
+	char one_byte;
+
+	errno = 0;
+	for(off = 0; off < n; off += page_size)
+		if(mincore((char *)v + off, page_size, (char *)&one_byte) != -1
+		   || errno != ENOMEM)
+			return 0;
+#endif
+	return 1;
+}
+
 void*
 runtime_SysAlloc(uintptr n)
 {
@@ -109,7 +127,12 @@  runtime_SysMap(void *v, uintptr n)
 	// On 64-bit, we don't actually have v reserved, so tread carefully.
 	if(sizeof(void*) == 8) {
 		p = runtime_mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, fd, 0);
-		if(p != v) {
+		if(p != v && addrspace_free(v, n)) {
+			// On some systems, mmap ignores v without
+			// MAP_FIXED, so retry if the address space is free.
+			p = runtime_mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, fd, 0);
+		}
+		if (p != v) {
 			runtime_printf("runtime: address space conflict: map(%p) = %p\n", v, p);
 			runtime_throw("runtime: address space conflict");
 		}