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:
-rw-r--r--winsup/cygwin/ChangeLog11
-rw-r--r--winsup/cygwin/heap.cc95
-rw-r--r--winsup/cygwin/shared.cc21
-rw-r--r--winsup/cygwin/shared_info.h5
-rw-r--r--winsup/cygwin/wincap.cc8
-rw-r--r--winsup/cygwin/wincap.h2
6 files changed, 82 insertions, 60 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 8551e462c..28188c204 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,16 @@
2011-05-16 Corinna Vinschen <corinna@vinschen.de>
+ * heap.cc (heap_init): Rewrite initial heap allocation to use addresses
+ beyond 0x20000000. Explain why and how.
+ * shared.cc (shared_info::heap_slop_size): Remove.
+ * shared_info.h (class shared_info): Remove heap_slop_inited and
+ heap_slop members. Remove heap_slop_size declaration.
+ (CURR_SHARED_MAGIC): Update.
+ * wincap.cc: Throughout, drop heapslop.
+ * wincap.h (struct wincaps): Drop heapslop.
+
+2011-05-16 Corinna Vinschen <corinna@vinschen.de>
+
* dcrt0.cc (child_info_fork::alloc_stack_hard_way): Check if the
requested stack is application-provided within the user heap or an
mmapped region. If so, just use it. Add comment to explain why.
diff --git a/winsup/cygwin/heap.cc b/winsup/cygwin/heap.cc
index 21516d5c9..0fe170a89 100644
--- a/winsup/cygwin/heap.cc
+++ b/winsup/cygwin/heap.cc
@@ -17,6 +17,7 @@ details. */
#include "dtable.h"
#include "cygheap.h"
#include "child_info.h"
+#include <sys/param.h>
#define assert(x)
@@ -30,41 +31,85 @@ heap_init ()
{
const DWORD alloctype = MEM_RESERVE;
/* If we're the forkee, we must allocate the heap at exactly the same place
- as our parent. If not, we don't care where it ends up. */
+ as our parent. If not, we (almost) don't care where it ends up. */
page_const = wincap.page_size ();
if (!cygheap->user_heap.base)
{
+ /* 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 safe region starting at 0x20000000.
+ This should work right from the start in 99% of the cases. But,
+ there's always a but. Read on... */
+ uintptr_t start_address = 0x20000000L;
+ uintptr_t largest_found = 0;
+ size_t largest_found_size = 0;
+ SIZE_T ret;
+ MEMORY_BASIC_INFORMATION mbi;
+
cygheap->user_heap.chunk = cygwin_shared->heap_chunk_size ();
- /* For some obscure reason Vista and 2003 sometimes reserve space after
- calls to CreateProcess overlapping the spot where the heap has been
- allocated. This apparently spoils fork. The behaviour looks quite
- arbitrary. Experiments on Vista show a memory size of 0x37e000 or
- 0x1fd000 overlapping the usual heap by at most 0x1ed000. So what
- we do here is to allocate the heap with an extra slop of (by default)
- 0x400000 and set the appropriate pointers to the start of the heap
- area + slop. A forking child then creates its heap at the new start
- address and without the slop factor. Since this is not entirely
- foolproof we add a registry setting "heap_slop_in_mb" so the slop
- factor can be influenced by the user if the need arises. */
- cygheap->user_heap.slop = cygwin_shared->heap_slop_size ();
- while (cygheap->user_heap.chunk >= MINHEAP_SIZE)
+ do
{
- /* Initialize page mask and default heap size. Preallocate a heap
- * to assure contiguous memory. */
- cygheap->user_heap.base =
- VirtualAlloc (NULL, cygheap->user_heap.chunk
- + cygheap->user_heap.slop,
- alloctype, PAGE_NOACCESS);
+ cygheap->user_heap.base = VirtualAlloc ((LPVOID) start_address,
+ cygheap->user_heap.chunk,
+ alloctype, PAGE_NOACCESS);
if (cygheap->user_heap.base)
break;
- cygheap->user_heap.chunk -= 1 * 1024 * 1024;
+
+ /* Ok, so we are at the 1% which didn't work with 0x20000000 out
+ of the box. What we do now is to search for the next free
+ region which matches our desired heap size. While doing that,
+ we keep track of the largest region we found. */
+ start_address += wincap.allocation_granularity ();
+ while ((ret = VirtualQuery ((LPCVOID) start_address, &mbi,
+ sizeof mbi)) != 0)
+ {
+ if (mbi.State == MEM_FREE)
+ {
+ if (mbi.RegionSize >= cygheap->user_heap.chunk)
+ break;
+ if (mbi.RegionSize > largest_found_size)
+ {
+ largest_found = (uintptr_t) mbi.BaseAddress;
+ largest_found_size = mbi.RegionSize;
+ }
+ }
+ /* Since VirtualAlloc only reserves at allocation granularity
+ boundaries, we round up here, too. Otherwise we might end
+ up at a bogus page-aligned address. */
+ start_address = roundup2 (start_address + mbi.RegionSize,
+ wincap.allocation_granularity ());
+ }
+ if (!ret)
+ {
+ /* In theory this should not happen. But if it happens, we have
+ collected the information about the largest available region
+ in the above loop. So, next we squeeze the heap into that
+ region, unless it's smaller than the minimum size. */
+ if (largest_found_size >= MINHEAP_SIZE)
+ {
+ cygheap->user_heap.chunk = largest_found_size;
+ cygheap->user_heap.base =
+ VirtualAlloc ((LPVOID) start_address,
+ cygheap->user_heap.chunk,
+ alloctype, PAGE_NOACCESS);
+ }
+ /* Last resort (but actually we are probably broken anyway):
+ Use the minimal heap size and let the system decide. */
+ if (!cygheap->user_heap.base)
+ {
+ cygheap->user_heap.chunk = MINHEAP_SIZE;
+ cygheap->user_heap.base =
+ VirtualAlloc (NULL, cygheap->user_heap.chunk,
+ alloctype, PAGE_NOACCESS);
+ }
+ }
}
+ while (!cygheap->user_heap.base && ret);
if (cygheap->user_heap.base == NULL)
- api_fatal ("unable to allocate heap, heap_chunk_size %p, slop %p, %E",
- cygheap->user_heap.chunk, cygheap->user_heap.slop);
- cygheap->user_heap.base = (void *) ((char *) cygheap->user_heap.base
- + cygheap->user_heap.slop);
+ api_fatal ("unable to allocate heap, heap_chunk_size %p, %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
+ cygheap->user_heap.chunk;
diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc
index 60173cda6..0bfd4be8d 100644
--- a/winsup/cygwin/shared.cc
+++ b/winsup/cygwin/shared.cc
@@ -441,27 +441,6 @@ memory_init (bool init_cygheap)
}
unsigned
-shared_info::heap_slop_size ()
-{
- if (!heap_slop_inited)
- {
- /* Fetch from registry, first user then local machine. */
- for (int i = 0; i < 2; i++)
- {
- reg_key reg (i, KEY_READ, NULL);
-
- if ((heap_slop = reg.get_dword (L"heap_slop_in_mb", 0)))
- break;
- heap_slop = wincap.heapslop ();
- }
- heap_slop <<= 20;
- heap_slop_inited = true;
- }
-
- return heap_slop;
-}
-
-unsigned
shared_info::heap_chunk_size ()
{
if (!heap_chunk)
diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h
index 5a083f8fa..feb8ff1da 100644
--- a/winsup/cygwin/shared_info.h
+++ b/winsup/cygwin/shared_info.h
@@ -30,7 +30,7 @@ public:
/* Data accessible to all tasks */
-#define CURR_SHARED_MAGIC 0x7f4db5d3U
+#define CURR_SHARED_MAGIC 0xb41ae342U
#define USER_VERSION 1
#define CURR_USER_MAGIC 0x6112afb3U
@@ -44,8 +44,6 @@ class shared_info
DWORD cb;
public:
DWORD heap_chunk;
- bool heap_slop_inited;
- DWORD heap_slop;
DWORD sys_mount_table_counter;
tty_list tty;
LONG last_used_bindresvport;
@@ -55,7 +53,6 @@ class shared_info
void initialize ();
void init_obcaseinsensitive ();
unsigned heap_chunk_size ();
- unsigned heap_slop_size ();
static void create ();
};
diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc
index aac916ba4..b959d1e57 100644
--- a/winsup/cygwin/wincap.cc
+++ b/winsup/cygwin/wincap.cc
@@ -24,7 +24,6 @@ details. */
#define wincap_minimal wincap_2000
wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = {
- heapslop:0x0,
max_sys_priv:SE_MANAGE_VOLUME_PRIVILEGE,
is_server:false,
has_physical_mem_access:true,
@@ -55,7 +54,6 @@ wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = {
};
wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = {
- heapslop:0x0,
max_sys_priv:SE_CREATE_GLOBAL_PRIVILEGE,
is_server:false,
has_physical_mem_access:true,
@@ -86,7 +84,6 @@ wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) =
};
wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = {
- heapslop:0x0,
max_sys_priv:SE_MANAGE_VOLUME_PRIVILEGE,
is_server:false,
has_physical_mem_access:true,
@@ -117,7 +114,6 @@ wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = {
};
wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = {
- heapslop:0x0,
max_sys_priv:SE_MANAGE_VOLUME_PRIVILEGE,
is_server:false,
has_physical_mem_access:true,
@@ -148,7 +144,6 @@ wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = {
};
wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = {
- heapslop:0x0,
max_sys_priv:SE_CREATE_GLOBAL_PRIVILEGE,
is_server:false,
has_physical_mem_access:true,
@@ -179,7 +174,6 @@ wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = {
};
wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
- heapslop:0x4,
max_sys_priv:SE_CREATE_GLOBAL_PRIVILEGE,
is_server:false,
has_physical_mem_access:false,
@@ -210,7 +204,6 @@ wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
};
wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
- heapslop:0x4,
max_sys_priv:SE_CREATE_SYMBOLIC_LINK_PRIVILEGE,
is_server:false,
has_physical_mem_access:false,
@@ -241,7 +234,6 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
};
wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
- heapslop:0x4,
max_sys_priv:SE_CREATE_SYMBOLIC_LINK_PRIVILEGE,
is_server:false,
has_physical_mem_access:false,
diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h
index 52af5b96b..629a062cd 100644
--- a/winsup/cygwin/wincap.h
+++ b/winsup/cygwin/wincap.h
@@ -14,7 +14,6 @@ details. */
struct wincaps
{
- DWORD heapslop;
DWORD max_sys_priv;
unsigned is_server : 1;
unsigned has_physical_mem_access : 1;
@@ -64,7 +63,6 @@ public:
#define IMPLEMENT(cap) cap() const { return ((wincaps *) this->caps)->cap; }
- DWORD IMPLEMENT (heapslop)
DWORD IMPLEMENT (max_sys_priv)
bool IMPLEMENT (is_server)
bool IMPLEMENT (has_physical_mem_access)