diff options
| author | apnadkarni <apnmbx-wits@yahoo.com> | 2023-05-20 16:39:50 (GMT) |
|---|---|---|
| committer | apnadkarni <apnmbx-wits@yahoo.com> | 2023-05-20 16:39:50 (GMT) |
| commit | f19e2665d309df5a484a53ea6d9b1098275e33db (patch) | |
| tree | 6906aa04fcb87740b514d40f1b4c83435a53a645 /generic/tclCkalloc.c | |
| parent | 72dfeb60e23c679d2c7258db4eb9ccce0a0661fa (diff) | |
| parent | 96d441c29a2a47269655285a02c546765c163fd2 (diff) | |
| download | tcl-f19e2665d309df5a484a53ea6d9b1098275e33db.zip tcl-f19e2665d309df5a484a53ea6d9b1098275e33db.tar.gz tcl-f19e2665d309df5a484a53ea6d9b1098275e33db.tar.bz2 | |
Fix [c9663296fd]. Also refactor memory reallocation.
Diffstat (limited to 'generic/tclCkalloc.c')
| -rw-r--r-- | generic/tclCkalloc.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/generic/tclCkalloc.c b/generic/tclCkalloc.c index 09e140a..106a62c 100644 --- a/generic/tclCkalloc.c +++ b/generic/tclCkalloc.c @@ -16,6 +16,7 @@ */ #include "tclInt.h" +#include <assert.h> #define FALSE 0 #define TRUE 1 @@ -1234,6 +1235,148 @@ TclDumpMemoryInfo( #endif /* TCL_MEM_DEBUG */ /* + *------------------------------------------------------------------------ + * + * TclAllocElemsEx -- + * + * See TclAttemptAllocElemsEx. This function differs in that it panics + * on failure. + * + * Results: + * Non-NULL pointer to allocated memory block. + * + * Side effects: + * Panics if memory of at least the requested size could not be + * allocated. + * + *------------------------------------------------------------------------ + */ +void * +TclAllocElemsEx( + Tcl_Size elemCount, /* Allocation will store at least these many... */ + Tcl_Size elemSize, /* ...elements of this size */ + Tcl_Size leadSize, /* Additional leading space in bytes */ + Tcl_Size *capacityPtr) /* OUTPUT: Actual capacity is stored + here if non-NULL. Only modified on success */ +{ + void *ptr = TclAttemptReallocElemsEx( + NULL, elemCount, elemSize, leadSize, capacityPtr); + if (ptr == NULL) { + Tcl_Panic("Failed to allocate %" TCL_SIZE_MODIFIER + "d elements of size %" TCL_SIZE_MODIFIER "d bytes.", + elemCount, + elemSize); + } + return ptr; +} + +/* + *------------------------------------------------------------------------ + * + * TclAttemptReallocElemsEx -- + * + * Attempts to allocate (oldPtr == NULL) or reallocate memory of the + * requested size plus some more for future growth. The amount of + * reallocation is adjusted depending on on failure. + * + * + * Results: + * Pointer to allocated memory block which is at least as large + * as the requested size or NULL if allocation failed. + * + *------------------------------------------------------------------------ + */ +void * +TclAttemptReallocElemsEx( + void *oldPtr, /* Pointer to memory block to reallocate or + * NULL to indicate this is a new allocation */ + Tcl_Size elemCount, /* Allocation will store at least these many... */ + Tcl_Size elemSize, /* ...elements of this size */ + Tcl_Size leadSize, /* Additional leading space in bytes */ + Tcl_Size *capacityPtr) /* OUTPUT: Actual capacity is stored + here if non-NULL. Only modified on success */ +{ + void *ptr; + Tcl_Size limit; + Tcl_Size attempt; + + assert(elemCount > 0); + assert(elemSize > 0); + assert(elemSize < TCL_SIZE_MAX); + assert(leadSize > 0); + assert(leadSize < TCL_SIZE_MAX); + + limit = (TCL_SIZE_MAX - leadSize) / elemSize; + if (elemCount > limit) { + return NULL; + } + /* Loop trying for extra space, reducing request each time */ + attempt = TclUpsizeAlloc(0, elemCount, limit); + ptr = NULL; + while (attempt > elemCount) { + if (oldPtr) { + ptr = Tcl_AttemptRealloc(oldPtr, leadSize + attempt * elemSize); + } else { + ptr = Tcl_AttemptAlloc(leadSize + attempt * elemSize); + } + if (ptr) { + break; + } + attempt = TclUpsizeRetry(elemCount, attempt); + } + /* Try exact size as a last resort */ + if (ptr == NULL) { + attempt = elemCount; + if (oldPtr) { + ptr = Tcl_AttemptRealloc(oldPtr, leadSize + attempt * elemSize); + } else { + ptr = Tcl_AttemptAlloc(leadSize + attempt * elemSize); + } + } + if (ptr && capacityPtr) { + *capacityPtr = attempt; + } + return ptr; +} + +/* + *------------------------------------------------------------------------ + * + * TclReallocElemsEx -- + * + * See TclAttemptReallocElemsEx. This function differs in that it panics + * on failure. + * + * Results: + * Non-NULL pointer to allocated memory block. + * + * Side effects: + * Panics if memory of at least the requested size could not be + * allocated. + * + *------------------------------------------------------------------------ + */ +void * +TclReallocElemsEx( + void *oldPtr, /* Pointer to memory block to reallocate */ + Tcl_Size elemCount, /* Allocation will store at least these many... */ + Tcl_Size elemSize, /* ...elements of this size */ + Tcl_Size leadSize, /* Additional leading space in bytes */ + Tcl_Size *capacityPtr) /* OUTPUT: Actual capacity is stored + here if non-NULL. Only modified on success */ +{ + void *ptr = TclAttemptReallocElemsEx( + oldPtr, elemCount, elemSize, leadSize, capacityPtr); + if (ptr == NULL) { + Tcl_Panic("Failed to reallocate %" TCL_SIZE_MODIFIER + "d elements of size %" TCL_SIZE_MODIFIER "d bytes.", + elemCount, + elemSize); + } + return ptr; +} + +/* *--------------------------------------------------------------------------- * * TclFinalizeMemorySubsystem -- |
