diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2024-12-21 15:32:17 +0100 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2024-12-21 15:32:17 +0100 |
| commit | 3e745474d3516891131d5efc1ec70486425a3b30 (patch) | |
| tree | 0ed75add40be05d5adfc2ae168ab3fa3ae4a4f60 /src | |
| parent | 5ad2f155c14faf25a5d54aafaf1c8bdc453d9c87 (diff) | |
| download | box64-3e745474d3516891131d5efc1ec70486425a3b30.tar.gz box64-3e745474d3516891131d5efc1ec70486425a3b30.zip | |
Improved memory tracking and 32bits memory allocation
Diffstat (limited to 'src')
| -rw-r--r-- | src/custommem.c | 98 | ||||
| -rw-r--r-- | src/custommmap.c | 3 | ||||
| -rw-r--r-- | src/include/custommem.h | 6 | ||||
| -rw-r--r-- | src/tools/bridge.c | 13 | ||||
| -rw-r--r-- | src/wrapped/wrappedlibc.c | 58 |
5 files changed, 107 insertions, 71 deletions
diff --git a/src/custommem.c b/src/custommem.c index b22127d1..51ac28cb 100644 --- a/src/custommem.c +++ b/src/custommem.c @@ -86,6 +86,7 @@ typedef struct blocklist_s { static int n_blocks = 0; // number of blocks for custom malloc static int c_blocks = 0; // capacity of blocks for custom malloc static blocklist_t* p_blocks = NULL; // actual blocks for custom malloc +static int setting_prot = 0; typedef union mark_s { struct { @@ -318,6 +319,16 @@ static size_t sizeBlock(void* sub) return SIZE_BLOCK(s->next); } +static int isBlockChainCoherent(blockmark_t* m, blockmark_t* end) +{ + while(m) { + if(m>end) return 0; + if(m==end) return 1; + m = NEXT_BLOCK(m); + } + return 0; +} + // return 1 if block is coherent, 0 if not (and printf the issues) int printBlockCoherent(int i) { @@ -328,6 +339,8 @@ int printBlockCoherent(int i) int ret = 1; blockmark_t* m = (blockmark_t*)p_blocks[i].block; if(!m) {printf_log(LOG_NONE, "Warning, block #%d is NULL\n", i); return 0;} + // check coherency of the chained list first + if(!isBlockChainCoherent(m, (blockmark_t*)(p_blocks[i].block+p_blocks[i].size-sizeof(blockmark_t)))) {printf_log(LOG_NONE, "Warning, block #%d chained list is not coherent\n", i); return 0;} // check if first is correct blockmark_t* first = getNextFreeBlock(m); if(p_blocks[i].first && p_blocks[i].first!=first) {printf_log(LOG_NONE, "First %p and stored first %p differs for block %d\n", first, p_blocks[i].first, i); ret = 0;} @@ -491,13 +504,14 @@ void* internal_customMalloc(size_t size, int is32bits) p_blocks = (blocklist_t*)box_realloc(p_blocks, c_blocks*sizeof(blocklist_t)); } size_t allocsize = (fullsize>MMAPSIZE)?fullsize:MMAPSIZE; + allocsize = (allocsize+box64_pagesize-1)&~(box64_pagesize-1); p_blocks[i].block = NULL; // incase there is a re-entrance p_blocks[i].first = NULL; p_blocks[i].size = 0; if(is32bits) // unlocking, because mmap might use it mutex_unlock(&mutex_blocks); void* p = is32bits - ?mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_32BIT, -1, 0) + ?box_mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_32BIT, -1, 0) :internal_mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); if(is32bits) mutex_lock(&mutex_blocks); @@ -522,11 +536,13 @@ void* internal_customMalloc(size_t size, int is32bits) if(blockstree) rb_set(blockstree, (uintptr_t)p, (uintptr_t)p+allocsize, i); if(mapallmem) { - // defer the setProtection... - //setProtection((uintptr_t)p, allocsize, PROT_READ | PROT_WRITE); - defered_prot_p = (uintptr_t)p; - defered_prot_sz = allocsize; - defered_prot_prot = PROT_READ|PROT_WRITE; + if(setting_prot) { + // defer the setProtection... + defered_prot_p = (uintptr_t)p; + defered_prot_sz = allocsize; + defered_prot_prot = PROT_READ|PROT_WRITE; + } else + setProtection((uintptr_t)p, allocsize, PROT_READ | PROT_WRITE); } return ret; } @@ -1543,10 +1559,12 @@ void setProtection(uintptr_t addr, size_t size, uint32_t prot) { size = ALIGN(size); LOCK_PROT(); + ++setting_prot; uintptr_t cur = addr & ~(box64_pagesize-1); uintptr_t end = ALIGN(cur+size); rb_set(mapallmem, cur, end, 1); rb_set(memprot, cur, end, prot); + --setting_prot; UNLOCK_PROT(); } @@ -1923,6 +1941,20 @@ void my_reserveHighMem() #ifdef BOX32 if(box64_is32bits) { reverveHigMem32(); + // now reserve some memory in low address (because wine tend to allocate everything for itself) + void* p[20]; + #define SZ 2*1024*1024 + size_t n = sizeof(p)/sizeof(p[0]); + for(size_t i=0; i<n; ++i) + p[i] = box32_malloc(SZ-128); + if(box64_log>=LOG_DEBUG) { + printf_log(LOG_DEBUG, "Reserved %u MB of low memory [", (SZ)*n); + for(size_t i=0; i<n; ++i) + printf_log(LOG_DEBUG, "%p%s", p[i], (i==(n-1))?"]\n":", "); + } + for(size_t i=0; i<n; ++i) + box32_free(p[i]); + #undef SZ return; } #endif @@ -2154,3 +2186,57 @@ int internal_munmap(void* addr, unsigned long length) #endif return ret; } + +EXPORT void* box_mmap(void *addr, size_t length, int prot, int flags, int fd, ssize_t offset) +{ + if(prot&PROT_WRITE) + prot|=PROT_READ; // PROT_READ is implicit with PROT_WRITE on i386 + int new_flags = flags; + void* old_addr = addr; + #ifndef NOALIGN + new_flags&=~MAP_32BIT; // remove MAP_32BIT + if((flags&MAP_32BIT) && !(flags&MAP_FIXED)) { + // MAP_32BIT only exist on x86_64! + addr = find31bitBlockNearHint(old_addr, length, 0); + } else if (box64_wine || 1) { // other mmap should be restricted to 47bits + if (!(flags&MAP_FIXED) && !addr) + addr = find47bitBlock(length); + } + #endif + void* ret = internal_mmap(addr, length, prot, new_flags, fd, offset); + #if !defined(NOALIGN) + if((ret!=MAP_FAILED) && (flags&MAP_32BIT) && + (((uintptr_t)ret>0xffffffffLL) || ((box64_wine) && ((uintptr_t)ret&0xffff) && (ret!=addr)))) { + int olderr = errno; + internal_munmap(ret, length); + loadProtectionFromMap(); // reload map, because something went wrong previously + addr = find31bitBlockNearHint(old_addr, length, 0); // is this the best way? + new_flags = (addr && isBlockFree(addr, length) )? (new_flags|MAP_FIXED) : new_flags; + if((new_flags&(MAP_FIXED|MAP_FIXED_NOREPLACE))==(MAP_FIXED|MAP_FIXED_NOREPLACE)) new_flags&=~MAP_FIXED_NOREPLACE; + ret = internal_mmap(addr, length, prot, new_flags, fd, offset); + if(old_addr && ret!=old_addr && ret!=MAP_FAILED) + errno = olderr; + } else if((ret!=MAP_FAILED) && !(flags&MAP_FIXED) && ((box64_wine)) && (addr && (addr!=ret)) && + (((uintptr_t)ret>0x7fffffffffffLL) || ((uintptr_t)ret&~0xffff))) { + int olderr = errno; + internal_munmap(ret, length); + loadProtectionFromMap(); // reload map, because something went wrong previously + addr = find47bitBlockNearHint(old_addr, length, 0); // is this the best way? + new_flags = (addr && isBlockFree(addr, length)) ? (new_flags|MAP_FIXED) : new_flags; + if((new_flags&(MAP_FIXED|MAP_FIXED_NOREPLACE))==(MAP_FIXED|MAP_FIXED_NOREPLACE)) new_flags&=~MAP_FIXED_NOREPLACE; + ret = internal_mmap(addr, length, prot, new_flags, fd, offset); + if(old_addr && ret!=old_addr && ret!=MAP_FAILED) { + errno = olderr; + if(old_addr>(void*)0x7fffffffff && !have48bits) + errno = EEXIST; + } + } + #endif + return ret; +} + +EXPORT int box_munmap(void* addr, size_t length) +{ + int ret = internal_munmap(addr, length); + return ret; +} diff --git a/src/custommmap.c b/src/custommmap.c index ab5288dd..c33841f8 100644 --- a/src/custommmap.c +++ b/src/custommmap.c @@ -24,6 +24,7 @@ void setProtection(uintptr_t addr, size_t size, uint32_t prot); void freeProtection(uintptr_t addr, size_t size); void* internal_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset); int internal_munmap(void* addr, unsigned long length); +void* box_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset); void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset); @@ -34,7 +35,7 @@ EXPORT void* mmap64(void *addr, unsigned long length, int prot, int flags, int f { void* ret; if(!addr && ((running32bits && box64_mmap32) || (flags&MAP_32BIT) || box64_is32bits)) - ret = my_mmap64(NULL, addr, length, prot, flags | MAP_32BIT, fd, offset); + ret = box_mmap(addr, length, prot, flags | MAP_32BIT, fd, offset); else ret = internal_mmap(addr, length, prot, flags, fd, offset); if(ret!=MAP_FAILED && mapallmem) diff --git a/src/include/custommem.h b/src/include/custommem.h index 13874592..e21f5514 100644 --- a/src/include/custommem.h +++ b/src/include/custommem.h @@ -136,7 +136,13 @@ int isInHotPage(uintptr_t addr); int checkInHotPage(uintptr_t addr); #endif +// this will simulate an x86_64 version of the function (no tracking will done, but tracking will be used) +void* box_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset); +// this will simulate an x86_64 version of the function (no tracking will done) +int box_munmap(void* addr, unsigned long length); +// this will call the syscall directly void* internal_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset); +// this will call the syscall directly int internal_munmap(void* addr, unsigned long length); void reserveHighMem(); diff --git a/src/tools/bridge.c b/src/tools/bridge.c index 7684ec3d..b2f78d86 100644 --- a/src/tools/bridge.c +++ b/src/tools/bridge.c @@ -37,24 +37,18 @@ typedef struct bridge_s { kh_bridgemap_t *bridgemap; } bridge_t; -// from src/wrapped/wrappedlibc.c -void* my_mmap(x64emu_t* emu, void* addr, unsigned long length, int prot, int flags, int fd, int64_t offset); -int my_munmap(x64emu_t* emu, void* addr, unsigned long length); - brick_t* NewBrick(void* old) { brick_t* ret = (brick_t*)box_calloc(1, sizeof(brick_t)); if(old) old = old + NBRICK * sizeof(onebridge_t); - void* ptr = my_mmap(NULL, old, NBRICK * sizeof(onebridge_t), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | 0x40 | MAP_ANONYMOUS, -1, 0); // 0x40 is MAP_32BIT + void* ptr = box_mmap(old, NBRICK * sizeof(onebridge_t), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | 0x40 | MAP_ANONYMOUS, -1, 0); // 0x40 is MAP_32BIT if(ptr == MAP_FAILED) - ptr = my_mmap(NULL, NULL, NBRICK * sizeof(onebridge_t), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | 0x40 | MAP_ANONYMOUS, -1, 0); + ptr = box_mmap(NULL, NBRICK * sizeof(onebridge_t), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | 0x40 | MAP_ANONYMOUS, -1, 0); if(ptr == MAP_FAILED) { printf_log(LOG_NONE, "Warning, cannot allocate 0x%lx aligned bytes for bridge, will probably crash later\n", NBRICK*sizeof(onebridge_t)); } - #ifdef DYNAREC setProtection((uintptr_t)ptr, NBRICK * sizeof(onebridge_t), PROT_READ | PROT_WRITE | PROT_EXEC | PROT_NOPROT); - #endif dynarec_log(LOG_INFO, "New Bridge brick at %p (size 0x%zx)\n", ptr, NBRICK*sizeof(onebridge_t)); ret->b = ptr; return ret; @@ -77,7 +71,8 @@ void FreeBridge(bridge_t** bridge) while(b) { brick_t *n = b->next; dynarec_log(LOG_INFO, "FreeBridge brick at %p (size 0x%zx)\n", b->b, NBRICK*sizeof(onebridge_t)); - my_munmap(NULL, b->b, NBRICK*sizeof(onebridge_t)); + box_munmap(b->b, NBRICK*sizeof(onebridge_t)); + freeProtection((uintptr_t)b->b, NBRICK*sizeof(onebridge_t)); box_free(b); b = n; } diff --git a/src/wrapped/wrappedlibc.c b/src/wrapped/wrappedlibc.c index a34d8faf..c8d14760 100644 --- a/src/wrapped/wrappedlibc.c +++ b/src/wrapped/wrappedlibc.c @@ -2973,59 +2973,7 @@ extern int have48bits; EXPORT void* my_mmap64(x64emu_t* emu, void *addr, size_t length, int prot, int flags, int fd, ssize_t offset) { (void)emu; - if(prot&PROT_WRITE) - prot|=PROT_READ; // PROT_READ is implicit with PROT_WRITE on i386 - if((emu || box64_is32bits) && (box64_log>=LOG_DEBUG || box64_dynarec_log>=LOG_DEBUG)) {printf_log(LOG_NONE, "mmap64(%p, 0x%lx, 0x%x, 0x%x, %d, %ld) => ", addr, length, prot, flags, fd, offset);} - int new_flags = flags; - void* old_addr = addr; - #ifndef NOALIGN - new_flags&=~MAP_32BIT; // remove MAP_32BIT - if((flags&MAP_32BIT) && !(flags&MAP_FIXED)) { - // MAP_32BIT only exist on x86_64! - addr = find31bitBlockNearHint(old_addr, length, 0); - } else if (box64_wine || 1) { // other mmap should be restricted to 47bits - if (!(flags&MAP_FIXED) && !addr) - addr = find47bitBlock(length); - } - #endif - void* ret = internal_mmap(addr, length, prot, new_flags, fd, offset); - #if !defined(NOALIGN) - if((ret!=MAP_FAILED) && (flags&MAP_32BIT) && - (((uintptr_t)ret>0xffffffffLL) || ((box64_wine) && ((uintptr_t)ret&0xffff) && (ret!=addr)))) { - int olderr = errno; - if((emu || box64_is32bits) && (box64_log>=LOG_DEBUG || box64_dynarec_log>=LOG_DEBUG)) printf_log(LOG_NONE, "Warning, mmap on 32bits didn't worked, ask %p, got %p ", addr, ret); - internal_munmap(ret, length); - loadProtectionFromMap(); // reload map, because something went wrong previously - addr = find31bitBlockNearHint(old_addr, length, 0); // is this the best way? - new_flags = (addr && isBlockFree(addr, length) )? (new_flags|MAP_FIXED) : new_flags; - if((new_flags&(MAP_FIXED|MAP_FIXED_NOREPLACE))==(MAP_FIXED|MAP_FIXED_NOREPLACE)) new_flags&=~MAP_FIXED_NOREPLACE; - ret = internal_mmap(addr, length, prot, new_flags, fd, offset); - if((emu || box64_is32bits) && (box64_log>=LOG_DEBUG || box64_dynarec_log>=LOG_DEBUG)) printf_log(LOG_NONE, " tried again with %p, got %p\n", addr, ret); - if(old_addr && ret!=old_addr && ret!=MAP_FAILED) - errno = olderr; - } else if((ret!=MAP_FAILED) && !(flags&MAP_FIXED) && ((box64_wine)) && (addr && (addr!=ret)) && - (((uintptr_t)ret>0x7fffffffffffLL) || ((uintptr_t)ret&~0xffff))) { - int olderr = errno; - if((emu || box64_is32bits) && (box64_log>=LOG_DEBUG || box64_dynarec_log>=LOG_DEBUG)) printf_log(LOG_NONE, "Warning, mmap on 47bits didn't worked, ask %p, got %p ", addr, ret); - internal_munmap(ret, length); - loadProtectionFromMap(); // reload map, because something went wrong previously - addr = find47bitBlockNearHint(old_addr, length, 0); // is this the best way? - new_flags = (addr && isBlockFree(addr, length)) ? (new_flags|MAP_FIXED) : new_flags; - if((new_flags&(MAP_FIXED|MAP_FIXED_NOREPLACE))==(MAP_FIXED|MAP_FIXED_NOREPLACE)) new_flags&=~MAP_FIXED_NOREPLACE; - ret = internal_mmap(addr, length, prot, new_flags, fd, offset); - if((emu || box64_is32bits) && (box64_log>=LOG_DEBUG || box64_dynarec_log>=LOG_DEBUG)) printf_log(LOG_NONE, " tried again with %p, got %p\n", addr, ret); - if(old_addr && ret!=old_addr && ret!=MAP_FAILED) { - errno = olderr; - if(old_addr>(void*)0x7fffffffff && !have48bits) - errno = EEXIST; - } - } - #endif - if((ret!=MAP_FAILED) && (flags&MAP_FIXED_NOREPLACE) && (ret!=addr)) { - internal_munmap(ret, length); - errno = EEXIST; - return MAP_FAILED; - } + void* ret = box_mmap(addr, length, prot, flags, fd, offset); int e = errno; if((ret==MAP_FAILED && (emu || box64_is32bits)) && (box64_log>=LOG_DEBUG || box64_dynarec_log>=LOG_DEBUG)) {printf_log(LOG_NONE, "%s (%d)\n", strerror(errno), errno);} if(((ret!=MAP_FAILED) && (emu || box64_is32bits)) && (box64_log>=LOG_DEBUG || box64_dynarec_log>=LOG_DEBUG)) {printf_log(LOG_NONE, "%p\n", ret);} @@ -3071,7 +3019,7 @@ EXPORT void* my_mmap64(x64emu_t* emu, void *addr, size_t length, int prot, int f setProtection_mmap((uintptr_t)ret, length, prot); else setProtection((uintptr_t)ret, length, prot); - if(old_addr && ret!=old_addr) + if(addr && ret!=addr) e = EEXIST; } errno = e; // preserve errno @@ -3133,7 +3081,7 @@ EXPORT int my_munmap(x64emu_t* emu, void* addr, size_t length) { (void)emu; if((emu || box64_is32bits) && (box64_log>=LOG_DEBUG || box64_dynarec_log>=LOG_DEBUG)) {printf_log(LOG_NONE, "munmap(%p, 0x%lx)\n", addr, length);} - int ret = internal_munmap(addr, length); + int ret = box_munmap(addr, length); int e = errno; #ifdef DYNAREC if(!ret && box64_dynarec && length) { |