]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: accurately record whether heap memory is reserved
authorIan Lance Taylor <iant@golang.org>
Tue, 25 Mar 2014 20:22:19 +0000 (13:22 -0700)
committerIan Lance Taylor <iant@golang.org>
Tue, 25 Mar 2014 20:22:19 +0000 (13:22 -0700)
The existing code did not have a clear notion of whether
memory has been actually reserved.  It checked based on
whether in 32-bit mode or 64-bit mode and (on GNU/Linux) the
requested address, but it confused the requested address and
the returned address.

LGTM=rsc
R=rsc, dvyukov
CC=golang-codereviews, michael.hudson
https://golang.org/cl/79610043

14 files changed:
src/pkg/runtime/malloc.goc
src/pkg/runtime/malloc.h
src/pkg/runtime/mem_darwin.c
src/pkg/runtime/mem_dragonfly.c
src/pkg/runtime/mem_freebsd.c
src/pkg/runtime/mem_linux.c
src/pkg/runtime/mem_nacl.c
src/pkg/runtime/mem_netbsd.c
src/pkg/runtime/mem_openbsd.c
src/pkg/runtime/mem_plan9.c
src/pkg/runtime/mem_solaris.c
src/pkg/runtime/mem_windows.c
src/pkg/runtime/mgc0.c
src/pkg/runtime/mheap.c

index 8f3603689c7f1f894895f57e8fcef327efdc90bf..03062adbbd701b22bfe0acc9570a495b4b619f60 100644 (file)
@@ -440,12 +440,14 @@ runtime·mallocinit(void)
        extern byte end[];
        uintptr limit;
        uint64 i;
+       bool reserved;
 
        p = nil;
        p_size = 0;
        arena_size = 0;
        bitmap_size = 0;
        spans_size = 0;
+       reserved = false;
 
        // for 64-bit build
        USED(p);
@@ -499,7 +501,7 @@ runtime·mallocinit(void)
                for(i = 0; i <= 0x7f; i++) {
                        p = (void*)(i<<40 | 0x00c0ULL<<32);
                        p_size = bitmap_size + spans_size + arena_size + PageSize;
-                       p = runtime·SysReserve(p, p_size);
+                       p = runtime·SysReserve(p, p_size, &reserved);
                        if(p != nil)
                                break;
                }
@@ -543,7 +545,7 @@ runtime·mallocinit(void)
                // to a MB boundary.
                p = (byte*)ROUND((uintptr)end + (1<<18), 1<<20);
                p_size = bitmap_size + spans_size + arena_size + PageSize;
-               p = runtime·SysReserve(p, p_size);
+               p = runtime·SysReserve(p, p_size, &reserved);
                if(p == nil)
                        runtime·throw("runtime: cannot reserve arena virtual address space");
        }
@@ -558,6 +560,7 @@ runtime·mallocinit(void)
        runtime·mheap.arena_start = p1 + spans_size + bitmap_size;
        runtime·mheap.arena_used = runtime·mheap.arena_start;
        runtime·mheap.arena_end = p + p_size;
+       runtime·mheap.arena_reserved = reserved;
 
        if(((uintptr)runtime·mheap.arena_start & (PageSize-1)) != 0)
                runtime·throw("misrounded allocation in mallocinit");
@@ -575,6 +578,7 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
 {
        byte *p, *p_end;
        uintptr p_size;
+       bool reserved;
 
        if(n > h->arena_end - h->arena_used) {
                // We are in 32-bit mode, maybe we didn't use all possible address space yet.
@@ -584,14 +588,19 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
                p_size = ROUND(n + PageSize, 256<<20);
                new_end = h->arena_end + p_size;
                if(new_end <= h->arena_start + MaxArena32) {
-                       p = runtime·SysReserve(h->arena_end, p_size);
-                       if(p == h->arena_end)
+                       // TODO: It would be bad if part of the arena
+                       // is reserved and part is not.
+                       p = runtime·SysReserve(h->arena_end, p_size, &reserved);
+                       if(p == h->arena_end) {
                                h->arena_end = new_end;
+                               h->arena_reserved = reserved;
+                       }
                        else if(p+p_size <= h->arena_start + MaxArena32) {
                                // Keep everything page-aligned.
                                // Our pages are bigger than hardware pages.
                                h->arena_end = p+p_size;
                                h->arena_used = p + (-(uintptr)p&(PageSize-1));
+                               h->arena_reserved = reserved;
                        } else {
                                uint64 stat;
                                stat = 0;
@@ -602,7 +611,7 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
        if(n <= h->arena_end - h->arena_used) {
                // Keep taking from our reservation.
                p = h->arena_used;
-               runtime·SysMap(p, n, &mstats.heap_sys);
+               runtime·SysMap(p, n, h->arena_reserved, &mstats.heap_sys);
                h->arena_used += n;
                runtime·MHeap_MapBits(h);
                runtime·MHeap_MapSpans(h);
@@ -615,7 +624,7 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
        }
        
        // If using 64-bit, our reservation is all we have.
-       if(sizeof(void*) == 8 && (uintptr)h->bitmap >= 0xffffffffU)
+       if(h->arena_end - h->arena_start >= MaxArena32)
                return nil;
 
        // On 32-bit, once the reservation is gone we can
index eb11cced68d5c09bffff6ea5849c4caf3fd13226..ca6289174e2eb100822b0593ea8c1d841d0bb6a0 100644 (file)
@@ -175,12 +175,18 @@ struct MLink
 // SysReserve reserves address space without allocating memory.
 // If the pointer passed to it is non-nil, the caller wants the
 // reservation there, but SysReserve can still choose another
-// location if that one is unavailable.
+// location if that one is unavailable.  On some systems and in some
+// cases SysReserve will simply check that the address space is
+// available and not actually reserve it.  If SysReserve returns
+// non-nil, it sets *reserved to true if the address space is
+// reserved, false if it has merely been checked.
 // NOTE: SysReserve returns OS-aligned memory, but the heap allocator
 // may use larger alignment, so the caller must be careful to realign the
 // memory obtained by SysAlloc.
 //
 // SysMap maps previously reserved address space for use.
+// The reserved argument is true if the address space was really
+// reserved, not merely checked.
 //
 // SysFault marks a (already SysAlloc'd) region to fault
 // if accessed.  Used only for debugging the runtime.
@@ -189,8 +195,8 @@ void*       runtime·SysAlloc(uintptr nbytes, uint64 *stat);
 void   runtime·SysFree(void *v, uintptr nbytes, uint64 *stat);
 void   runtime·SysUnused(void *v, uintptr nbytes);
 void   runtime·SysUsed(void *v, uintptr nbytes);
-void   runtime·SysMap(void *v, uintptr nbytes, uint64 *stat);
-void*  runtime·SysReserve(void *v, uintptr nbytes);
+void   runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat);
+void*  runtime·SysReserve(void *v, uintptr nbytes, bool *reserved);
 void   runtime·SysFault(void *v, uintptr nbytes);
 
 // FixAlloc is a simple free-list allocator for fixed size objects.
@@ -492,6 +498,7 @@ struct MHeap
        byte *arena_start;
        byte *arena_used;
        byte *arena_end;
+       bool arena_reserved;
 
        // central free lists for small size classes.
        // the padding makes sure that the MCentrals are
index 47fe2a525ffbd7f5b4152c00b24b6bf017da18b4..878c4e1c5577a48d8a003ee9af9e3076c03e6892 100644 (file)
@@ -48,10 +48,11 @@ runtime·SysFault(void *v, uintptr n)
 }
 
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
        void *p;
 
+       *reserved = true;
        p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
        if(p < (void*)4096)
                return nil;
@@ -64,10 +65,12 @@ enum
 };
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
        void *p;
        
+       USED(reserved);
+
        runtime·xadd64(stat, n);
        p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
        if(p == (void*)ENOMEM)
index ada820c2de814b134e11c2b7aace74da80543b95..c270332cb9e5d585e2926031f6050f5d799d18de 100644 (file)
@@ -52,16 +52,19 @@ runtime·SysFault(void *v, uintptr n)
 }
 
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
        void *p;
 
        // On 64-bit, people with ulimit -v set complain if we reserve too
        // much address space.  Instead, assume that the reservation is okay
        // and check the assumption in SysMap.
-       if(sizeof(void*) == 8)
+       if(sizeof(void*) == 8 && n > 1LL<<32) {
+               *reserved = false;
                return v;
-       
+       }
+
+       *reserved = true;
        p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
        if(p < (void*)4096)
                return nil;
@@ -69,14 +72,14 @@ runtime·SysReserve(void *v, uintptr n)
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
        void *p;
        
        runtime·xadd64(stat, n);
 
        // On 64-bit, we don't actually have v reserved, so tread carefully.
-       if(sizeof(void*) == 8) {
+       if(!reserved) {
                // TODO(jsing): For some reason DragonFly seems to return
                // memory at a different address than we requested, even when
                // there should be no reason for it to do so. This can be
index 1d6024013b8d5e7c1ffdd7a0242dfe49eeba993e..586947a2dcb257c2809580261079bd5c75b22a31 100644 (file)
@@ -52,16 +52,19 @@ runtime·SysFault(void *v, uintptr n)
 }
 
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
        void *p;
 
        // On 64-bit, people with ulimit -v set complain if we reserve too
        // much address space.  Instead, assume that the reservation is okay
        // and check the assumption in SysMap.
-       if(sizeof(void*) == 8)
+       if(sizeof(void*) == 8 && n > 1LL<<32) {
+               *reserved = false;
                return v;
-       
+       }
+
+       *reserved = true;
        p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
        if(p < (void*)4096)
                return nil;
@@ -69,14 +72,14 @@ runtime·SysReserve(void *v, uintptr n)
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
        void *p;
        
        runtime·xadd64(stat, n);
 
        // On 64-bit, we don't actually have v reserved, so tread carefully.
-       if(sizeof(void*) == 8) {
+       if(!reserved) {
                p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
                if(p == (void*)ENOMEM)
                        runtime·throw("runtime: out of memory");
index 2ead204101fb71ff38513689ec4bd0ba1e90cf72..3f997be96b609292967688d7bf0cdbd53288130e 100644 (file)
@@ -99,7 +99,7 @@ runtime·SysFault(void *v, uintptr n)
 }
 
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
        void *p;
 
@@ -107,7 +107,7 @@ runtime·SysReserve(void *v, uintptr n)
        // much address space.  Instead, assume that the reservation is okay
        // if we can reserve at least 64K and check the assumption in SysMap.
        // Only user-mode Linux (UML) rejects these requests.
-       if(sizeof(void*) == 8 && (uintptr)v >= 0xffffffffU) {
+       if(sizeof(void*) == 8 && n > 1LL<<32) {
                p = mmap_fixed(v, 64<<10, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
                if (p != v) {
                        if(p >= (void*)4096)
@@ -115,24 +115,26 @@ runtime·SysReserve(void *v, uintptr n)
                        return nil;
                }
                runtime·munmap(p, 64<<10);
+               *reserved = false;
                return v;
        }
 
        p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
        if((uintptr)p < 4096)
                return nil;
+       *reserved = true;
        return p;
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
        void *p;
        
        runtime·xadd64(stat, n);
 
        // On 64-bit, we don't actually have v reserved, so tread carefully.
-       if(sizeof(void*) == 8 && (uintptr)v >= 0xffffffffU) {
+       if(!reserved) {
                p = mmap_fixed(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
                if(p == (void*)ENOMEM)
                        runtime·throw("runtime: out of memory");
index c743259cc06d1d4129ab1f5a8a0046fc2c902580..e2bca40a4904b1b965a99da064772c8c1925165f 100644 (file)
@@ -60,31 +60,34 @@ runtime·SysFault(void *v, uintptr n)
 }
 
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
        void *p;
 
        // On 64-bit, people with ulimit -v set complain if we reserve too
        // much address space.  Instead, assume that the reservation is okay
        // and check the assumption in SysMap.
-       if(NaCl || sizeof(void*) == 8)
+       if(NaCl || sizeof(void*) == 8) {
+               *reserved = false;
                return v;
+       }
        
        p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
        if(p < (void*)4096)
                return nil;
+       *reserved = true;
        return p;
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
        void *p;
        
        runtime·xadd64(stat, n);
 
        // On 64-bit, we don't actually have v reserved, so tread carefully.
-       if(sizeof(void*) == 8) {
+       if(!reserved) {
                p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
                if(p == (void*)ENOMEM) {
                        runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
index ed0a05836999fc7dc0651591d2b1bde11750088d..861ae90c7e00941b2c7dfd65e81f7c3cb0d6d383 100644 (file)
@@ -52,31 +52,34 @@ runtime·SysFault(void *v, uintptr n)
 }
 
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
        void *p;
 
        // On 64-bit, people with ulimit -v set complain if we reserve too
        // much address space.  Instead, assume that the reservation is okay
        // and check the assumption in SysMap.
-       if(sizeof(void*) == 8)
+       if(sizeof(void*) == 8 && n > 1LL<<32) {
+               *reserved = false;
                return v;
+       }
 
        p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
        if(p < (void*)4096)
                return nil;
+       *reserved = true;
        return p;
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
        void *p;
        
        runtime·xadd64(stat, n);
 
        // On 64-bit, we don't actually have v reserved, so tread carefully.
-       if(sizeof(void*) == 8) {
+       if(!reserved) {
                p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
                if(p == (void*)ENOMEM)
                        runtime·throw("runtime: out of memory");
index ed0a05836999fc7dc0651591d2b1bde11750088d..861ae90c7e00941b2c7dfd65e81f7c3cb0d6d383 100644 (file)
@@ -52,31 +52,34 @@ runtime·SysFault(void *v, uintptr n)
 }
 
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
        void *p;
 
        // On 64-bit, people with ulimit -v set complain if we reserve too
        // much address space.  Instead, assume that the reservation is okay
        // and check the assumption in SysMap.
-       if(sizeof(void*) == 8)
+       if(sizeof(void*) == 8 && n > 1LL<<32) {
+               *reserved = false;
                return v;
+       }
 
        p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
        if(p < (void*)4096)
                return nil;
+       *reserved = true;
        return p;
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
        void *p;
        
        runtime·xadd64(stat, n);
 
        // On 64-bit, we don't actually have v reserved, so tread carefully.
-       if(sizeof(void*) == 8) {
+       if(!reserved) {
                p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
                if(p == (void*)ENOMEM)
                        runtime·throw("runtime: out of memory");
index 709ff69a1c410371f84b6292adfc72fc87559f7c..bbf04c7eda1d1d31a6762c9122153ca113d8453c 100644 (file)
@@ -62,9 +62,9 @@ runtime·SysUsed(void *v, uintptr nbytes)
 }
 
 void
-runtime·SysMap(void *v, uintptr nbytes, uint64 *stat)
+runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat)
 {
-       USED(v, nbytes, stat);
+       USED(v, nbytes, reserved, stat);
 }
 
 void
@@ -74,8 +74,9 @@ runtime·SysFault(void *v, uintptr nbytes)
 }
 
 void*
-runtime·SysReserve(void *v, uintptr nbytes)
+runtime·SysReserve(void *v, uintptr nbytes, bool *reserved)
 {
        USED(v);
+       *reserved = true;
        return runtime·SysAlloc(nbytes, &mstats.heap_sys);
 }
index f82a25b031275e443fa1263a17eb5f981f8278f1..034222887bce8247c2df62d2dcfdccd269422199 100644 (file)
@@ -53,31 +53,34 @@ runtime·SysFault(void *v, uintptr n)
 }
 
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
        void *p;
 
        // On 64-bit, people with ulimit -v set complain if we reserve too
        // much address space.  Instead, assume that the reservation is okay
        // and check the assumption in SysMap.
-       if(sizeof(void*) == 8)
+       if(sizeof(void*) == 8 && n > 1LL<<32) {
+               *reserved = false;
                return v;
+       }
        
        p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
        if(p < (void*)4096)
                return nil;
+       *reserved = true;
        return p;
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
        void *p;
        
        runtime·xadd64(stat, n);
 
        // On 64-bit, we don't actually have v reserved, so tread carefully.
-       if(sizeof(void*) == 8) {
+       if(!reserved) {
                p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
                if(p == (void*)ENOMEM)
                        runtime·throw("runtime: out of memory");
index c08200825995c9a0628d16df40e80f69b44c1622..551c96ce996229d1a0f703f585ba447b3df03748 100644 (file)
@@ -73,6 +73,7 @@ runtime·SysFault(void *v, uintptr n)
 void*
 runtime·SysReserve(void *v, uintptr n)
 {
+       *reserved = true;
        // v is just a hint.
        // First try at v.
        v = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_RESERVE, (uintptr)PAGE_READWRITE);
@@ -84,10 +85,12 @@ runtime·SysReserve(void *v, uintptr n)
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
        void *p;
-       
+
+       USED(reserved);
+
        runtime·xadd64(stat, n);
        p = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_COMMIT, (uintptr)PAGE_READWRITE);
        if(p != v)
index 87e016993358c0572d58900ced3afc327adacd23..166c52b2ad7da229ec4a98174e82475297a12933 100644 (file)
@@ -2773,6 +2773,6 @@ runtime·MHeap_MapBits(MHeap *h)
        if(h->bitmap_mapped >= n)
                return;
 
-       runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped, &mstats.gc_sys);
+       runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped, h->arena_reserved, &mstats.gc_sys);
        h->bitmap_mapped = n;
 }
index 93cf83f163cbdf47ba3d9515fef5689912b47156..0cb7043f440ffd0259c65d478fe7d6be331c9894 100644 (file)
@@ -85,7 +85,7 @@ runtime·MHeap_MapSpans(MHeap *h)
        n = ROUND(n, PhysPageSize);
        if(h->spans_mapped >= n)
                return;
-       runtime·SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, &mstats.other_sys);
+       runtime·SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, h->arena_reserved, &mstats.other_sys);
        h->spans_mapped = n;
 }