about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2024-12-21 15:32:17 +0100
committerptitSeb <sebastien.chev@gmail.com>2024-12-21 15:32:17 +0100
commit3e745474d3516891131d5efc1ec70486425a3b30 (patch)
tree0ed75add40be05d5adfc2ae168ab3fa3ae4a4f60 /src
parent5ad2f155c14faf25a5d54aafaf1c8bdc453d9c87 (diff)
downloadbox64-3e745474d3516891131d5efc1ec70486425a3b30.tar.gz
box64-3e745474d3516891131d5efc1ec70486425a3b30.zip
Improved memory tracking and 32bits memory allocation
Diffstat (limited to 'src')
-rw-r--r--src/custommem.c98
-rw-r--r--src/custommmap.c3
-rw-r--r--src/include/custommem.h6
-rw-r--r--src/tools/bridge.c13
-rw-r--r--src/wrapped/wrappedlibc.c58
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) {