diff --git a/CMakeLists.txt b/CMakeLists.txt index 47def7927..860cdd387 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1415,6 +1415,23 @@ elseif(GNU) target_compile_definitions(libfastfetch PUBLIC PATH_MAX=4096) endif() +if(WIN32) + check_function_exists(_msize HAVE_MSVC_MSIZE) + if(HAVE_MSVC_MSIZE) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_MSVC_MSIZE=1) + endif() +else() + check_function_exists(malloc_usable_size HAVE_MALLOC_USABLE_SIZE) + if(HAVE_MALLOC_USABLE_SIZE) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_MALLOC_USABLE_SIZE=1) + else() + check_function_exists(malloc_size HAVE_MALLOC_SIZE) + if(HAVE_MALLOC_SIZE) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_MALLOC_SIZE=1) + endif() + endif() +endif() + if(FreeBSD OR OpenBSD OR NetBSD) include(CheckStructHasMember) set(CMAKE_REQUIRED_DEFINITIONS "-D_IFI_OQDROPS=1") diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index d66245520..aae3f1710 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -1,4 +1,5 @@ #include "FFstrbuf.h" +#include "util/mallocHelper.h" #include #include @@ -21,11 +22,27 @@ void ffStrbufInitVF(FFstrbuf* strbuf, const char* format, va_list arguments) { assert(format != NULL); - int len = vasprintf(&strbuf->chars, format, arguments); + char* buffer = NULL; + int len = vasprintf(&buffer, format, arguments); assert(len >= 0); - strbuf->allocated = (uint32_t)(len + 1); - strbuf->length = (uint32_t)len; + ffStrbufInitMoveNS(strbuf, (uint32_t)len, buffer); +} + +// Takes ownership of `heapStr`. The caller must not free `heapStr` after calling this +// function; the memory will be managed and freed via the associated FFstrbuf. +void ffStrbufInitMoveNS(FFstrbuf* strbuf, uint32_t length, char* heapStr) +{ + assert(heapStr != NULL); + + strbuf->length = length; + size_t allocSize = ffMallocUsableSize(heapStr); + if (allocSize == 0) + allocSize = length + 1; + else if (allocSize > UINT32_MAX) + allocSize = UINT32_MAX; + strbuf->allocated = (uint32_t) allocSize; + strbuf->chars = heapStr; } void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free) diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 07fa98c61..a4bfcde4c 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -34,6 +34,7 @@ typedef struct FFstrbuf static inline void ffStrbufInit(FFstrbuf* strbuf); void ffStrbufInitA(FFstrbuf* strbuf, uint32_t allocate); void ffStrbufInitVF(FFstrbuf* strbuf, const char* format, va_list arguments); +void ffStrbufInitMoveNS(FFstrbuf* strbuf, uint32_t length, char* heapStr); void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free); void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free); @@ -212,6 +213,11 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateF(const char* format, ...) return strbuf; } +static inline void ffStrbufInitMoveS(FFstrbuf* strbuf, char* heapStr) +{ + ffStrbufInitMoveNS(strbuf, (uint32_t) strlen(heapStr), heapStr); +} + static inline void ffStrbufDestroy(FFstrbuf* strbuf) { extern char* CHAR_NULL_PTR; diff --git a/src/util/mallocHelper.h b/src/util/mallocHelper.h index 8e314841e..eaea5f3da 100644 --- a/src/util/mallocHelper.h +++ b/src/util/mallocHelper.h @@ -3,6 +3,12 @@ #include #include +#if FF_HAVE_MALLOC_USABLE_SIZE || FF_HAVE_MSVC_MSIZE + #include +#elif FF_HAVE_MALLOC_SIZE + #include +#endif + static inline void ffWrapFree(const void* pPtr) { assert(pPtr); @@ -11,3 +17,18 @@ static inline void ffWrapFree(const void* pPtr) } #define FF_AUTO_FREE __attribute__((__cleanup__(ffWrapFree))) + +// ptr MUST be a malloc'ed pointer +static inline size_t ffMallocUsableSize(const void* ptr) +{ + assert(ptr); + #if FF_HAVE_MALLOC_USABLE_SIZE + return malloc_usable_size((void*) ptr); + #elif FF_HAVE_MALLOC_SIZE + return malloc_size((void*) ptr); + #elif FF_HAVE_MSVC_MSIZE + return _msize((void*) ptr); + #else + return 0; // Not supported + #endif +} diff --git a/tests/strbuf.c b/tests/strbuf.c index 496ef4b09..466fb9297 100644 --- a/tests/strbuf.c +++ b/tests/strbuf.c @@ -229,9 +229,18 @@ int main(void) ffStrbufDestroy(&strbuf); + //initMoveS + { + char* heapStr = strdup("1234567890"); + ffStrbufInitMoveS(&strbuf, heapStr); + VERIFY(ffStrbufEqualS(&strbuf, "1234567890")); + VERIFY(strbuf.allocated >= 11); + ffStrbufDestroy(&strbuf); + } + //initF ffStrbufInitF(&strbuf, "%s", "1234567890123456789012345678901"); - VERIFY(strbuf.allocated == 32); + VERIFY(strbuf.allocated >= 32); VERIFY(ffStrbufEqualS(&strbuf, "1234567890123456789012345678901")); //containC