summaryrefslogtreecommitdiff
path: root/rts
diff options
context:
space:
mode:
authorTamar Christina <tamar@zhox.com>2018-11-22 11:47:10 -0500
committerBen Gamari <ben@smart-cactus.org>2018-11-22 13:14:01 -0500
commit676f1f2d2eb39740fe5d88e72f6aa8e89cb0ebc0 (patch)
tree844a246a4e9383732f66091ffce0d5c7f7f4e91b /rts
parent7cba71fc25af8287db61f6f6aa80d45ce96404a7 (diff)
downloadhaskell-676f1f2d2eb39740fe5d88e72f6aa8e89cb0ebc0.tar.gz
rts: fix Windows megablock allocator
The megablock allocator does not currently check that after aligning the free region if it still has enough space to actually do the allocation. This causes it to return a memory region which it didn't fully allocate itself. Even worse, it can cause it to return a block with a region that will be present in two allocation pools. This causes if you're lucky an error from the OS that you're committing memory that has never been reserved, or causes random heap corruption. This change makes it consider the alignment as well. Test Plan: ./validate , testcase testmblockalloc Reviewers: bgamari, erikd, simonmar Reviewed By: simonmar Subscribers: rwbarton, carter Differential Revision: https://phabricator.haskell.org/D5363
Diffstat (limited to 'rts')
-rw-r--r--rts/win32/OSMem.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/rts/win32/OSMem.c b/rts/win32/OSMem.c
index c62ee3b7a4..57997b1ac5 100644
--- a/rts/win32/OSMem.c
+++ b/rts/win32/OSMem.c
@@ -144,8 +144,11 @@ findFreeBlocks(uint32_t n) {
temp.next=free_blocks; temp.base=0; temp.size=0;
prev=&temp;
/* TODO: Don't just take first block, find smallest sufficient block */
- for( ; it!=0 && it->size<required_size; prev=it, it=it->next ) {}
- if(it!=0) {
+ for ( ; it; prev=it, it=it->next )
+ {
+ if (!it || it->size < required_size)
+ continue;
+
if( (((W_)it->base) & MBLOCK_MASK) == 0) { /* MBlock aligned */
ret = (void*)it->base;
if(it->size==required_size) {
@@ -155,24 +158,30 @@ findFreeBlocks(uint32_t n) {
it->base += required_size;
it->size -=required_size;
}
+ break;
} else {
char* need_base;
block_rec* next;
int new_size;
need_base =
(char*)(((W_)it->base) & ((W_)~MBLOCK_MASK)) + MBLOCK_SIZE;
+ new_size = need_base - it->base;
+ /* Make sure that after alignment we have enough space. */
+ W_ total_size = new_size + required_size;
+ if (total_size > it->size)
+ continue;
next = (block_rec*)stgMallocBytes(
sizeof(block_rec)
, "getMBlocks: findFreeBlocks: splitting");
- new_size = need_base - it->base;
next->base = need_base +required_size;
- next->size = it->size - (new_size+required_size);
+ next->size = it->size - total_size;
it->size = new_size;
next->next = it->next;
it->next = next;
ret=(void*)need_base;
+ break;
}
- }
+ }
free_blocks=temp.next;
return ret;
}