Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/heap.cc')
-rw-r--r--winsup/cygwin/heap.cc91
1 files changed, 63 insertions, 28 deletions
diff --git a/winsup/cygwin/heap.cc b/winsup/cygwin/heap.cc
index 23093dda7..b10261cb6 100644
--- a/winsup/cygwin/heap.cc
+++ b/winsup/cygwin/heap.cc
@@ -1,7 +1,7 @@
/* heap.cc: Cygwin heap manager.
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc.
+ 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
This file is part of Cygwin.
@@ -22,13 +22,22 @@ details. */
#define assert(x)
-static unsigned page_const;
+static ptrdiff_t page_const;
#define MINHEAP_SIZE (4 * 1024 * 1024)
static uintptr_t
eval_start_address ()
{
+#ifdef __x86_64__
+ /* On 64 bit, we choose a fixed address outside the 32 bit area. The
+ executable starts at 0x1:00400000L, the Cygwin DLL starts at
+ 0x1:80040000L, other rebased DLLs are located in the region from
+ 0x2:00000000L up to 0x4:00000000L, -auto-image-based DLLs are located
+ in the region from 0x4:00000000L up to 0x6:00000000L.
+ So we let the heap start at 0x6:00000000L. */
+ uintptr_t start_address = 0x600000000L;
+#else
/* Starting with Vista, Windows performs heap ASLR. This spoils the entire
region below 0x20000000 for us, because that region is used by Windows
to randomize heap and stack addresses. Therefore we put our heap into a
@@ -53,30 +62,41 @@ eval_start_address ()
memory for heap, thread stacks, and shared memory regions. */
start_address = 0x80000000L;
}
+#endif
return start_address;
}
-static unsigned
+static SIZE_T
eval_initial_heap_size ()
{
PIMAGE_DOS_HEADER dosheader;
- PIMAGE_NT_HEADERS32 ntheader;
- unsigned size;
+ PIMAGE_NT_HEADERS ntheader;
+ SIZE_T size;
dosheader = (PIMAGE_DOS_HEADER) GetModuleHandle (NULL);
- ntheader = (PIMAGE_NT_HEADERS32) ((PBYTE) dosheader + dosheader->e_lfanew);
+ ntheader = (PIMAGE_NT_HEADERS) ((PBYTE) dosheader + dosheader->e_lfanew);
/* LoaderFlags is an obsolete DWORD member of the PE/COFF file header.
It's value is ignored by the loader, so we're free to use it for
- Cygwin. If it's 0, we default to the usual 384 Megs. Otherwise,
- we use it as the default initial heap size in megabyte. Valid values
- are between 4 and 2048 Megs. */
+ Cygwin. If it's 0, we default to the usual 384 Megs on 32 bit and
+ 512 on 64 bit. Otherwise, we use it as the default initial heap size
+ in megabyte. Valid values are between 4 and 2048/8388608 Megs. */
+
size = ntheader->OptionalHeader.LoaderFlags;
+#ifdef __x86_64__
+ if (size == 0)
+ size = 512;
+ else if (size < 4)
+ size = 4;
+ else if (size > 8388608)
+ size = 8388608;
+#else
if (size == 0)
size = 384;
else if (size < 4)
size = 4;
else if (size > 2048)
size = 2048;
+#endif
return size << 20;
}
@@ -93,7 +113,7 @@ heap_init ()
{
uintptr_t start_address = eval_start_address ();
PVOID largest_found = NULL;
- size_t largest_found_size = 0;
+ SIZE_T largest_found_size = 0;
SIZE_T ret;
MEMORY_BASIC_INFORMATION mbi;
@@ -156,7 +176,7 @@ heap_init ()
}
while (!cygheap->user_heap.base && ret);
if (cygheap->user_heap.base == NULL)
- api_fatal ("unable to allocate heap, heap_chunk_size %p, %E",
+ api_fatal ("unable to allocate heap, heap_chunk_size %ly, %E",
cygheap->user_heap.chunk);
cygheap->user_heap.ptr = cygheap->user_heap.top = cygheap->user_heap.base;
cygheap->user_heap.max = (char *) cygheap->user_heap.base
@@ -164,14 +184,21 @@ heap_init ()
}
else
{
- DWORD chunk = cygheap->user_heap.chunk; /* allocation chunk */
+ SIZE_T chunk = cygheap->user_heap.chunk; /* allocation chunk */
/* total size commited in parent */
- DWORD allocsize = (char *) cygheap->user_heap.top -
- (char *) cygheap->user_heap.base;
+ SIZE_T allocsize = (char *) cygheap->user_heap.top -
+ (char *) cygheap->user_heap.base;
/* Loop until we've managed to reserve an adequate amount of memory. */
char *p;
- DWORD reserve_size = chunk * ((allocsize + (chunk - 1)) / chunk);
+ SIZE_T reserve_size = chunk * ((allocsize + (chunk - 1)) / chunk);
+ /* With ptmalloc3 there's a good chance that there has been no memory
+ allocated on the heap. If we don't check that, reserve_size will
+ be 0 and from there, the below loop will end up overallocating due
+ to integer overflow. */
+ if (!reserve_size)
+ reserve_size = chunk;
+
while (1)
{
p = (char *) VirtualAlloc (cygheap->user_heap.base, reserve_size,
@@ -183,12 +210,14 @@ heap_init ()
}
if (!p && in_forkee && !fork_info->abort (NULL))
api_fatal ("couldn't allocate heap, %E, base %p, top %p, "
- "reserve_size %d, allocsize %d, page_const %d",
+ "reserve_size %ld, allocsize %ld, page_const %d",
cygheap->user_heap.base, cygheap->user_heap.top,
reserve_size, allocsize, page_const);
if (p != cygheap->user_heap.base)
- api_fatal ("heap allocated at wrong address %p (mapped) != %p (expected)", p, cygheap->user_heap.base);
- if (allocsize && !VirtualAlloc (cygheap->user_heap.base, allocsize, MEM_COMMIT, PAGE_READWRITE))
+ api_fatal ("heap allocated at wrong address %p (mapped) "
+ "!= %p (expected)", p, cygheap->user_heap.base);
+ if (allocsize && !VirtualAlloc (cygheap->user_heap.base, allocsize,
+ MEM_COMMIT, PAGE_READWRITE))
api_fatal ("MEM_COMMIT failed, %E");
}
@@ -198,7 +227,7 @@ heap_init ()
size has not been evaluated yet, except in a forked child. Since
heap_init is called early, the heap size is printed pretty much at the
start of the strace output, so there isn't anything lost. */
- debug_printf ("heap base %p, heap top %p, heap size %p (%u)",
+ debug_printf ("heap base %p, heap top %p, heap size %ly (%lu)",
cygheap->user_heap.base, cygheap->user_heap.top,
cygheap->user_heap.chunk, cygheap->user_heap.chunk);
page_const--;
@@ -209,11 +238,14 @@ heap_init ()
/* FIXME: This function no longer handles "split heaps". */
+/* Linux defines n to be intptr_t, newlib defines it to be ptrdiff_t.
+ It shouldn't matter much, though, since the function is not standarized
+ and sizeof(ptrdiff_t) == sizeof(intptr_t) anyway. */
extern "C" void *
-sbrk (int n)
+sbrk (ptrdiff_t n)
{
char *newtop, *newbrk;
- unsigned commitbytes, newbrksize;
+ SIZE_T commitbytes, newbrksize;
if (n == 0)
return cygheap->user_heap.ptr; /* Just wanted to find current cygheap->user_heap.ptr address */
@@ -230,9 +262,8 @@ sbrk (int n)
assert (newtop < cygheap->user_heap.top);
n = (char *) cygheap->user_heap.top - newtop;
if (VirtualFree (newtop, n, MEM_DECOMMIT)) /* Give it back to OS */
- goto good; /* Didn't take */
- else
- goto err;
+ goto good;
+ goto err; /* Didn't take */
}
assert (newtop > cygheap->user_heap.top);
@@ -256,11 +287,15 @@ sbrk (int n)
if ((newbrksize = cygheap->user_heap.chunk) < commitbytes)
newbrksize = commitbytes;
- if ((VirtualAlloc (cygheap->user_heap.top, newbrksize, MEM_RESERVE, PAGE_NOACCESS)
- || VirtualAlloc (cygheap->user_heap.top, newbrksize = commitbytes, MEM_RESERVE, PAGE_NOACCESS))
- && VirtualAlloc (cygheap->user_heap.top, commitbytes, MEM_COMMIT, PAGE_READWRITE) != NULL)
+ if ((VirtualAlloc (cygheap->user_heap.top, newbrksize,
+ MEM_RESERVE, PAGE_NOACCESS)
+ || VirtualAlloc (cygheap->user_heap.top, newbrksize = commitbytes,
+ MEM_RESERVE, PAGE_NOACCESS))
+ && VirtualAlloc (cygheap->user_heap.top, commitbytes,
+ MEM_COMMIT, PAGE_READWRITE) != NULL)
{
- cygheap->user_heap.max = (char *) cygheap->user_heap.max + pround (newbrksize);
+ cygheap->user_heap.max = (char *) cygheap->user_heap.max
+ + pround (newbrksize);
goto good;
}