From 75eb27a4937b9173b6c8102a17428b67ea65d267 Mon Sep 17 00:00:00 2001 From: Lightning11wins Date: Mon, 15 Dec 2025 09:19:09 -0700 Subject: [PATCH 1/7] Improve code clarity with minimal logic modifications. --- centrallix-lib/include/newmalloc.h | 10 +- centrallix-lib/src/newmalloc.c | 604 +++++++++++++++-------------- 2 files changed, 321 insertions(+), 293 deletions(-) diff --git a/centrallix-lib/include/newmalloc.h b/centrallix-lib/include/newmalloc.h index 6022e72e3..038df686a 100644 --- a/centrallix-lib/include/newmalloc.h +++ b/centrallix-lib/include/newmalloc.h @@ -32,7 +32,7 @@ typedef struct _ov int Magic; struct _ov *Next; } - Overlay,*pOverlay; + Overlay, *pOverlay; #ifdef NMMALLOC_DEBUG #define BLK_LEAK_CHECK 1 @@ -70,15 +70,15 @@ void nmSetErrFunction(int (*error_fn)()); void nmClear(); void nmCheckAll(); // checks for buffer overflows void* nmMalloc(int size); -void nmFree(void* ptr,int size); +void nmFree(void* ptr, int size); void nmStats(); -void nmRegister(int size,char* name); +void nmRegister(int size, char* name); void nmDebug(); void nmDeltas(); void* nmSysMalloc(int size); void nmSysFree(void* ptr); -void* nmSysRealloc(void* ptr, int newsize); -char* nmSysStrdup(const char* ptr); +void* nmSysRealloc(void* ptr, int new_size); +char* nmSysStrdup(const char* str); void nmEnableTagging(); void nmRegisterTagID(int tag_id, char* name); diff --git a/centrallix-lib/src/newmalloc.c b/centrallix-lib/src/newmalloc.c index 32c02b85d..117f53c20 100644 --- a/centrallix-lib/src/newmalloc.c +++ b/centrallix-lib/src/newmalloc.c @@ -1,13 +1,3 @@ -#ifdef HAVE_CONFIG_H -#include "cxlibconfig-internal.h" -#endif -#include -#include -#include -#include -#include "magic.h" -#include "newmalloc.h" - /************************************************************************/ /* Centrallix Application Server System */ /* Centrallix Base Library */ @@ -36,6 +26,18 @@ /* all.... */ /************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "cxlibconfig-internal.h" +#endif + +#include +#include +#include +#include +#include + +#include "magic.h" +#include "newmalloc.h" /** define BUFFER_OVERFLOW_CHECKING for buffer overflow checking @@ -56,8 +58,8 @@ typedef struct _mem struct _mem *next; int magic_start; /** not 'really' here **/ - //char data[size]; - //int magic_end; + // char data[size]; + // int magic_end; } MemStruct, *pMemStruct; #define EXTRA_MEM (3*sizeof(int)+sizeof(void*)) @@ -84,7 +86,7 @@ void* blks[MAX_BLOCKS]; int blksiz[MAX_BLOCKS]; #endif -int isinit=0; +bool is_init = false; int (*err_fn)() = NULL; int nmsys_outcnt[MAX_SIZE+1]; @@ -101,191 +103,206 @@ typedef struct _RB pRegisteredBlockType blknames[MAX_SIZE+1]; + void nmInitialize() { - int i; - - for(i=0;i<=MAX_SIZE;i++) lists[i]=NULL; - for(i=0;i<=MAX_SIZE;i++) listcnt[i] = 0; - for(i=0;i<=MAX_SIZE;i++) outcnt[i] = 0; - for(i=0;i<=MAX_SIZE;i++) outcnt_delta[i] = 0; - for(i=0;i<=MAX_SIZE;i++) blknames[i] = NULL; - for(i=0;i<=MAX_SIZE;i++) usagecnt[i] = 0; - for(i=0;i<=MAX_SIZE;i++) nmsys_outcnt[i] = 0; - for(i=0;i<=MAX_SIZE;i++) nmsys_outcnt_delta[i] = 0; + for (int i = 0; i <= MAX_SIZE; i++) lists[i] = NULL; + for (int i = 0; i <= MAX_SIZE; i++) listcnt[i] = 0; + for (int i = 0; i <= MAX_SIZE; i++) outcnt[i] = 0; + for (int i = 0; i <= MAX_SIZE; i++) outcnt_delta[i] = 0; + for (int i = 0; i <= MAX_SIZE; i++) blknames[i] = NULL; + for (int i = 0; i <= MAX_SIZE; i++) usagecnt[i] = 0; + for (int i = 0; i <= MAX_SIZE; i++) nmsys_outcnt[i] = 0; + for (int i = 0; i <= MAX_SIZE; i++) nmsys_outcnt_delta[i] = 0; + #ifdef BLK_LEAK_CHECK - for(i=0;imagic_start!=MGK_MEMSTART) - { - printf("bad magic_start at %p (%p) -- 0x%08x != 0x%08x\n",MEMDATA(mem),mem,mem->magic_start,MGK_MEMSTART); - ret = -1; - } - if(ENDMAGIC(mem)!=MGK_MEMEND) - { - printf("bad magic_end at %p (%p) -- 0x%08x != 0x%08x\n",MEMDATA(mem),mem,ENDMAGIC(mem),MGK_MEMEND); - ret = -1; - } + int ret = 0; + + if (mem->magic_start != MGK_MEMSTART) + { + fprintf(stderr, + "Bad magic_start at %p (%p) -- 0x%08x != 0x%08x\n", + MEMDATA(mem), mem, mem->magic_start, MGK_MEMSTART + ); + ret = -1; + } + + if (ENDMAGIC(mem) != MGK_MEMEND) + { + fprintf(stderr, + "Bad magic_end at %p (%p) -- 0x%08x != 0x%08x\n", + MEMDATA(mem), mem, ENDMAGIC(mem), MGK_MEMEND + ); + ret = -1; + } + return ret; } #endif + void nmCheckAll() { #ifdef BUFFER_OVERFLOW_CHECKING - pMemStruct mem; - int ret=0; - mem=startMemList; - while(mem) - { - if(nmCheckItem(mem)==-1) - ret=-1; - mem=mem->next; - } - if(ret==-1) - { - printf("causing segfault to halt.......\n"); - *(int*)NULL=0; - } + int ret = 0; + + for (pMemStruct mem = startMemList; mem != NULL; mem = mem->next) + if (nmCheckItem(mem) == -1) ret = -1; + + if (ret == -1) + { + printf("causing segfault to halt.......\n"); + *(int*)NULL = 0; + } #endif + + return; } + #ifdef BUFFER_OVERFLOW_CHECKING void* nmDebugMalloc(int size) { - pMemStruct tmp; - - tmp = (pMemStruct)malloc(size+EXTRA_MEM); - if(!tmp) - return NULL; - tmp->next = startMemList; - startMemList=tmp; - tmp->size=size; - tmp->magic_start=MGK_MEMSTART; - ENDMAGIC(tmp)=MGK_MEMEND; + pMemStruct tmp = (pMemStruct)malloc(size + EXTRA_MEM); + if(tmp == NULL) return NULL; + + tmp->size = size; + tmp->magic_start = MGK_MEMSTART; + ENDMAGIC(tmp) = MGK_MEMEND; + + tmp->next = startMemList; + startMemList = tmp; return (void*)MEMDATA(tmp); } + void -nmDebugFree(void *ptr) +nmDebugFree(void* ptr) { - pMemStruct tmp; - pMemStruct prev; - - tmp = MEMDATATOSTRUCT(ptr); - nmCheckItem(tmp); - if(tmp==startMemList) - { - startMemList=tmp->next; - } - else - { - prev = startMemList; - while(prev->next != tmp) - prev=prev->next; - prev->next=tmp->next; - } - free(tmp); + pMemStruct tmp = MEMDATATOSTRUCT(ptr); + + nmCheckItem(tmp); + + if (tmp == startMemList) + { + startMemList = tmp->next; + } + else + { + pMemStruct prev = startMemList; + while (prev->next != tmp) + prev = prev->next; + + prev->next = tmp->next; + } + + free(tmp); + + return; } -void* -nmDebugRealloc(void *ptr,int newsize) + +void* +nmDebugRealloc(void* ptr, int new_size) { - void *newptr; - int oldsize; - - if(!ptr) - return nmDebugMalloc(newsize); - newptr=(void*)nmDebugMalloc(newsize); - if(!newptr) - return NULL; - oldsize=MEMDATATOSTRUCT(ptr)->size; - memmove(newptr,ptr,oldsize); - nmDebugFree(ptr); - return newptr; + if (ptr == NULL) return nmDebugMalloc(new_size); + + void* new_ptr = (void*)nmDebugMalloc(new_size); + if (new_ptr == NULL) return NULL; + + int old_size = MEMDATATOSTRUCT(ptr)->size; + memmove(new_ptr, ptr, old_size); + + nmDebugFree(ptr); + + return new_ptr; } #else -#define nmDebugMalloc(size) malloc(size) -#define nmDebugFree(ptr) free(ptr) -#define nmDebugRealloc(ptr,size) realloc(ptr,size) + #define nmDebugMalloc(size) malloc(size) + #define nmDebugFree(ptr) free(ptr) + #define nmDebugRealloc(ptr,size) realloc(ptr,size) #endif + void nmSetErrFunction(int (*error_fn)()) { - err_fn = error_fn; + err_fn = error_fn; + return; } + void nmClear() { - int i; - pOverlay ov,del; - - if (!isinit) nmInitialize(); - - for(i=MIN_SIZE;i<=MAX_SIZE;i++) + if (!is_init) nmInitialize(); + + for (size_t size = MIN_SIZE; size <= MAX_SIZE; size++) { - ov = lists[i]; - while(ov) - { - del = ov; + pOverlay ov = lists[size]; + while (ov != NULL) + { + pOverlay del = ov; ov = ov->Next; nmDebugFree(del); } - lists[i] = NULL; + lists[size] = NULL; } - + return; } + void* nmMalloc(int size) { - void* tmp; -#ifdef BLK_LEAK_CHECK - int i; -#endif - - if (!isinit) nmInitialize(); - + void* tmp = NULL; + + if (!is_init) nmInitialize(); + #ifdef GLOBAL_BLK_COUNTING nmMallocCnt++; #endif - + #ifdef BUFFER_OVERFLOW_CHECKING nmCheckAll(); #endif - - if (size <= MAX_SIZE && size >= MIN_SIZE) + + if (MIN_SIZE <= size && size <= MAX_SIZE) { #ifdef SIZED_BLK_COUNTING outcnt[size]++; usagecnt[size]++; #endif + if (lists[size] == NULL) { tmp = (void*)nmDebugMalloc(size); @@ -295,9 +312,11 @@ nmMalloc(int size) #ifdef GLOBAL_BLK_COUNTING nmMallocHits++; #endif - tmp = lists[size]; - ASSERTMAGIC(tmp,MGK_FREEMEM); - lists[size]=lists[size]->Next; + + tmp = lists[size]; + ASSERTMAGIC(tmp, MGK_FREEMEM); + lists[size] = lists[size]->Next; + #ifdef SIZED_BLK_COUNTING listcnt[size]--; #endif @@ -309,10 +328,11 @@ nmMalloc(int size) nmMallocTooBig++; if (size > nmMallocLargest) nmMallocLargest = size; #endif + tmp = (void*)nmDebugMalloc(size); } - - if (!tmp) + + if (tmp == NULL) { if (err_fn) err_fn("Insufficient system memory for operation."); } @@ -321,13 +341,13 @@ nmMalloc(int size) if (size >= MIN_SIZE) OVERLAY(tmp)->Magic = MGK_ALLOCMEM; } - + #ifdef BUFFER_OVERFLOW_CHECKING nmCheckAll(); #endif - + #ifdef BLK_LEAK_CHECK - for(i=0;i= MIN_SIZE) - ASSERTNOTMAGIC(ptr,MGK_FREEMEM); - - if (!ptr) return; - - if (!isinit) nmInitialize(); - + ASSERTNOTMAGIC(ptr, MGK_FREEMEM); + + if (ptr == NULL) return; + #ifdef GLOBAL_BLK_COUNTING nmFreeCnt++; #endif - + #ifdef BUFFER_OVERFLOW_CHECKING nmCheckAll(); #endif - + #ifdef BLK_LEAK_CHECK - for(i=0;i= MIN_SIZE) + if (size <= MAX_SIZE && size >= MIN_SIZE) { -#ifdef DUP_FREE_CHECK - tmp = lists[size]; - while(tmp) - { + #ifdef DUP_FREE_CHECK + for (pOverlay tmp = lists[size]; tmp != NULL; tmp = OVERLAY(tmp)->Next) + { ASSERTMAGIC(OVERLAY(tmp),MGK_FREEMEM); if (OVERLAY(tmp) == OVERLAY(ptr)) { - printf("Duplicate nmFree()!!! Size = %d, Address = %p\n",size,ptr); + printf("Duplicate nmFree()!!! Size = %d, Address = %p\n", size, ptr); if (err_fn) err_fn("Internal error - duplicate nmFree() occurred."); return; } - tmp = OVERLAY(tmp)->Next; } -#endif -#ifdef SIZED_BLK_COUNTING - outcnt[size]--; -#endif + #endif + + OVERLAY(ptr)->Magic = MGK_FREEMEM; OVERLAY(ptr)->Next = lists[size]; lists[size] = OVERLAY(ptr); -#ifdef SIZED_BLK_COUNTING + ptr = NULL; + + #ifdef SIZED_BLK_COUNTING + outcnt[size]--; listcnt[size]++; -#endif - OVERLAY(ptr)->Magic = MGK_FREEMEM; + #endif } - else - { #endif + + if (ptr != NULL) + { nmDebugFree(ptr); -#ifndef NO_BLK_CACHE + ptr = NULL; } -#endif - + #ifdef BUFFER_OVERFLOW_CHECKING nmCheckAll(); #endif - + return; } @@ -427,37 +437,38 @@ nmFree(void* ptr, int size) void nmStats() { - - if (!isinit) nmInitialize(); - - printf("NewMalloc subsystem statistics:\n"); - printf(" nmMalloc: %d calls, %d hits (%3.3f%%)\n", - nmMallocCnt, - nmMallocHits, - (float)nmMallocHits/(float)nmMallocCnt*100.0); - printf(" nmFree: %d calls\n", nmFreeCnt); - printf(" bigblks: %d too big, %d largest size\n\n", - nmMallocTooBig, - nmMallocLargest); - + if (!is_init) nmInitialize(); + + printf( + "NewMalloc subsystem statistics:\n" + " nmMalloc: %d calls, %d hits (%3.3f%%)\n" + " nmFree: %d calls\n" + " bigblks: %d too big, %d largest size\n\n", + nmMallocCnt, nmMallocHits, (float)nmMallocHits / (float)nmMallocCnt * 100.0, + nmFreeCnt, + nmMallocTooBig, nmMallocLargest + ); + return; } void -nmRegister(int size,char* name) +nmRegister(int size, char* name) { - pRegisteredBlockType blk; - - if (size > MAX_SIZE) return; - - blk = (pRegisteredBlockType)malloc(sizeof(RegisteredBlockType)); + pRegisteredBlockType blk = NULL; + + if (size > MAX_SIZE) return; + + blk = (pRegisteredBlockType)malloc(sizeof(RegisteredBlockType)); + if (blk == NULL) return; blk->Next = blknames[size]; - blk->Size = size; - strcpy(blk->Name,name); blknames[size] = blk; + blk->Magic = MGK_REGISBLK; - + blk->Size = size; + strcpy(blk->Name, name); + return; } @@ -465,33 +476,34 @@ nmRegister(int size,char* name) void nmDebug() { - int i; - pRegisteredBlockType blk; - printf("size\tout\tcache\tusage\tnames\n"); - for(i=MIN_SIZE;iName); - blk = blk->Next; - } - printf("\n"); + if (usagecnt[size] == 0) continue; + + printf("%ld\t%d\t%d\t%d\t", size, outcnt[size], listcnt[size], usagecnt[size]); + + for (pRegisteredBlockType blk = blknames[size]; blk != NULL; blk = blk->Next) + { + ASSERTMAGIC(blk, MGK_REGISBLK); + printf("%s ", blk->Name); } + + printf("\n"); } + printf("\n-----\n"); printf("size\toutcnt\n-------\t-------\n"); - for(i=MIN_SIZE;i<=MAX_SIZE;i++) + + for (size_t size = MIN_SIZE; size <= MAX_SIZE; size++) { - if (nmsys_outcnt[i]) printf("%d\t%d\n",i,nmsys_outcnt[i]); + if (nmsys_outcnt[size] == 0) continue; + + printf("%ld\t%d\n", size, nmsys_outcnt[size]); } printf("\n"); - + return; } @@ -499,41 +511,40 @@ nmDebug() void nmDeltas() { - int i, total; - pRegisteredBlockType blk; - - total = 0; printf("size\tdelta\tnames\n-------\t-------\t-------\n"); - for(i=MIN_SIZE;i<=MAX_SIZE;i++) + + int total_delta = 0; + for (size_t size = MIN_SIZE; size <= MAX_SIZE; size++) { - if (outcnt[i] != outcnt_delta[i]) - { - printf("%d\t%d\t",i,outcnt[i] - outcnt_delta[i]); - total += (i * (outcnt[i] - outcnt_delta[i])); - blk = blknames[i]; - while(blk) - { - ASSERTMAGIC(blk,MGK_REGISBLK); - printf("%s ", blk->Name); - blk = blk->Next; - } - printf("\n"); - outcnt_delta[i] = outcnt[i]; + if (outcnt[size] == outcnt_delta[size]) continue; + + printf("%ld\t%d\t", size, outcnt[size] - outcnt_delta[size]); + total_delta += (size * (outcnt[size] - outcnt_delta[size])); + + for (pRegisteredBlockType blk = blknames[size]; blk != NULL; blk = blk->Next) + { + ASSERTMAGIC(blk, MGK_REGISBLK); + printf("%s ", blk->Name); } + + printf("\n"); + + outcnt_delta[size] = outcnt[size]; } + printf("\nsize\tdelta\n-------\t-------\n"); - for(i=MIN_SIZE;i<=MAX_SIZE;i++) + for (size_t size = MIN_SIZE; size <= MAX_SIZE; size++) { - if (nmsys_outcnt[i] != nmsys_outcnt_delta[i]) - { - printf("%d\t%d\n",i,nmsys_outcnt[i] - nmsys_outcnt_delta[i]); - total += (i * (nmsys_outcnt[i] - nmsys_outcnt_delta[i])); - nmsys_outcnt_delta[i] = nmsys_outcnt[i]; - } + if (nmsys_outcnt[size] == nmsys_outcnt_delta[size]) continue; + + printf("%ld\t%d\n", size, nmsys_outcnt[size] - nmsys_outcnt_delta[size]); + total_delta += (size * (nmsys_outcnt[size] - nmsys_outcnt_delta[size])); + nmsys_outcnt_delta[size] = nmsys_outcnt[size]; } printf("\n"); - printf("delta %d total bytes\n", total); - + + printf("delta %d total bytes\n", total_delta); + return; } @@ -541,74 +552,91 @@ nmDeltas() void* nmSysMalloc(int size) { -#ifdef NM_USE_SYSMALLOC - char* ptr; - ptr = (char*)nmDebugMalloc(size+sizeof(int)); - if (!ptr) return NULL; - *(int*)ptr = size; -#ifdef SIZED_BLK_COUNTING - if (size > 0 && size <= MAX_SIZE) nmsys_outcnt[size]++; -#endif - return (void*)(ptr+sizeof(int)); +#ifndef NM_USE_SYSMALLOC + return (void*)nmDebugMalloc(size); #else - return (void*)nmDebugMalloc(size); + + char* ptr = (char*)nmDebugMalloc(sizeof(int) + size); + if (ptr == NULL) return NULL; + + *(int*)ptr = size; + + #ifdef SIZED_BLK_COUNTING + if (size > 0 && size <= MAX_SIZE) nmsys_outcnt[size]++; + #endif + + return (void*)(sizeof(int) + ptr); #endif + + return NULL; /** Unreachable. **/ } + void nmSysFree(void* ptr) { -#ifdef NM_USE_SYSMALLOC -#ifdef SIZED_BLK_COUNTING - int size; - size = *(int*)(((char*)ptr)-sizeof(int)); - if (size > 0 && size <= MAX_SIZE) nmsys_outcnt[size]--; -#endif - nmDebugFree(((char*)ptr)-sizeof(int)); +#ifndef NM_USE_SYSMALLOC + nmDebugFree(ptr); #else - nmDebugFree(ptr); + + #ifdef SIZED_BLK_COUNTING + int size; + size = *(int*)(((char*)ptr)-sizeof(int)); + if (size > 0 && size <= MAX_SIZE) nmsys_outcnt[size]--; + #endif + + nmDebugFree(((char*)ptr) - sizeof(int)); #endif + return; } + void* -nmSysRealloc(void* ptr, int newsize) +nmSysRealloc(void* ptr, int new_size) { -#ifdef NM_USE_SYSMALLOC -#ifdef SIZED_BLK_COUNTING - int size; -#endif - char* newptr; - if (!ptr) return nmSysMalloc(newsize); -#ifdef SIZED_BLK_COUNTING - size = *(int*)(((char*)ptr)-sizeof(int)); -#endif - newptr = (char*)nmDebugRealloc((((char*)ptr)-sizeof(int)), newsize+sizeof(int)); - if (!newptr) return NULL; -#ifdef SIZED_BLK_COUNTING - if (size > 0 && size <= MAX_SIZE) nmsys_outcnt[size]--; -#endif - *(int*)newptr = newsize; -#ifdef SIZED_BLK_COUNTING - if (newsize > 0 && newsize <= MAX_SIZE) nmsys_outcnt[newsize]++; -#endif - return (void*)(newptr+sizeof(int)); +#ifndef NM_USE_SYSMALLOC + return (void*)nmDebugRealloc(ptr, new_size); #else - return (void*)nmDebugRealloc(ptr,newsize); + + if (ptr == NULL) return nmSysMalloc(new_size); + + void* buffer_ptr = ((char*)ptr) - sizeof(int); + const int size = *(int*)buffer_ptr; + if (size == new_size) return ptr; + + char* new_ptr = (char*)nmDebugRealloc(buffer_ptr, sizeof(int) + new_size); + if (new_ptr == NULL) return NULL; + + *(int*)new_ptr = new_size; + + #ifdef SIZED_BLK_COUNTING + if (0 < size && size <= MAX_SIZE) nmsys_outcnt[size]--; + if (0 < new_size && new_size <= MAX_SIZE) nmsys_outcnt[new_size]++; + #endif + + return (void*)(sizeof(int) + new_ptr); #endif + + return NULL; /** Unreachable. **/ } + char* -nmSysStrdup(const char* ptr) +nmSysStrdup(const char* str) { -#ifdef NM_USE_SYSMALLOC - char* newptr; - int n = strlen(ptr); - newptr = (char*)nmSysMalloc(n+1); - if (!newptr) return NULL; - memcpy(newptr,ptr,n+1); - return newptr; +#ifndef NM_USE_SYSMALLOC + return strdup(str); #else - return strdup(ptr); + + size_t n = strlen(str) + 1u; + char* new_str = (char*)nmSysMalloc(n); + if (new_str == NULL) return NULL; + + memcpy(new_str, str, n); + + return new_str; #endif + + return NULL; /** Unreachable. **/ } From 49d80093a8809c7bcd46d273b5dd6e84dfac89c3 Mon Sep 17 00:00:00 2001 From: Lightning11wins Date: Mon, 15 Dec 2025 09:25:33 -0700 Subject: [PATCH 2/7] Add code comments. --- centrallix-lib/include/newmalloc.h | 10 +- centrallix-lib/src/newmalloc.c | 286 +++++++++++++++++++++++++---- 2 files changed, 255 insertions(+), 41 deletions(-) diff --git a/centrallix-lib/include/newmalloc.h b/centrallix-lib/include/newmalloc.h index 038df686a..60b2d8a2e 100644 --- a/centrallix-lib/include/newmalloc.h +++ b/centrallix-lib/include/newmalloc.h @@ -44,11 +44,10 @@ typedef struct _ov #define SIZED_BLK_COUNTING 1 #endif -/** nmMalloc block caching causes Valgrind to lose track of what call - ** stack actually allocated the block to begin with. So if we're using - ** valgrind, turn off block caching altogether, and make the nmSysXyz() calls - ** just pass-throughs. - **/ +/*** nmMalloc block caching causes Valgrind to lose track of the call stack + *** where the developer allocated the block. If we are using Valgrind, this + *** caching is disabled. ALso, the nmSysXyz() call are simply pass-throughs. + ***/ #ifdef USING_VALGRIND #define NO_BLK_CACHE 1 #undef NM_USE_SYSMALLOC @@ -80,6 +79,7 @@ void nmSysFree(void* ptr); void* nmSysRealloc(void* ptr, int new_size); char* nmSysStrdup(const char* str); +/** Tagging system (not implemented). **/ void nmEnableTagging(); void nmRegisterTagID(int tag_id, char* name); void nmSetTag(void* ptr, int tag_id, void* tag); diff --git a/centrallix-lib/src/newmalloc.c b/centrallix-lib/src/newmalloc.c index 117f53c20..475ca772b 100644 --- a/centrallix-lib/src/newmalloc.c +++ b/centrallix-lib/src/newmalloc.c @@ -8,22 +8,24 @@ /* GNU Lesser General Public License, Version 2.1, contained in the */ /* included file "COPYING". */ /* */ -/* Module: NewMalloc memory manager (newmalloc.c, .h) */ -/* Author: Greg Beeley (GRB) */ +/* Module: NewMalloc memory manager (newmalloc.c, .h) */ +/* Author: Greg Beeley (GRB) */ /* */ /* Description: This module provides block-caching memory allocation */ -/* and debugging services, to help find memory leaks as */ -/* well. It also interacts with the magic number module */ -/* to ensure memory allocation consistency. Slower in */ -/* debugging mode but can improve app speed dramatically */ -/* in implementation mode. While blocks returned from the */ -/* nm* routines can be mixed-and-matched with the normall */ -/* libc functions, this defeats the purpose of the system */ -/* and leads to inaccuracies in the debugging information. */ +/* and debugging services to help find memory leaks and */ +/* other memory errors. It also uses magic numbers to */ +/* ensure memory allocation consistency. This module is */ +/* slower than standard libc allocation when in debug */ +/* mode, but it is drastically faster in production mode. */ +/* */ +/* Although blocks returned from the nm* routines can be */ +/* mixed-and-matched with the normal libc functions, this */ +/* leads to inaccuracies in the debugging information and */ +/* thus defeats the purpose of having a custom library. */ /* The returned blocks from the nmSys* functions CANNOT */ /* be intermixed with normal malloc/free. In short, if */ -/* you use this library, DONT use normal malloc/free at */ -/* all.... */ +/* you use this library, do NOT use the normal libc */ +/* malloc/free at all. */ /************************************************************************/ #ifdef HAVE_CONFIG_H @@ -40,17 +42,17 @@ #include "newmalloc.h" -/** define BUFFER_OVERFLOW_CHECKING for buffer overflow checking -*** this works off of magic numbers in the 4 bytes on either end -*** of the buffer that is returned to the user, at the cost of -*** 16 bytes of memory per buffer, and a full scan of the list -*** of allocated memory twice per nmMalloc() or nmFree() call -*** -*** the check can be made at any time from normal code by calling: -*** nmCheckAll() -*** -- this functions is still defined if BUFFER_OVERFLOW_CHECKING is -*** not defined, but it becomes a NOOP -**/ +/*** BUFFER_OVERFLOW_CHECKING adds 4 bytes of magic data to either end of + *** the memory buffer returned to the user by nmMalloc(). This allows us + *** to detect clobbered memory at the cost of increasing memory overhead + *** by 16 bytes per allocated buffer, and requires a full scan of the + *** allocated memory list twice in each nmMalloc() or nmFree() call. + *** + *** This check can also be run manually by calling nmCheckAll(). + *** + *** Note: nmCheckAll() is still defined if BUFFER_OVERFLOW_CHECKING is not + *** defined (it is a NOOP). + ***/ #ifdef BUFFER_OVERFLOW_CHECKING typedef struct _mem { @@ -70,7 +72,8 @@ typedef struct _mem pMemStruct startMemList; #endif -pOverlay lists[MAX_SIZE+1]; +/** List of overlay structs, used for caching allocated memory. **/ +pOverlay lists[MAX_SIZE+1]; /* TODO: Greg - Is this 65KB global variable a problem? (On the stack, it would be...) */ int listcnt[MAX_SIZE+1]; int outcnt[MAX_SIZE+1]; int outcnt_delta[MAX_SIZE+1]; @@ -104,8 +107,9 @@ typedef struct _RB pRegisteredBlockType blknames[MAX_SIZE+1]; +/** Initialize the NewMalloc subsystem. **/ void -nmInitialize() +nmInitialize(void) { for (int i = 0; i <= MAX_SIZE; i++) lists[i] = NULL; for (int i = 0; i <= MAX_SIZE; i++) listcnt[i] = 0; @@ -130,6 +134,7 @@ nmInitialize() startMemList = NULL; #endif + /** Done. **/ is_init = true; return; @@ -137,11 +142,18 @@ nmInitialize() #ifdef BUFFER_OVERFLOW_CHECKING +/*** Check the before and after magic values on a MemStruct to detect memory + *** buffer overflows. + *** + *** @param mem A pointer to the memory struct to check. + *** @returns 0 on success, or -1 if an overflow is detected. + ***/ int nmCheckItem(pMemStruct mem) { int ret = 0; + /** Check the starting magic value. **/ if (mem->magic_start != MGK_MEMSTART) { fprintf(stderr, @@ -151,6 +163,7 @@ nmCheckItem(pMemStruct mem) ret = -1; } + /** Check the ending magic value. **/ if (ENDMAGIC(mem) != MGK_MEMEND) { fprintf(stderr, @@ -165,15 +178,20 @@ nmCheckItem(pMemStruct mem) #endif +/*** Check the before and after magic values on all MemStructs to detect memory + *** buffer overflows. Causes a seg fault if such an overflow is detected. + ***/ void -nmCheckAll() +nmCheckAll(void) { #ifdef BUFFER_OVERFLOW_CHECKING int ret = 0; + /** Traverse the memory list and check each item. **/ for (pMemStruct mem = startMemList; mem != NULL; mem = mem->next) if (nmCheckItem(mem) == -1) ret = -1; + /** "Handle" error. **/ if (ret == -1) { printf("causing segfault to halt.......\n"); @@ -186,60 +204,94 @@ nmCheckAll() #ifdef BUFFER_OVERFLOW_CHECKING +/*** Allocate new memory, using before and after magic values. + *** + *** @param size The size of the memory buffer to be allocated. + *** @returns A pointer to the start of the allocated memory buffer. + ***/ void* nmDebugMalloc(int size) { + /** Allocate space for the data. **/ pMemStruct tmp = (pMemStruct)malloc(size + EXTRA_MEM); if(tmp == NULL) return NULL; + /** Initialize data in the memory struct (including magic values). **/ tmp->size = size; tmp->magic_start = MGK_MEMSTART; ENDMAGIC(tmp) = MGK_MEMEND; + /** Prepend this mem struct to the MemList linked list. **/ tmp->next = startMemList; startMemList = tmp; + /** Return the memory data for the user to use. **/ return (void*)MEMDATA(tmp); } +/*** Free a memory buffer allocated using `nmDebugMalloc()`. The before and + *** after magic values are checked and a warning is displayed if an overflow + *** has occurred (although this does not halt the program or function). + *** + *** @param ptr A pointer to the memory to be freed. + ***/ void nmDebugFree(void* ptr) { + /** Get the mem struct for the item being freed. **/ pMemStruct tmp = MEMDATATOSTRUCT(ptr); + /** Verify that our data hasn't been clobbered. **/ nmCheckItem(tmp); + /** Remove the item from the linked list. **/ if (tmp == startMemList) - { + { /* Item is at the start. */ startMemList = tmp->next; } else - { + { /* Item is not at the start. */ + /** Traverse the linked list to find the previous item. **/ pMemStruct prev = startMemList; while (prev->next != tmp) prev = prev->next; + /** Fix the gap that will be left by freeing this item. **/ prev->next = tmp->next; } + /** Free the item. **/ free(tmp); return; } +/*** Reallocates a memory block from `nmDebugMalloc()` (or `nmDebugRealloc()`) + *** to a new size, maintaining as much data as possible. Data loss only + *** occurs if the new size is smaller, in which case bits are lost starting + *** at the end of the buffer. + *** + *** @param ptr A pointer to the current buffer (deallocated by this call). + *** @param new_size The size that the buffer should be after this call. + *** @returns The new buffer, or NULL if an error occurs. + ***/ void* nmDebugRealloc(void* ptr, int new_size) { + /** Behaves as nmDebugMalloc() if there is no target pointer. **/ if (ptr == NULL) return nmDebugMalloc(new_size); + /** Allocate new data. **/ void* new_ptr = (void*)nmDebugMalloc(new_size); if (new_ptr == NULL) return NULL; + /** Move the old data. **/ int old_size = MEMDATATOSTRUCT(ptr)->size; memmove(new_ptr, ptr, old_size); + /** Free the old allocation. **/ nmDebugFree(ptr); return new_ptr; @@ -260,11 +312,16 @@ nmSetErrFunction(int (*error_fn)()) } +/*** Clear the allocated memory block cache. This deallocates all memory + *** blocks that were marked as unused by a call to `nmFree()`, but were + *** moved to the cache instead of being freed to the OS memory pool. + ***/ void -nmClear() +nmClear(void) { if (!is_init) nmInitialize(); + /** Iterate over each overlay list in the cache and clear it. **/ for (size_t size = MIN_SIZE; size <= MAX_SIZE; size++) { pOverlay ov = lists[size]; @@ -281,6 +338,17 @@ nmClear() } +/*** Allocate memory using block caching. The allocated block may be supplied + *** by the cache (if available), or requested from the operating system. + *** + *** @attention Should only be used for memory that will benefit from caching + *** (e.g. a struct of a constant size). Dynamically sized memory (such as + *** variable-length strings) should be allocated using nmSysMalloc() to + *** avoid overhead from unnecessary caching. + *** + *** @param size The size of the memory block to be allocated. + *** @returns A pointer to the start of the allocated memory block. + ***/ void* nmMalloc(int size) { @@ -288,35 +356,43 @@ nmMalloc(int size) if (!is_init) nmInitialize(); +/** Handle counting. **/ #ifdef GLOBAL_BLK_COUNTING nmMallocCnt++; #endif +/** Handle buffer overflow check. **/ #ifdef BUFFER_OVERFLOW_CHECKING nmCheckAll(); #endif + /** Use caching if the size can be cached. **/ if (MIN_SIZE <= size && size <= MAX_SIZE) { +/** Handle counting. **/ #ifdef SIZED_BLK_COUNTING outcnt[size]++; usagecnt[size]++; #endif + /** Cache check. **/ if (lists[size] == NULL) - { + { /* Miss. */ tmp = (void*)nmDebugMalloc(size); } else - { + { /* Hit. */ + /** Handle counting. **/ #ifdef GLOBAL_BLK_COUNTING nmMallocHits++; #endif + /** Pop allocated memory off of the start of the cache list. **/ tmp = lists[size]; ASSERTMAGIC(tmp, MGK_FREEMEM); lists[size] = lists[size]->Next; +/** Handle counting. **/ #ifdef SIZED_BLK_COUNTING listcnt[size]--; #endif @@ -324,14 +400,21 @@ nmMalloc(int size) } else { +/** Handle counting. **/ #ifdef GLOBAL_BLK_COUNTING - nmMallocTooBig++; + nmMallocTooBig++; /* TODO: Greg - Couldn't the memory also be too small to cache? */ if (size > nmMallocLargest) nmMallocLargest = size; #endif + /** Caching isn't supported for this size: Allocate memory normally. **/ tmp = (void*)nmDebugMalloc(size); } + /** TODO: Greg - We might need more docs for overlays. **/ + /*** It seems like this code block is doing too many different things. It + *** uses overlays, which I don't fully understand, so I wasn't able to + *** simplify it. + ***/ if (tmp == NULL) { if (err_fn) err_fn("Insufficient system memory for operation."); @@ -342,11 +425,14 @@ nmMalloc(int size) OVERLAY(tmp)->Magic = MGK_ALLOCMEM; } +/** Handle overflow check. **/ #ifdef BUFFER_OVERFLOW_CHECKING nmCheckAll(); #endif +/** Handle memory leak checks. **/ #ifdef BLK_LEAK_CHECK + /** Find the next open index in the blocks array and record this block. **/ for (int i = 0; i < MAX_BLOCKS; i++) { if (blks[i] == NULL) @@ -358,29 +444,52 @@ nmMalloc(int size) } #endif + /** Return the allocated memory. **/ return tmp; } +/*** Free a memory buffer allocated using `nmMalloc()`. This buffer may be + *** deallocated into the operating system memory pool, or it may be cached + *** for reuse with `nmMalloc()`. + *** + *** @attention Be EXTREMELY careful not to provide an incorrect size value. + *** This can lead to memory blocks being cached incorrectly, which causes + *** errors to occur when they are reallocated, possibly FAR AWAY from the + *** original source of the bug. + *** + *** @param ptr A pointer to the memory to be freed. + *** @param size The size of the memory block to be freed. (Note: Even though + *** the OS does store this value, the C memory manager does not make it + *** available to us, so it must be provided for this function to run.) + ***/ void nmFree(void* ptr, int size) { if (!is_init) nmInitialize(); + /*** If there should be an overlay, assert that it does NOT indicate that + *** this memory was already freed and returned to the cache. + ***/ if (size >= MIN_SIZE) ASSERTNOTMAGIC(ptr, MGK_FREEMEM); + /** If the pointer is null, no work needed. **/ if (ptr == NULL) return; +/** Handle counting. **/ #ifdef GLOBAL_BLK_COUNTING nmFreeCnt++; #endif +/** Handle overflow check. **/ #ifdef BUFFER_OVERFLOW_CHECKING nmCheckAll(); #endif +/** Handle memory leak check. **/ #ifdef BLK_LEAK_CHECK + /** Find this block in the blocks array and remove it. **/ for (int i = 0; i < MAX_BLOCKS; i++) { if (blks[i] == ptr) @@ -392,10 +501,13 @@ nmFree(void* ptr, int size) } #endif +/** Check for the block cache if it is enabled. **/ #ifndef NO_BLK_CACHE if (size <= MAX_SIZE && size >= MIN_SIZE) { +/** Handle duplicate free check. **/ #ifdef DUP_FREE_CHECK + /** Search the freed memory cache to see if this memory is there. **/ for (pOverlay tmp = lists[size]; tmp != NULL; tmp = OVERLAY(tmp)->Next) { ASSERTMAGIC(OVERLAY(tmp),MGK_FREEMEM); @@ -408,11 +520,13 @@ nmFree(void* ptr, int size) } #endif + /** Add the freed memory to the cache. **/ OVERLAY(ptr)->Magic = MGK_FREEMEM; OVERLAY(ptr)->Next = lists[size]; lists[size] = OVERLAY(ptr); ptr = NULL; +/** Handle counting. **/ #ifdef SIZED_BLK_COUNTING outcnt[size]--; listcnt[size]++; @@ -420,12 +534,14 @@ nmFree(void* ptr, int size) } #endif + /** Free the block if it was not consumed by the cache. **/ if (ptr != NULL) { nmDebugFree(ptr); ptr = NULL; } +/** Handle overflow check. **/ #ifdef BUFFER_OVERFLOW_CHECKING nmCheckAll(); #endif @@ -434,11 +550,13 @@ nmFree(void* ptr, int size) } +/** Print stats about the NewMalloc subsystem, for debugging. **/ void -nmStats() +nmStats(void) { if (!is_init) nmInitialize(); + /** Print subsystem stats. **/ printf( "NewMalloc subsystem statistics:\n" " nmMalloc: %d calls, %d hits (%3.3f%%)\n" @@ -453,18 +571,22 @@ nmStats() } +/** Register a new memory size with a name, for debugging. **/ void nmRegister(int size, char* name) { pRegisteredBlockType blk = NULL; + /** Ignore blocks too large to be cached. **/ if (size > MAX_SIZE) return; + /** Prepend a new RegisteredBlockType record to the list of records for this size. **/ blk = (pRegisteredBlockType)malloc(sizeof(RegisteredBlockType)); if (blk == NULL) return; blk->Next = blknames[size]; blknames[size] = blk; + /** Initialize values for this record. **/ blk->Magic = MGK_REGISBLK; blk->Size = size; strcpy(blk->Name, name); @@ -473,17 +595,25 @@ nmRegister(int size, char* name) } +/** Print debug information about the newmalloc system. **/ void -nmDebug() +nmDebug(void) { + /** Print the header for the block sizes table. **/ printf("size\tout\tcache\tusage\tnames\n"); + /** Iterate through each possible block size. **/ for (size_t size = MIN_SIZE; size < MAX_SIZE; size++) { + /** Skip unused block sizes. **/ if (usagecnt[size] == 0) continue; + /** Print stats about this block size. **/ printf("%ld\t%d\t%d\t%d\t", size, outcnt[size], listcnt[size], usagecnt[size]); + /*** Traverse the linked list that holds all registered names for the given + *** size and print each one. + **/ for (pRegisteredBlockType blk = blknames[size]; blk != NULL; blk = blk->Next) { ASSERTMAGIC(blk, MGK_REGISBLK); @@ -493,13 +623,17 @@ nmDebug() printf("\n"); } + /** Print the header for the nmSysXYZ() info table. **/ printf("\n-----\n"); printf("size\toutcnt\n-------\t-------\n"); + /** Iterate through each possible block size. **/ for (size_t size = MIN_SIZE; size <= MAX_SIZE; size++) { + /** Skip unused block sizes. **/ if (nmsys_outcnt[size] == 0) continue; + /** Print the nmSysXYZ() block information. **/ printf("%ld\t%d\n", size, nmsys_outcnt[size]); } printf("\n"); @@ -508,83 +642,128 @@ nmDebug() } +/** Print debug information about the newmalloc system. **/ void -nmDeltas() +nmDeltas(void) { + /** Print the header for the block size deltas table. **/ printf("size\tdelta\tnames\n-------\t-------\t-------\n"); + /** Iterate through each possible block size. **/ int total_delta = 0; for (size_t size = MIN_SIZE; size <= MAX_SIZE; size++) { + /** Skip entries where there is no change. **/ if (outcnt[size] == outcnt_delta[size]) continue; + /** Print the change and add it to the total_delta. **/ printf("%ld\t%d\t", size, outcnt[size] - outcnt_delta[size]); total_delta += (size * (outcnt[size] - outcnt_delta[size])); + /*** Traverse the linked list that holds all registered names for the given + *** size and print each one. + **/ for (pRegisteredBlockType blk = blknames[size]; blk != NULL; blk = blk->Next) { ASSERTMAGIC(blk, MGK_REGISBLK); printf("%s ", blk->Name); } + /** End of line. **/ printf("\n"); + /** Reset the delta. **/ outcnt_delta[size] = outcnt[size]; } + /** Print the header for the nmSysXYZ() info table. **/ printf("\nsize\tdelta\n-------\t-------\n"); for (size_t size = MIN_SIZE; size <= MAX_SIZE; size++) { + /** Skip sizes where no change in memory occurred. **/ if (nmsys_outcnt[size] == nmsys_outcnt_delta[size]) continue; + /** Print the results. **/ printf("%ld\t%d\n", size, nmsys_outcnt[size] - nmsys_outcnt_delta[size]); total_delta += (size * (nmsys_outcnt[size] - nmsys_outcnt_delta[size])); nmsys_outcnt_delta[size] = nmsys_outcnt[size]; } printf("\n"); + /** Print the total delta. **/ + /** TODO: Israel - Change this to use snprint_bytes() once that function is available. **/ printf("delta %d total bytes\n", total_delta); return; } +/*** Allocate memory without using block caching. The size of the allocated + *** memory is stored at the start of the memory block for debugging. + *** + *** @attention Should be used for memory that will NOT benefit from caching + *** (e.g. a variable length string). Consistently sized memory (such as + *** a struct of a constant size) should be allocated using nmMalloc() to + *** improve performance. + *** + *** @param size The size of the memory block to be allocated. + *** @returns A pointer to the start of the allocated memory block. + ***/ void* nmSysMalloc(int size) { +/** Fallback if sysMalloc() is disabled. **/ #ifndef NM_USE_SYSMALLOC return (void*)nmDebugMalloc(size); #else + /** Allocate the requested space, plus the initial size int. **/ char* ptr = (char*)nmDebugMalloc(sizeof(int) + size); if (ptr == NULL) return NULL; + /** Set the size int. **/ *(int*)ptr = size; + /** Update sized block counting, if necessary. **/ #ifdef SIZED_BLK_COUNTING if (size > 0 && size <= MAX_SIZE) nmsys_outcnt[size]++; #endif + /** Return the allocated memory (starting after the size int). **/ return (void*)(sizeof(int) + ptr); #endif return NULL; /** Unreachable. **/ } +/*** TODO: Greg - I believe that the above code is the best way to satisfy my interpretation of + *** requirement 2 of the coding style: "Every function must have a return + *** line at the end, even if the function never reaches that return." + *** Without the goofy unreachable return, the last line will be an #endif. + *** Am I following the style correctly? + ***/ + +/*** Free a memory buffer allocated using `nmSysMalloc()` (or similar). + *** + *** @param ptr A pointer to the memory to be freed. + ***/ void nmSysFree(void* ptr) { +/** Fallback if sysMalloc() is disabled. **/ #ifndef NM_USE_SYSMALLOC nmDebugFree(ptr); #else + /** Count sized blocks, if enabled. **/ #ifdef SIZED_BLK_COUNTING int size; size = *(int*)(((char*)ptr)-sizeof(int)); if (size > 0 && size <= MAX_SIZE) nmsys_outcnt[size]--; #endif + /** Free the initial size int, as well as the rest of the allocated memory. **/ nmDebugFree(((char*)ptr) - sizeof(int)); #endif @@ -592,29 +771,45 @@ nmSysFree(void* ptr) } +/*** Reallocates a memory block from `nmSysMalloc()` (or similar) to a new + *** size, maintaining as much data as possible. Data loss only occurs if the + *** new size is smaller, in which case bits are lost starting at the end of + *** the buffer. + *** + *** @param ptr A pointer to the current buffer (deallocated by this call). + *** @param new_size The size that the buffer should be after this call. + *** @returns The new buffer, or NULL if an error occurs. + ***/ void* nmSysRealloc(void* ptr, int new_size) { +/** Fallback if sysMalloc() is disabled. **/ #ifndef NM_USE_SYSMALLOC return (void*)nmDebugRealloc(ptr, new_size); #else + /** Behaves as nmSysMalloc() if there is no target pointer. **/ if (ptr == NULL) return nmSysMalloc(new_size); + /** If no work needs to be done, do nothing. **/ void* buffer_ptr = ((char*)ptr) - sizeof(int); const int size = *(int*)buffer_ptr; if (size == new_size) return ptr; + /** Realloc the given memory with space for the initial size int. **/ char* new_ptr = (char*)nmDebugRealloc(buffer_ptr, sizeof(int) + new_size); if (new_ptr == NULL) return NULL; + /** Update the initial size int. **/ *(int*)new_ptr = new_size; + /** Handle counting. **/ #ifdef SIZED_BLK_COUNTING if (0 < size && size <= MAX_SIZE) nmsys_outcnt[size]--; if (0 < new_size && new_size <= MAX_SIZE) nmsys_outcnt[new_size]++; #endif + /** Return the pointer to the new memory. **/ return (void*)(sizeof(int) + new_ptr); #endif @@ -622,17 +817,36 @@ nmSysRealloc(void* ptr, int new_size) } +/*** Duplicate a string into a new memory buffer, which is allocated by using + *** `nmSysMalloc()` (and thus, it should be freed with `nmSysFree()` to avoid + *** causing a memory leak). + *** + *** Note: The string is not deallocated by this function call. Thus, it can + *** be stack allocated, heap allocated, or even a string literal without + *** causing an error. + *** + *** @attention The str pointer is _assumed_ to point to a null-terminated + *** string. If this is not the case, the behavior is undefined, as with + *** the C standard `strdup()` function. + *** + *** @param str The string to be duplicated. + *** @returns A pointer to the new string buffer containing the string, or + *** NULL if an error occurs. + ***/ char* nmSysStrdup(const char* str) { +/** Fallback if sysMalloc() is disabled. **/ #ifndef NM_USE_SYSMALLOC return strdup(str); #else - size_t n = strlen(str) + 1u; + /** Allocate space for the string. **/ + size_t n = strlen(str) + 1u; /* Length, including the null terminator. */ char* new_str = (char*)nmSysMalloc(n); if (new_str == NULL) return NULL; + /** Copy the string into the new memory. **/ memcpy(new_str, str, n); return new_str; From 3c5d207498670bd6ed3474331f99b03ed430b7d4 Mon Sep 17 00:00:00 2001 From: Lightning11wins Date: Mon, 15 Dec 2025 09:52:55 -0700 Subject: [PATCH 3/7] Improve developer experience. Add nmSysGetSize(). Add a warning when using nmStats() with the necessary stat tracking disabled. Update errors to print to stderr instead of stdout. Abstract registered block name printing into a public helper function. --- centrallix-lib/include/newmalloc.h | 2 + centrallix-lib/src/newmalloc.c | 73 ++++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/centrallix-lib/include/newmalloc.h b/centrallix-lib/include/newmalloc.h index 60b2d8a2e..7fa0fa781 100644 --- a/centrallix-lib/include/newmalloc.h +++ b/centrallix-lib/include/newmalloc.h @@ -72,12 +72,14 @@ void* nmMalloc(int size); void nmFree(void* ptr, int size); void nmStats(); void nmRegister(int size, char* name); +void nmPrintNames(int size); void nmDebug(); void nmDeltas(); void* nmSysMalloc(int size); void nmSysFree(void* ptr); void* nmSysRealloc(void* ptr, int new_size); char* nmSysStrdup(const char* str); +int nmSysGetSize(void* ptr); /** Tagging system (not implemented). **/ void nmEnableTagging(); diff --git a/centrallix-lib/src/newmalloc.c b/centrallix-lib/src/newmalloc.c index 475ca772b..fc877c034 100644 --- a/centrallix-lib/src/newmalloc.c +++ b/centrallix-lib/src/newmalloc.c @@ -194,7 +194,7 @@ nmCheckAll(void) /** "Handle" error. **/ if (ret == -1) { - printf("causing segfault to halt.......\n"); + fprintf(stderr, "causing segfault to halt.......\n"); *(int*)NULL = 0; } #endif @@ -214,7 +214,7 @@ nmDebugMalloc(int size) { /** Allocate space for the data. **/ pMemStruct tmp = (pMemStruct)malloc(size + EXTRA_MEM); - if(tmp == NULL) return NULL; + if (tmp == NULL) return NULL; /** Initialize data in the memory struct (including magic values). **/ tmp->size = size; @@ -513,7 +513,7 @@ nmFree(void* ptr, int size) ASSERTMAGIC(OVERLAY(tmp),MGK_FREEMEM); if (OVERLAY(tmp) == OVERLAY(ptr)) { - printf("Duplicate nmFree()!!! Size = %d, Address = %p\n", size, ptr); + fprintf(stderr, "Duplicate nmFree()!!! Size = %d, Address = %p\n", size, ptr); if (err_fn) err_fn("Internal error - duplicate nmFree() occurred."); return; } @@ -556,6 +556,11 @@ nmStats(void) { if (!is_init) nmInitialize(); + /** Warn if statistics are not being tracked. **/ + #ifndef GLOBAL_BLK_COUNTING + fprintf(stderr, "Warning: GLOBAL_BLK_COUNTING is disabled.\n"); + #endif + /** Print subsystem stats. **/ printf( "NewMalloc subsystem statistics:\n" @@ -594,6 +599,25 @@ nmRegister(int size, char* name) return; } +/*** Print the registered names for a block of data of a given size to stdout. + *** + *** @param size The size of block to query. + ***/ +void +nmPrintNames(int size) + { + /*** Traverse the linked list that holds all registered names for the given + *** size and print each one. + **/ + for (pRegisteredBlockType blk = blknames[size]; blk != NULL; blk = blk->Next) + { + ASSERTMAGIC(blk, MGK_REGISBLK); + printf("%s ", blk->Name); + } + + return; + } + /** Print debug information about the newmalloc system. **/ void @@ -611,14 +635,8 @@ nmDebug(void) /** Print stats about this block size. **/ printf("%ld\t%d\t%d\t%d\t", size, outcnt[size], listcnt[size], usagecnt[size]); - /*** Traverse the linked list that holds all registered names for the given - *** size and print each one. - **/ - for (pRegisteredBlockType blk = blknames[size]; blk != NULL; blk = blk->Next) - { - ASSERTMAGIC(blk, MGK_REGISBLK); - printf("%s ", blk->Name); - } + /** Print each name for this block size. **/ + nmPrintNames(size); printf("\n"); } @@ -660,14 +678,8 @@ nmDeltas(void) printf("%ld\t%d\t", size, outcnt[size] - outcnt_delta[size]); total_delta += (size * (outcnt[size] - outcnt_delta[size])); - /*** Traverse the linked list that holds all registered names for the given - *** size and print each one. - **/ - for (pRegisteredBlockType blk = blknames[size]; blk != NULL; blk = blk->Next) - { - ASSERTMAGIC(blk, MGK_REGISBLK); - printf("%s ", blk->Name); - } + /** Print each name for this block size from the linked list. **/ + nmPrintNames(size); /** End of line. **/ printf("\n"); @@ -854,3 +866,26 @@ nmSysStrdup(const char* str) return NULL; /** Unreachable. **/ } + + +/*** Gets the size of memory allocated in the buffer using an `nmSysXYZ()` + *** function, if possible (depending on compiler #define flags, this size + *** might not be stored). + *** + *** @param ptr A pointer to the memory buffer to be checked. The function's + *** behavior is undefined if this pointer is a nonNULL value which does + *** NOT point to the start of a valid memory block from an `nmSysXYZ()`. + *** @returns The size of the memory buffer, if it can be found, or + *** -1 if the size of the buffere was not stored, or + *** -1 if `ptr` is NULL. + ***/ +int +nmSysGetSize(void* ptr) + { +#ifndef NM_USE_SYSMALLOC + return -1; /* Value not stored. */ +#else + if (ptr == NULL) return -1; + return *(ptr - sizeof(int)); +#endif + } From 7de81eeb4e67a0198beab40afb204365295619fb Mon Sep 17 00:00:00 2001 From: Lightning11wins Date: Thu, 8 Jan 2026 10:55:28 -0700 Subject: [PATCH 4/7] Fix a compiler error caused by a missing typecast. --- centrallix-lib/src/newmalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/centrallix-lib/src/newmalloc.c b/centrallix-lib/src/newmalloc.c index fc877c034..ad4df09b8 100644 --- a/centrallix-lib/src/newmalloc.c +++ b/centrallix-lib/src/newmalloc.c @@ -886,6 +886,6 @@ nmSysGetSize(void* ptr) return -1; /* Value not stored. */ #else if (ptr == NULL) return -1; - return *(ptr - sizeof(int)); + return *(int*)(ptr - sizeof(int)); #endif } From 6940889e9d78bcb21315da188544313bfa1d6620 Mon Sep 17 00:00:00 2001 From: Lightning11wins Date: Wed, 18 Feb 2026 11:04:43 -0700 Subject: [PATCH 5/7] Address GreptileAI comments. Fix buffer overflow in nmDebugRealloc(). Fix buffer overflow in nmRegister(). Fix incorrect format specifiers for size types. Fix pointer arithmetic on void*. Reduce padding in RegisteredBlockType struct. Add doc comment for RegisteredBlockType struct. Fix typos in comments. Improve detail and clarity of some comments. --- centrallix-lib/include/newmalloc.h | 7 ++-- centrallix-lib/src/newmalloc.c | 54 ++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/centrallix-lib/include/newmalloc.h b/centrallix-lib/include/newmalloc.h index 7fa0fa781..6b31de0bd 100644 --- a/centrallix-lib/include/newmalloc.h +++ b/centrallix-lib/include/newmalloc.h @@ -44,9 +44,10 @@ typedef struct _ov #define SIZED_BLK_COUNTING 1 #endif -/*** nmMalloc block caching causes Valgrind to lose track of the call stack - *** where the developer allocated the block. If we are using Valgrind, this - *** caching is disabled. ALso, the nmSysXyz() call are simply pass-throughs. +/*** nmMalloc() block caching reuses memory blocks, causing Valgrind to loose + *** track of where the developer actually allocated them. Thus, we disable + *** it if Valgrind is in use. Also, we disable the nmSysXyz() calls, causing + *** them to be replaced with pass-through wrappers. ***/ #ifdef USING_VALGRIND #define NO_BLK_CACHE 1 diff --git a/centrallix-lib/src/newmalloc.c b/centrallix-lib/src/newmalloc.c index ad4df09b8..83ade0f12 100644 --- a/centrallix-lib/src/newmalloc.c +++ b/centrallix-lib/src/newmalloc.c @@ -41,6 +41,20 @@ #include "magic.h" #include "newmalloc.h" +/** Temporary implementations until the ones from the dups branch is available. **/ +/** TODO: Israel - Remove once the dups branch is merged. **/ +#define min(a, b) \ + ({ \ + __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + (_a < _b) ? _a : _b; \ + }) +#define max(a, b) \ + ({ \ + __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + (_a > _b) ? _a : _b; \ + }) /*** BUFFER_OVERFLOW_CHECKING adds 4 bytes of magic data to either end of *** the memory buffer returned to the user by nmMalloc(). This allows us @@ -73,7 +87,8 @@ pMemStruct startMemList; #endif /** List of overlay structs, used for caching allocated memory. **/ -pOverlay lists[MAX_SIZE+1]; /* TODO: Greg - Is this 65KB global variable a problem? (On the stack, it would be...) */ +/** TODO: Greg - This is nearly 200 KB of variables, is that a problem? (On the stack, this would be a seg fault!!) **/ +pOverlay lists[MAX_SIZE+1]; int listcnt[MAX_SIZE+1]; int outcnt[MAX_SIZE+1]; int outcnt_delta[MAX_SIZE+1]; @@ -95,15 +110,29 @@ int (*err_fn)() = NULL; int nmsys_outcnt[MAX_SIZE+1]; int nmsys_outcnt_delta[MAX_SIZE+1]; +/*** The registration data that associates a name with a specific block size + *** of data stored in memory. Used to create a linked list for each possible + *** block size. + *** + *** Memory Stats: + *** - Padding: 0 bytes + *** - Total size: 80 bytes + *** + *** @param Size The size of the memory block. + *** @param Name The name associated with the memory block. + *** @param Next The next block of this size in the linked list. + *** @param Magic A magic value for detecting corrupted memory. + ***/ typedef struct _RB { int Magic; + int Size; struct _RB* Next; char Name[64]; - int Size; } RegisteredBlockType, *pRegisteredBlockType; +/** Heads of registered-block linked lists, where index = block size. **/ pRegisteredBlockType blknames[MAX_SIZE+1]; @@ -289,7 +318,7 @@ nmDebugRealloc(void* ptr, int new_size) /** Move the old data. **/ int old_size = MEMDATATOSTRUCT(ptr)->size; - memmove(new_ptr, ptr, old_size); + memmove(new_ptr, ptr, min(new_size, old_size)); /** Free the old allocation. **/ nmDebugFree(ptr); @@ -594,7 +623,7 @@ nmRegister(int size, char* name) /** Initialize values for this record. **/ blk->Magic = MGK_REGISBLK; blk->Size = size; - strcpy(blk->Name, name); + strtcpy(blk->Name, name, sizeof(blk->Name) / sizeof(char)); return; } @@ -633,7 +662,7 @@ nmDebug(void) if (usagecnt[size] == 0) continue; /** Print stats about this block size. **/ - printf("%ld\t%d\t%d\t%d\t", size, outcnt[size], listcnt[size], usagecnt[size]); + printf("%zu\t%d\t%d\t%d\t", size, outcnt[size], listcnt[size], usagecnt[size]); /** Print each name for this block size. **/ nmPrintNames(size); @@ -652,7 +681,7 @@ nmDebug(void) if (nmsys_outcnt[size] == 0) continue; /** Print the nmSysXYZ() block information. **/ - printf("%ld\t%d\n", size, nmsys_outcnt[size]); + printf("%zu\t%d\n", size, nmsys_outcnt[size]); } printf("\n"); @@ -675,7 +704,7 @@ nmDeltas(void) if (outcnt[size] == outcnt_delta[size]) continue; /** Print the change and add it to the total_delta. **/ - printf("%ld\t%d\t", size, outcnt[size] - outcnt_delta[size]); + printf("%zu\t%d\t", size, outcnt[size] - outcnt_delta[size]); total_delta += (size * (outcnt[size] - outcnt_delta[size])); /** Print each name for this block size from the linked list. **/ @@ -696,7 +725,7 @@ nmDeltas(void) if (nmsys_outcnt[size] == nmsys_outcnt_delta[size]) continue; /** Print the results. **/ - printf("%ld\t%d\n", size, nmsys_outcnt[size] - nmsys_outcnt_delta[size]); + printf("%zu\t%d\n", size, nmsys_outcnt[size] - nmsys_outcnt_delta[size]); total_delta += (size * (nmsys_outcnt[size] - nmsys_outcnt_delta[size])); nmsys_outcnt_delta[size] = nmsys_outcnt[size]; } @@ -886,6 +915,11 @@ nmSysGetSize(void* ptr) return -1; /* Value not stored. */ #else if (ptr == NULL) return -1; - return *(int*)(ptr - sizeof(int)); -#endif + + /*** Create a pointer to the start of the allocated buffer, which stores + *** the allocated size. + ***/ + int* buffer_ptr = ((char*)ptr) - sizeof(int); + return *buffer_ptr; +#endif } From c40fc8d076239ec12ace122e0163d9806e73765c Mon Sep 17 00:00:00 2001 From: Lightning11wins Date: Wed, 18 Feb 2026 13:37:03 -0700 Subject: [PATCH 6/7] Overhaul types in newmalloc. Update allocation function to use size_t (instead of int), matching C stdlib functions. Update statistics variables to use unsigned long long instead of int. Add ignored errors when tracked statistics indicate something has gone wrong. Improve formatting for printing of statistics. Improve formatting of printed errors to start with ERROR (making them more obvious). Fix build warning due to a missing include statement. Clean up some comments. --- centrallix-lib/include/newmalloc.h | 16 +-- centrallix-lib/src/newmalloc.c | 178 +++++++++++++++++------------ 2 files changed, 115 insertions(+), 79 deletions(-) diff --git a/centrallix-lib/include/newmalloc.h b/centrallix-lib/include/newmalloc.h index 6b31de0bd..061f7f520 100644 --- a/centrallix-lib/include/newmalloc.h +++ b/centrallix-lib/include/newmalloc.h @@ -55,7 +55,7 @@ typedef struct _ov #endif #define OVERLAY(x) ((pOverlay)(x)) -#define MAX_SIZE (8192) +#define MAX_SIZE (8192lu) #define MIN_SIZE (sizeof(Overlay)) #ifdef BLK_LEAK_CHECK @@ -69,18 +69,18 @@ void nmInitialize(); void nmSetErrFunction(int (*error_fn)()); void nmClear(); void nmCheckAll(); // checks for buffer overflows -void* nmMalloc(int size); -void nmFree(void* ptr, int size); +void* nmMalloc(size_t size); +void nmFree(void* ptr, size_t size); void nmStats(); -void nmRegister(int size, char* name); -void nmPrintNames(int size); +void nmRegister(size_t size, char* name); +void nmPrintNames(size_t size); void nmDebug(); void nmDeltas(); -void* nmSysMalloc(int size); +void* nmSysMalloc(size_t size); void nmSysFree(void* ptr); -void* nmSysRealloc(void* ptr, int new_size); +void* nmSysRealloc(void* ptr, size_t new_size); char* nmSysStrdup(const char* str); -int nmSysGetSize(void* ptr); +size_t nmSysGetSize(void* ptr); /** Tagging system (not implemented). **/ void nmEnableTagging(); diff --git a/centrallix-lib/src/newmalloc.c b/centrallix-lib/src/newmalloc.c index 83ade0f12..940041950 100644 --- a/centrallix-lib/src/newmalloc.c +++ b/centrallix-lib/src/newmalloc.c @@ -32,6 +32,7 @@ #include "cxlibconfig-internal.h" #endif +#include #include #include #include @@ -40,6 +41,7 @@ #include "magic.h" #include "newmalloc.h" +#include "strtcpy.h" /** Temporary implementations until the ones from the dups branch is available. **/ /** TODO: Israel - Remove once the dups branch is merged. **/ @@ -70,7 +72,7 @@ #ifdef BUFFER_OVERFLOW_CHECKING typedef struct _mem { - int size; + size_t size; struct _mem *next; int magic_start; /** not 'really' here **/ @@ -87,17 +89,17 @@ pMemStruct startMemList; #endif /** List of overlay structs, used for caching allocated memory. **/ -/** TODO: Greg - This is nearly 200 KB of variables, is that a problem? (On the stack, this would be a seg fault!!) **/ +/** TODO: Greg - This is over 327 KB of variables, is that a problem? (On the stack, this would be a seg fault!!) **/ pOverlay lists[MAX_SIZE+1]; -int listcnt[MAX_SIZE+1]; -int outcnt[MAX_SIZE+1]; -int outcnt_delta[MAX_SIZE+1]; -int usagecnt[MAX_SIZE+1]; -int nmFreeCnt; -int nmMallocCnt; -int nmMallocHits; -int nmMallocTooBig; -int nmMallocLargest; +unsigned long long int listcnt[MAX_SIZE+1]; +unsigned long long int outcnt[MAX_SIZE+1]; +unsigned long long int outcnt_delta[MAX_SIZE+1]; +unsigned long long int usagecnt[MAX_SIZE+1]; +unsigned long long int nmFreeCnt; +unsigned long long int nmMallocCnt; +unsigned long long int nmMallocHits; +unsigned long long int nmMallocTooBig; +size_t nmMallocLargest; #ifdef BLK_LEAK_CHECK void* blks[MAX_BLOCKS]; @@ -107,8 +109,8 @@ int blksiz[MAX_BLOCKS]; bool is_init = false; int (*err_fn)() = NULL; -int nmsys_outcnt[MAX_SIZE+1]; -int nmsys_outcnt_delta[MAX_SIZE+1]; +unsigned long long int nmsys_outcnt[MAX_SIZE+1]; +unsigned long long int nmsys_outcnt_delta[MAX_SIZE+1]; /*** The registration data that associates a name with a specific block size *** of data stored in memory. Used to create a linked list for each possible @@ -186,7 +188,7 @@ nmCheckItem(pMemStruct mem) if (mem->magic_start != MGK_MEMSTART) { fprintf(stderr, - "Bad magic_start at %p (%p) -- 0x%08x != 0x%08x\n", + "ERROR: Bad magic_start at %p (%p) -- 0x%08x != 0x%08x\n", MEMDATA(mem), mem, mem->magic_start, MGK_MEMSTART ); ret = -1; @@ -196,7 +198,7 @@ nmCheckItem(pMemStruct mem) if (ENDMAGIC(mem) != MGK_MEMEND) { fprintf(stderr, - "Bad magic_end at %p (%p) -- 0x%08x != 0x%08x\n", + "ERROR: Bad magic_end at %p (%p) -- 0x%08x != 0x%08x\n", MEMDATA(mem), mem, ENDMAGIC(mem), MGK_MEMEND ); ret = -1; @@ -239,7 +241,7 @@ nmCheckAll(void) *** @returns A pointer to the start of the allocated memory buffer. ***/ void* -nmDebugMalloc(int size) +nmDebugMalloc(size_t size) { /** Allocate space for the data. **/ pMemStruct tmp = (pMemStruct)malloc(size + EXTRA_MEM); @@ -307,7 +309,7 @@ nmDebugFree(void* ptr) *** @returns The new buffer, or NULL if an error occurs. ***/ void* -nmDebugRealloc(void* ptr, int new_size) +nmDebugRealloc(void* ptr, size_t new_size) { /** Behaves as nmDebugMalloc() if there is no target pointer. **/ if (ptr == NULL) return nmDebugMalloc(new_size); @@ -317,7 +319,7 @@ nmDebugRealloc(void* ptr, int new_size) if (new_ptr == NULL) return NULL; /** Move the old data. **/ - int old_size = MEMDATATOSTRUCT(ptr)->size; + size_t old_size = MEMDATATOSTRUCT(ptr)->size; memmove(new_ptr, ptr, min(new_size, old_size)); /** Free the old allocation. **/ @@ -379,7 +381,7 @@ nmClear(void) *** @returns A pointer to the start of the allocated memory block. ***/ void* -nmMalloc(int size) +nmMalloc(size_t size) { void* tmp = NULL; @@ -423,6 +425,13 @@ nmMalloc(int size) /** Handle counting. **/ #ifdef SIZED_BLK_COUNTING + if (listcnt[size] == 0u) + { + fprintf(stderr, + "ERROR: Removed block from cache when stats show that " + "it should be empty!! Expect broken statistics.\n" + ); + } listcnt[size]--; #endif } @@ -493,7 +502,7 @@ nmMalloc(int size) *** available to us, so it must be provided for this function to run.) ***/ void -nmFree(void* ptr, int size) +nmFree(void* ptr, size_t size) { if (!is_init) nmInitialize(); @@ -542,7 +551,7 @@ nmFree(void* ptr, int size) ASSERTMAGIC(OVERLAY(tmp),MGK_FREEMEM); if (OVERLAY(tmp) == OVERLAY(ptr)) { - fprintf(stderr, "Duplicate nmFree()!!! Size = %d, Address = %p\n", size, ptr); + fprintf(stderr, "ERROR: Duplicate nmFree()!!! Size = %d, Address = %p\n", size, ptr); if (err_fn) err_fn("Internal error - duplicate nmFree() occurred."); return; } @@ -557,6 +566,13 @@ nmFree(void* ptr, int size) /** Handle counting. **/ #ifdef SIZED_BLK_COUNTING + if (outcnt[size] == 0u) + { + fprintf(stderr, + "ERROR: Call to nmFree() memory of a size that has no " + "valid allocated memory!! Expect broken statistics.\n" + ); + } outcnt[size]--; listcnt[size]++; #endif @@ -593,10 +609,10 @@ nmStats(void) /** Print subsystem stats. **/ printf( "NewMalloc subsystem statistics:\n" - " nmMalloc: %d calls, %d hits (%3.3f%%)\n" - " nmFree: %d calls\n" - " bigblks: %d too big, %d largest size\n\n", - nmMallocCnt, nmMallocHits, (float)nmMallocHits / (float)nmMallocCnt * 100.0, + " nmMalloc: %llu calls, %llu hits (%3.3lf%%)\n" + " nmFree: %llu calls\n" + " bigblks: %llu too big, %zu largest size\n\n", + nmMallocCnt, nmMallocHits, (double)nmMallocHits / (double)nmMallocCnt * 100.0, nmFreeCnt, nmMallocTooBig, nmMallocLargest ); @@ -607,7 +623,7 @@ nmStats(void) /** Register a new memory size with a name, for debugging. **/ void -nmRegister(int size, char* name) +nmRegister(size_t size, char* name) { pRegisteredBlockType blk = NULL; @@ -633,11 +649,9 @@ nmRegister(int size, char* name) *** @param size The size of block to query. ***/ void -nmPrintNames(int size) +nmPrintNames(size_t size) { - /*** Traverse the linked list that holds all registered names for the given - *** size and print each one. - **/ + /** Traverse the linked list of registered structs to print each name. **/ for (pRegisteredBlockType blk = blknames[size]; blk != NULL; blk = blk->Next) { ASSERTMAGIC(blk, MGK_REGISBLK); @@ -659,10 +673,13 @@ nmDebug(void) for (size_t size = MIN_SIZE; size < MAX_SIZE; size++) { /** Skip unused block sizes. **/ - if (usagecnt[size] == 0) continue; + if (usagecnt[size] == 0llu) continue; /** Print stats about this block size. **/ - printf("%zu\t%d\t%d\t%d\t", size, outcnt[size], listcnt[size], usagecnt[size]); + printf( + "%zu\t%llu\t%lld\t%llu\t", + size, outcnt[size], listcnt[size], usagecnt[size] + ); /** Print each name for this block size. **/ nmPrintNames(size); @@ -671,17 +688,20 @@ nmDebug(void) } /** Print the header for the nmSysXYZ() info table. **/ - printf("\n-----\n"); - printf("size\toutcnt\n-------\t-------\n"); + printf( + "\n-----\n" + "size\toutcnt\n" + "-------\t-------\n" + ); /** Iterate through each possible block size. **/ for (size_t size = MIN_SIZE; size <= MAX_SIZE; size++) { /** Skip unused block sizes. **/ - if (nmsys_outcnt[size] == 0) continue; + if (nmsys_outcnt[size] == 0llu) continue; /** Print the nmSysXYZ() block information. **/ - printf("%zu\t%d\n", size, nmsys_outcnt[size]); + printf("%zu\t%llu\n", size, nmsys_outcnt[size]); } printf("\n"); @@ -694,17 +714,20 @@ void nmDeltas(void) { /** Print the header for the block size deltas table. **/ - printf("size\tdelta\tnames\n-------\t-------\t-------\n"); + printf( + "size\tdelta\tnames\n" + "-------\t-------\t-------\n" + ); /** Iterate through each possible block size. **/ - int total_delta = 0; + unsigned long long int total_delta = 0llu; for (size_t size = MIN_SIZE; size <= MAX_SIZE; size++) { /** Skip entries where there is no change. **/ if (outcnt[size] == outcnt_delta[size]) continue; /** Print the change and add it to the total_delta. **/ - printf("%zu\t%d\t", size, outcnt[size] - outcnt_delta[size]); + printf("%zu\t%lld\t", size, outcnt[size] - outcnt_delta[size]); total_delta += (size * (outcnt[size] - outcnt_delta[size])); /** Print each name for this block size from the linked list. **/ @@ -718,14 +741,17 @@ nmDeltas(void) } /** Print the header for the nmSysXYZ() info table. **/ - printf("\nsize\tdelta\n-------\t-------\n"); + printf( + "\nsize\tdelta\n" + "-------\t-------\n" + ); for (size_t size = MIN_SIZE; size <= MAX_SIZE; size++) { /** Skip sizes where no change in memory occurred. **/ if (nmsys_outcnt[size] == nmsys_outcnt_delta[size]) continue; /** Print the results. **/ - printf("%zu\t%d\n", size, nmsys_outcnt[size] - nmsys_outcnt_delta[size]); + printf("%zu\t%llu\n", size, nmsys_outcnt[size] - nmsys_outcnt_delta[size]); total_delta += (size * (nmsys_outcnt[size] - nmsys_outcnt_delta[size])); nmsys_outcnt_delta[size] = nmsys_outcnt[size]; } @@ -733,7 +759,7 @@ nmDeltas(void) /** Print the total delta. **/ /** TODO: Israel - Change this to use snprint_bytes() once that function is available. **/ - printf("delta %d total bytes\n", total_delta); + printf("delta %llu total bytes\n", total_delta); return; } @@ -751,7 +777,7 @@ nmDeltas(void) *** @returns A pointer to the start of the allocated memory block. ***/ void* -nmSysMalloc(int size) +nmSysMalloc(size_t size) { /** Fallback if sysMalloc() is disabled. **/ #ifndef NM_USE_SYSMALLOC @@ -759,19 +785,30 @@ nmSysMalloc(int size) #else /** Allocate the requested space, plus the initial size int. **/ - char* ptr = (char*)nmDebugMalloc(sizeof(int) + size); + char* ptr = (char*)nmDebugMalloc(sizeof(unsigned int) + size); if (ptr == NULL) return NULL; - /** Set the size int. **/ - *(int*)ptr = size; + /** Convert the provided size to an unsigned int. **/ + /** TODO: Greg - Can we modify nmSys blocks to start with a size_t to avoid this? **/ + if (size > UINT_MAX) + { + fprintf(stderr, + "ERROR: Requested buffer size (%zu) > UINT MAX (%u).\n", + size, UINT_MAX + ); + return NULL; + } + + /** Set the size uint. **/ + *(unsigned int*)(ptr) = (unsigned int)size; /** Update sized block counting, if necessary. **/ #ifdef SIZED_BLK_COUNTING if (size > 0 && size <= MAX_SIZE) nmsys_outcnt[size]++; #endif - /** Return the allocated memory (starting after the size int). **/ - return (void*)(sizeof(int) + ptr); + /** Return the allocated memory (starting after the size uint). **/ + return (void*)(sizeof(unsigned int) + ptr); #endif return NULL; /** Unreachable. **/ @@ -799,13 +836,12 @@ nmSysFree(void* ptr) /** Count sized blocks, if enabled. **/ #ifdef SIZED_BLK_COUNTING - int size; - size = *(int*)(((char*)ptr)-sizeof(int)); + const size_t size = nmSysGetSize(ptr); if (size > 0 && size <= MAX_SIZE) nmsys_outcnt[size]--; #endif - /** Free the initial size int, as well as the rest of the allocated memory. **/ - nmDebugFree(((char*)ptr) - sizeof(int)); + /** Free the initial unsigned int, as well as the rest of the allocated memory. **/ + nmDebugFree(((char*)ptr) - sizeof(unsigned int)); #endif return; @@ -822,7 +858,7 @@ nmSysFree(void* ptr) *** @returns The new buffer, or NULL if an error occurs. ***/ void* -nmSysRealloc(void* ptr, int new_size) +nmSysRealloc(void* ptr, size_t new_size) { /** Fallback if sysMalloc() is disabled. **/ #ifndef NM_USE_SYSMALLOC @@ -832,17 +868,16 @@ nmSysRealloc(void* ptr, int new_size) /** Behaves as nmSysMalloc() if there is no target pointer. **/ if (ptr == NULL) return nmSysMalloc(new_size); - /** If no work needs to be done, do nothing. **/ - void* buffer_ptr = ((char*)ptr) - sizeof(int); - const int size = *(int*)buffer_ptr; - if (size == new_size) return ptr; + /** If the memory block size does not change, do nothing. **/ + if (nmSysGetSize(ptr) == new_size) return ptr; - /** Realloc the given memory with space for the initial size int. **/ - char* new_ptr = (char*)nmDebugRealloc(buffer_ptr, sizeof(int) + new_size); + /** Realloc the given memory with space for the initial uint. **/ + void* buffer_ptr = ((char*)ptr) - sizeof(unsigned int); + char* new_ptr = (char*)nmDebugRealloc(buffer_ptr, sizeof(unsigned int) + new_size); if (new_ptr == NULL) return NULL; - /** Update the initial size int. **/ - *(int*)new_ptr = new_size; + /** Update the initial size uint. **/ + *(unsigned int*)new_ptr = new_size; /** Handle counting. **/ #ifdef SIZED_BLK_COUNTING @@ -851,7 +886,7 @@ nmSysRealloc(void* ptr, int new_size) #endif /** Return the pointer to the new memory. **/ - return (void*)(sizeof(int) + new_ptr); + return (void*)(sizeof(unsigned int) + new_ptr); #endif return NULL; /** Unreachable. **/ @@ -905,21 +940,22 @@ nmSysStrdup(const char* str) *** behavior is undefined if this pointer is a nonNULL value which does *** NOT point to the start of a valid memory block from an `nmSysXYZ()`. *** @returns The size of the memory buffer, if it can be found, or - *** -1 if the size of the buffere was not stored, or - *** -1 if `ptr` is NULL. + *** 0 if the size of the buffer was not stored, or + *** 0 if `ptr` is NULL. ***/ -int +size_t nmSysGetSize(void* ptr) { #ifndef NM_USE_SYSMALLOC - return -1; /* Value not stored. */ + return 0lu; /* Value not stored. */ #else - if (ptr == NULL) return -1; + if (ptr == NULL) return 0lu; - /*** Create a pointer to the start of the allocated buffer, which stores - *** the allocated size. + /*** Create a pointer to the start of the allocated buffer and read the + *** allocation size stored there. ***/ - int* buffer_ptr = ((char*)ptr) - sizeof(int); - return *buffer_ptr; + const void* buffer_ptr = ((char*)ptr) - sizeof(unsigned int); + const unsigned int raw_size_value = *(unsigned int*)buffer_ptr; + return (size_t)raw_size_value; #endif } From 3e6284b1c60fcba95d82853d4a8c3dc2bd31bc23 Mon Sep 17 00:00:00 2001 From: Lightning11wins Date: Thu, 19 Feb 2026 10:34:32 -0700 Subject: [PATCH 7/7] Update types. Update nmSys blocks to use size_t to store size data. Update MemStruct to match new types. Update RegisteredBlockType to match new types. Update and add comments. Fix incorrect format specifiers. --- centrallix-lib/src/newmalloc.c | 84 +++++++++++++++------------------- 1 file changed, 38 insertions(+), 46 deletions(-) diff --git a/centrallix-lib/src/newmalloc.c b/centrallix-lib/src/newmalloc.c index 940041950..d8d80b1b3 100644 --- a/centrallix-lib/src/newmalloc.c +++ b/centrallix-lib/src/newmalloc.c @@ -73,18 +73,23 @@ typedef struct _mem { size_t size; - struct _mem *next; - int magic_start; - /** not 'really' here **/ - // char data[size]; - // int magic_end; + struct _mem* next; + Magic_t magic_start; + /** Data after the struct. **/ + // char data[size]; /* The wrapped memory buffer. */ + // Magic_t magic_end; } MemStruct, *pMemStruct; -#define EXTRA_MEM (3*sizeof(int)+sizeof(void*)) -#define MEMSTRUCT(x) ((pMemStruct)(x)) -#define MEMDATA(x) ((void*)((char*)(x)+(sizeof(int)*2+sizeof(void*)))) -#define ENDMAGIC(x) (*((int*)((char*)(MEMDATA(x))+MEMSTRUCT(x)->size))) -#define MEMDATATOSTRUCT(x) ((pMemStruct)((char*)(x)-(sizeof(int)*2+sizeof(void*)))) +/*** The amount of additional memory consumed by each memory buffer, in bytes, + *** when the buffer overflow checking wrapper is enabled. + ***/ +#define EXTRA_MEM (sizeof(MemStruct) + sizeof(Magic_t)) +/** Converts a MemStruct pointer to a pointer to the wrapped data. **/ +#define MEMDATA(x) ((void*)((char*)(x) + sizeof(MemStruct))) +/** Gets the magic value from the end of a wrapped data buffer. **/ +#define ENDMAGIC(x) (*(int*)((char*)MEMDATA(x) + ((pMemStruct)(x))->size)) +/** Converts a data buffer to a pointer to the wrapping MemStruct. **/ +#define MEMDATATOSTRUCT(x) ((pMemStruct)((char*)(x) - sizeof(MemStruct))) pMemStruct startMemList; #endif @@ -127,8 +132,8 @@ unsigned long long int nmsys_outcnt_delta[MAX_SIZE+1]; ***/ typedef struct _RB { - int Magic; - int Size; + Magic_t Magic; + size_t Size; struct _RB* Next; char Name[64]; } @@ -551,7 +556,7 @@ nmFree(void* ptr, size_t size) ASSERTMAGIC(OVERLAY(tmp),MGK_FREEMEM); if (OVERLAY(tmp) == OVERLAY(ptr)) { - fprintf(stderr, "ERROR: Duplicate nmFree()!!! Size = %d, Address = %p\n", size, ptr); + fprintf(stderr, "ERROR: Duplicate nmFree()!!! Size = %zu, Address = %p\n", size, ptr); if (err_fn) err_fn("Internal error - duplicate nmFree() occurred."); return; } @@ -677,7 +682,7 @@ nmDebug(void) /** Print stats about this block size. **/ printf( - "%zu\t%llu\t%lld\t%llu\t", + "%zu\t%llu\t%llu\t%llu\t", size, outcnt[size], listcnt[size], usagecnt[size] ); @@ -784,31 +789,20 @@ nmSysMalloc(size_t size) return (void*)nmDebugMalloc(size); #else - /** Allocate the requested space, plus the initial size int. **/ - char* ptr = (char*)nmDebugMalloc(sizeof(unsigned int) + size); + /** Allocate the requested space, plus the initial size number. **/ + char* ptr = (char*)nmDebugMalloc(sizeof(size_t) + size); if (ptr == NULL) return NULL; - /** Convert the provided size to an unsigned int. **/ - /** TODO: Greg - Can we modify nmSys blocks to start with a size_t to avoid this? **/ - if (size > UINT_MAX) - { - fprintf(stderr, - "ERROR: Requested buffer size (%zu) > UINT MAX (%u).\n", - size, UINT_MAX - ); - return NULL; - } - - /** Set the size uint. **/ - *(unsigned int*)(ptr) = (unsigned int)size; + /** Set the size number. **/ + *(size_t*)(ptr) = size; /** Update sized block counting, if necessary. **/ #ifdef SIZED_BLK_COUNTING if (size > 0 && size <= MAX_SIZE) nmsys_outcnt[size]++; #endif - /** Return the allocated memory (starting after the size uint). **/ - return (void*)(sizeof(unsigned int) + ptr); + /** Return the allocated memory (starting after the size number). **/ + return (void*)(sizeof(size_t) + ptr); #endif return NULL; /** Unreachable. **/ @@ -840,8 +834,8 @@ nmSysFree(void* ptr) if (size > 0 && size <= MAX_SIZE) nmsys_outcnt[size]--; #endif - /** Free the initial unsigned int, as well as the rest of the allocated memory. **/ - nmDebugFree(((char*)ptr) - sizeof(unsigned int)); + /** Free the initial size_t, as well as the rest of the allocated memory. **/ + nmDebugFree(((char*)ptr) - sizeof(size_t)); #endif return; @@ -869,15 +863,16 @@ nmSysRealloc(void* ptr, size_t new_size) if (ptr == NULL) return nmSysMalloc(new_size); /** If the memory block size does not change, do nothing. **/ - if (nmSysGetSize(ptr) == new_size) return ptr; + const size_t size = nmSysGetSize(ptr); + if (size == new_size) return ptr; - /** Realloc the given memory with space for the initial uint. **/ - void* buffer_ptr = ((char*)ptr) - sizeof(unsigned int); - char* new_ptr = (char*)nmDebugRealloc(buffer_ptr, sizeof(unsigned int) + new_size); + /** Realloc the given memory with space for the initial size number. **/ + void* buffer_ptr = ((char*)ptr) - sizeof(size_t); + char* new_ptr = (char*)nmDebugRealloc(buffer_ptr, sizeof(size_t) + new_size); if (new_ptr == NULL) return NULL; - /** Update the initial size uint. **/ - *(unsigned int*)new_ptr = new_size; + /** Update the initial size number. **/ + *(size_t*)(new_ptr) = new_size; /** Handle counting. **/ #ifdef SIZED_BLK_COUNTING @@ -886,7 +881,7 @@ nmSysRealloc(void* ptr, size_t new_size) #endif /** Return the pointer to the new memory. **/ - return (void*)(sizeof(unsigned int) + new_ptr); + return (void*)(sizeof(size_t) + new_ptr); #endif return NULL; /** Unreachable. **/ @@ -951,11 +946,8 @@ nmSysGetSize(void* ptr) #else if (ptr == NULL) return 0lu; - /*** Create a pointer to the start of the allocated buffer and read the - *** allocation size stored there. - ***/ - const void* buffer_ptr = ((char*)ptr) - sizeof(unsigned int); - const unsigned int raw_size_value = *(unsigned int*)buffer_ptr; - return (size_t)raw_size_value; + /** Read the size from the start of the nmSys block. **/ + const void* buffer_ptr = ((char*)ptr) - sizeof(size_t); + return *(size_t*)buffer_ptr; #endif }