* 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.
This commit is contained in:
parent
6d6cfa4840
commit
883ea27df0
@ -1,3 +1,14 @@
|
|||||||
|
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>
|
2011-05-16 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* dcrt0.cc (child_info_fork::alloc_stack_hard_way): Check if the
|
* dcrt0.cc (child_info_fork::alloc_stack_hard_way): Check if the
|
||||||
|
@ -17,6 +17,7 @@ details. */
|
|||||||
#include "dtable.h"
|
#include "dtable.h"
|
||||||
#include "cygheap.h"
|
#include "cygheap.h"
|
||||||
#include "child_info.h"
|
#include "child_info.h"
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
#define assert(x)
|
#define assert(x)
|
||||||
|
|
||||||
@ -30,41 +31,85 @@ heap_init ()
|
|||||||
{
|
{
|
||||||
const DWORD alloctype = MEM_RESERVE;
|
const DWORD alloctype = MEM_RESERVE;
|
||||||
/* If we're the forkee, we must allocate the heap at exactly the same place
|
/* 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 ();
|
page_const = wincap.page_size ();
|
||||||
if (!cygheap->user_heap.base)
|
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 ();
|
cygheap->user_heap.chunk = cygwin_shared->heap_chunk_size ();
|
||||||
/* For some obscure reason Vista and 2003 sometimes reserve space after
|
do
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
/* Initialize page mask and default heap size. Preallocate a heap
|
cygheap->user_heap.base = VirtualAlloc ((LPVOID) start_address,
|
||||||
* to assure contiguous memory. */
|
cygheap->user_heap.chunk,
|
||||||
cygheap->user_heap.base =
|
|
||||||
VirtualAlloc (NULL, cygheap->user_heap.chunk
|
|
||||||
+ cygheap->user_heap.slop,
|
|
||||||
alloctype, PAGE_NOACCESS);
|
alloctype, PAGE_NOACCESS);
|
||||||
if (cygheap->user_heap.base)
|
if (cygheap->user_heap.base)
|
||||||
break;
|
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)
|
if (cygheap->user_heap.base == NULL)
|
||||||
api_fatal ("unable to allocate heap, heap_chunk_size %p, slop %p, %E",
|
api_fatal ("unable to allocate heap, heap_chunk_size %p, %E",
|
||||||
cygheap->user_heap.chunk, cygheap->user_heap.slop);
|
cygheap->user_heap.chunk);
|
||||||
cygheap->user_heap.base = (void *) ((char *) cygheap->user_heap.base
|
|
||||||
+ cygheap->user_heap.slop);
|
|
||||||
cygheap->user_heap.ptr = cygheap->user_heap.top = cygheap->user_heap.base;
|
cygheap->user_heap.ptr = cygheap->user_heap.top = cygheap->user_heap.base;
|
||||||
cygheap->user_heap.max = (char *) cygheap->user_heap.base
|
cygheap->user_heap.max = (char *) cygheap->user_heap.base
|
||||||
+ cygheap->user_heap.chunk;
|
+ cygheap->user_heap.chunk;
|
||||||
|
@ -440,27 +440,6 @@ memory_init (bool init_cygheap)
|
|||||||
user_info::create (false); /* Initialize per-user shared memory */
|
user_info::create (false); /* Initialize per-user shared memory */
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
unsigned
|
||||||
shared_info::heap_chunk_size ()
|
shared_info::heap_chunk_size ()
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,7 @@ public:
|
|||||||
/* Data accessible to all tasks */
|
/* Data accessible to all tasks */
|
||||||
|
|
||||||
|
|
||||||
#define CURR_SHARED_MAGIC 0x7f4db5d3U
|
#define CURR_SHARED_MAGIC 0xb41ae342U
|
||||||
|
|
||||||
#define USER_VERSION 1
|
#define USER_VERSION 1
|
||||||
#define CURR_USER_MAGIC 0x6112afb3U
|
#define CURR_USER_MAGIC 0x6112afb3U
|
||||||
@ -44,8 +44,6 @@ class shared_info
|
|||||||
DWORD cb;
|
DWORD cb;
|
||||||
public:
|
public:
|
||||||
DWORD heap_chunk;
|
DWORD heap_chunk;
|
||||||
bool heap_slop_inited;
|
|
||||||
DWORD heap_slop;
|
|
||||||
DWORD sys_mount_table_counter;
|
DWORD sys_mount_table_counter;
|
||||||
tty_list tty;
|
tty_list tty;
|
||||||
LONG last_used_bindresvport;
|
LONG last_used_bindresvport;
|
||||||
@ -55,7 +53,6 @@ class shared_info
|
|||||||
void initialize ();
|
void initialize ();
|
||||||
void init_obcaseinsensitive ();
|
void init_obcaseinsensitive ();
|
||||||
unsigned heap_chunk_size ();
|
unsigned heap_chunk_size ();
|
||||||
unsigned heap_slop_size ();
|
|
||||||
static void create ();
|
static void create ();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ details. */
|
|||||||
#define wincap_minimal wincap_2000
|
#define wincap_minimal wincap_2000
|
||||||
|
|
||||||
wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = {
|
wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = {
|
||||||
heapslop:0x0,
|
|
||||||
max_sys_priv:SE_MANAGE_VOLUME_PRIVILEGE,
|
max_sys_priv:SE_MANAGE_VOLUME_PRIVILEGE,
|
||||||
is_server:false,
|
is_server:false,
|
||||||
has_physical_mem_access:true,
|
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)) = {
|
wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = {
|
||||||
heapslop:0x0,
|
|
||||||
max_sys_priv:SE_CREATE_GLOBAL_PRIVILEGE,
|
max_sys_priv:SE_CREATE_GLOBAL_PRIVILEGE,
|
||||||
is_server:false,
|
is_server:false,
|
||||||
has_physical_mem_access:true,
|
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)) = {
|
wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = {
|
||||||
heapslop:0x0,
|
|
||||||
max_sys_priv:SE_MANAGE_VOLUME_PRIVILEGE,
|
max_sys_priv:SE_MANAGE_VOLUME_PRIVILEGE,
|
||||||
is_server:false,
|
is_server:false,
|
||||||
has_physical_mem_access:true,
|
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)) = {
|
wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = {
|
||||||
heapslop:0x0,
|
|
||||||
max_sys_priv:SE_MANAGE_VOLUME_PRIVILEGE,
|
max_sys_priv:SE_MANAGE_VOLUME_PRIVILEGE,
|
||||||
is_server:false,
|
is_server:false,
|
||||||
has_physical_mem_access:true,
|
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)) = {
|
wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = {
|
||||||
heapslop:0x0,
|
|
||||||
max_sys_priv:SE_CREATE_GLOBAL_PRIVILEGE,
|
max_sys_priv:SE_CREATE_GLOBAL_PRIVILEGE,
|
||||||
is_server:false,
|
is_server:false,
|
||||||
has_physical_mem_access:true,
|
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)) = {
|
wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
|
||||||
heapslop:0x4,
|
|
||||||
max_sys_priv:SE_CREATE_GLOBAL_PRIVILEGE,
|
max_sys_priv:SE_CREATE_GLOBAL_PRIVILEGE,
|
||||||
is_server:false,
|
is_server:false,
|
||||||
has_physical_mem_access: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)) = {
|
wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
|
||||||
heapslop:0x4,
|
|
||||||
max_sys_priv:SE_CREATE_SYMBOLIC_LINK_PRIVILEGE,
|
max_sys_priv:SE_CREATE_SYMBOLIC_LINK_PRIVILEGE,
|
||||||
is_server:false,
|
is_server:false,
|
||||||
has_physical_mem_access: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)) = {
|
wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
|
||||||
heapslop:0x4,
|
|
||||||
max_sys_priv:SE_CREATE_SYMBOLIC_LINK_PRIVILEGE,
|
max_sys_priv:SE_CREATE_SYMBOLIC_LINK_PRIVILEGE,
|
||||||
is_server:false,
|
is_server:false,
|
||||||
has_physical_mem_access:false,
|
has_physical_mem_access:false,
|
||||||
|
@ -14,7 +14,6 @@ details. */
|
|||||||
|
|
||||||
struct wincaps
|
struct wincaps
|
||||||
{
|
{
|
||||||
DWORD heapslop;
|
|
||||||
DWORD max_sys_priv;
|
DWORD max_sys_priv;
|
||||||
unsigned is_server : 1;
|
unsigned is_server : 1;
|
||||||
unsigned has_physical_mem_access : 1;
|
unsigned has_physical_mem_access : 1;
|
||||||
@ -64,7 +63,6 @@ public:
|
|||||||
|
|
||||||
#define IMPLEMENT(cap) cap() const { return ((wincaps *) this->caps)->cap; }
|
#define IMPLEMENT(cap) cap() const { return ((wincaps *) this->caps)->cap; }
|
||||||
|
|
||||||
DWORD IMPLEMENT (heapslop)
|
|
||||||
DWORD IMPLEMENT (max_sys_priv)
|
DWORD IMPLEMENT (max_sys_priv)
|
||||||
bool IMPLEMENT (is_server)
|
bool IMPLEMENT (is_server)
|
||||||
bool IMPLEMENT (has_physical_mem_access)
|
bool IMPLEMENT (has_physical_mem_access)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user