diff --git a/builds/posix/prefix.hpux_aCC b/builds/posix/prefix.hpux_aCC index 36ef1488d3..9a1d4e5f4e 100644 --- a/builds/posix/prefix.hpux_aCC +++ b/builds/posix/prefix.hpux_aCC @@ -21,7 +21,7 @@ # Notes: # Firebird requires the HP-UX Atomic APIs ("AtomicAPI" bundle), released as an -# optional Software Pack (SPK) for HP-UX 11i v2 or v3. +# optional Software Pack (SPK) for HP-UX 11i v2 or v3. # Before attempting the HPUX build, you must export necessary # CFLAGS and CXXFLAGS to be picked up by the configure process and @@ -60,15 +60,12 @@ COMMON_FLAGS= -DHP11 -DHPUX -D_XOPEN_SOURCE_EXTENDED -D_HP_ATOMIC_INLINE \ # Flags specific to production or debug build... # -z, disallow dereferencing of null pointers at runtime -# -DLIBC_CALLS_NEW, Firebird macro, used when C++ runtime can call -# redefined by us operator new before initialization of global variables. -# Required on IA-64, but evidently only by debug build!? ifeq ($(shell uname -m),ia64) # ...for IA-64 PROD_FLAGS= +O2 +Onolimit +Ofltacc=strict +Ofenvaccess \ $(COMMON_FLAGS) -DEV_FLAGS= -g -z -DLIBC_CALLS_NEW \ +DEV_FLAGS= -g -z \ $(COMMON_FLAGS) else # ...for PA-RISC diff --git a/extern/re2/re2/re2.cc b/extern/re2/re2/re2.cc index 85ba1f4ecd..d303f0c818 100644 --- a/extern/re2/re2/re2.cc +++ b/extern/re2/re2/re2.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -60,9 +61,9 @@ RE2::Options::Options(RE2::CannedOptions opt) // static empty objects for use as const references. // To avoid global constructors, allocated in RE2::Init(). -static const std::string* empty_string; -static const std::map* empty_named_groups; -static const std::map* empty_group_names; +static std::unique_ptr empty_string; +static std::unique_ptr> empty_named_groups; +static std::unique_ptr> empty_group_names; // Converts from Regexp error code to RE2 error code. // Maybe some day they will diverge. In any event, this @@ -173,15 +174,15 @@ int RE2::Options::ParseFlags() const { void RE2::Init(const StringPiece& pattern, const Options& options) { static std::once_flag empty_once; std::call_once(empty_once, []() { - empty_string = new std::string; - empty_named_groups = new std::map; - empty_group_names = new std::map; + empty_string.reset(new std::string); + empty_named_groups.reset(new std::map); + empty_group_names.reset(new std::map); }); pattern_.assign(pattern.data(), pattern.size()); options_.Copy(options); entire_regexp_ = NULL; - error_ = empty_string; + error_ = empty_string.get(); error_code_ = NoError; error_arg_.clear(); prefix_.clear(); @@ -267,11 +268,11 @@ RE2::~RE2() { entire_regexp_->Decref(); delete prog_; delete rprog_; - if (error_ != empty_string) + if (error_ != empty_string.get()) delete error_; - if (named_groups_ != NULL && named_groups_ != empty_named_groups) + if (named_groups_ != NULL && named_groups_ != empty_named_groups.get()) delete named_groups_; - if (group_names_ != NULL && group_names_ != empty_group_names) + if (group_names_ != NULL && group_names_ != empty_group_names.get()) delete group_names_; } @@ -352,7 +353,7 @@ const std::map& RE2::NamedCapturingGroups() const { if (re->suffix_regexp_ != NULL) re->named_groups_ = re->suffix_regexp_->NamedCaptures(); if (re->named_groups_ == NULL) - re->named_groups_ = empty_named_groups; + re->named_groups_ = empty_named_groups.get(); }, this); return *named_groups_; } @@ -363,7 +364,7 @@ const std::map& RE2::CapturingGroupNames() const { if (re->suffix_regexp_ != NULL) re->group_names_ = re->suffix_regexp_->CaptureNames(); if (re->group_names_ == NULL) - re->group_names_ = empty_group_names; + re->group_names_ = empty_group_names.get(); }, this); return *group_names_; } diff --git a/src/auth/SecureRemotePassword/Message.h b/src/auth/SecureRemotePassword/Message.h index 3f026b4a88..2d99447311 100644 --- a/src/auth/SecureRemotePassword/Message.h +++ b/src/auth/SecureRemotePassword/Message.h @@ -234,7 +234,7 @@ private: { unsigned l = aMeta->getMessageLength(&statusWrapper); check(&statusWrapper); - buffer = new unsigned char[l]; + buffer = FB_NEW unsigned char[l]; } public: @@ -336,7 +336,7 @@ public: if (!charBuffer) { - charBuffer = new char[size + 1]; + charBuffer = FB_NEW char[size + 1]; } getStrValue(charBuffer); return charBuffer; diff --git a/src/common/classes/alloc.cpp b/src/common/classes/alloc.cpp index 5fe2f5ce01..86c5a64ec9 100644 --- a/src/common/classes/alloc.cpp +++ b/src/common/classes/alloc.cpp @@ -40,12 +40,22 @@ #include "firebird.h" #include "../common/classes/alloc.h" -#ifndef WIN_NT +#ifdef WIN_NT + +#include + +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH +#endif + +#else + #include #include #include #include #include + #endif #include "../common/classes/fb_tls.h" @@ -68,25 +78,10 @@ #define VALGRIND_FIX_IT // overrides suspicious valgrind behavior #endif // USE_VALGRIND -void* operator new(size_t s ALLOC_PARAMS) -{ - return MemoryPool::globalAlloc(s ALLOC_PASS_ARGS); -} -void* operator new[](size_t s ALLOC_PARAMS) -{ - return MemoryPool::globalAlloc(s ALLOC_PASS_ARGS); -} -void operator delete(void* mem ALLOC_PARAMS) noexcept -{ - MemoryPool::globalFree(mem); -} -void operator delete[](void* mem ALLOC_PARAMS) noexcept -{ - MemoryPool::globalFree(mem); -} - namespace { +///#define MEM_DEBUG_EXTERNAL + /*** emergency debugging stuff static const char* lastFileName; static int lastLine; @@ -147,7 +142,14 @@ typedef Firebird::AtomicCounter::counter_type StatInt; const int MAP_CACHE_SIZE = 16; // == 1 MB const size_t DEFAULT_ALLOCATION = 65536; -Firebird::Vector extents_cache; +struct ExtentsCache // C++ aggregate - members are statically initialized to zeros +{ + unsigned count; + void* data[MAP_CACHE_SIZE]; +}; + +ExtentsCache defaultExtentsCache; +ExtentsCache externalExtentsCache; #ifndef WIN_NT struct FailedBlock @@ -191,7 +193,7 @@ inline size_t get_map_page_size() static volatile size_t map_page_size = 0; if (!map_page_size) { - Firebird::MutexLockGuard guard(*cache_mutex, "get_map_page_size"); + Firebird::MutexLockGuard guard(cache_mutex, "get_map_page_size"); if (!map_page_size) map_page_size = get_page_size(); } @@ -1731,10 +1733,22 @@ private: public: static MemPool* defaultMemPool; - MemPool(); - MemPool(MemPool& parent, MemoryStats& stats); + MemPool(MemoryStats& stats, ExtentsCache* extentsCache); + MemPool(MemPool& parent, MemoryStats& stats, ExtentsCache* extentsCache); virtual ~MemPool(void); +public: + static inline constexpr MemPool* getPoolFromPointer(void* ptr) noexcept + { + if (ptr) + { + auto block = (MemBlock*) ((UCHAR*) ptr - offsetof(MemBlock, body)); + return block->pool; + } + + return nullptr; + } + private: static const size_t minAllocation = 65536; static const size_t roundingSize = ALLOC_ALIGNMENT; @@ -1749,12 +1763,10 @@ private: int blocksActive; bool pool_destroying, parent_redirect; - // Statistics group for the pool - MemoryStats* stats; - // Parent pool if present - MemPool* parent; - // Memory used - AtomicCounter used_memory, mapped_memory; + MemoryStats* stats; // Statistics group for the pool + MemPool* parent; // Parent pool if present + ExtentsCache* extentsCache; + AtomicCounter used_memory, mapped_memory; // Memory used private: @@ -1810,7 +1822,7 @@ private: virtual void memoryIsExhausted(void); void* allocRaw(size_t length); static void releaseMemory(void* block, bool flagExtent) noexcept; - static void releaseRaw(bool destroying, void *block, size_t size, bool use_cache = true) noexcept; + static void releaseRaw(bool destroying, void *block, size_t size, ExtentsCache* extentsCache) noexcept; void* getExtent(size_t from, size_t& to); public: @@ -1843,23 +1855,36 @@ public: void setStatsGroup(MemoryStats& stats) noexcept; // Initialize and finalize global memory pool - static MemPool* init() + static MemPool* initDefaultPool() { fb_assert(!defaultMemPool); - static char mpBuffer[sizeof(MemPool) + ALLOC_ALIGNMENT]; - defaultMemPool = new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) mpBuffer)) MemPool(); + alignas(alignof(MemPool)) static char mpBuffer[sizeof(MemPool)]; + defaultMemPool = new(mpBuffer) MemPool(*MemoryPool::default_stats_group, &defaultExtentsCache); return defaultMemPool; } - static void cleanup() + static void cleanupDefaultPool() { defaultMemPool->~MemPool(); defaultMemPool = NULL; - while (extents_cache.getCount()) - releaseRaw(true, extents_cache.pop(), DEFAULT_ALLOCATION, false); + while (defaultExtentsCache.count) + releaseRaw(true, defaultExtentsCache.data[--defaultExtentsCache.count], DEFAULT_ALLOCATION, nullptr); + cleanupFailedList(); + } + + static void cleanupExternalPool() + { + while (externalExtentsCache.count) + releaseRaw(true, externalExtentsCache.data[--externalExtentsCache.count], DEFAULT_ALLOCATION, nullptr); + + cleanupFailedList(); + } + + static void cleanupFailedList() + { #ifndef WIN_NT unsigned oldCount = 0; @@ -1880,7 +1905,7 @@ public: ++newCount; FailedBlock* fb = oldList; SemiDoubleLink::pop(oldList); - releaseRaw(true, fb, fb->blockSize, false); + releaseRaw(true, fb, fb->blockSize, nullptr); } if (newCount == oldCount) @@ -1889,7 +1914,6 @@ public: oldCount = newCount; } #endif // WIN_NT - } // Statistics @@ -2012,28 +2036,28 @@ GlobalPtr forceCreationOfDefaultMemoryPool; MemoryPool* MemoryPool::defaultMemoryManager = NULL; MemoryStats* MemoryPool::default_stats_group = NULL; +MemoryPool* MemoryPool::externalMemoryManager = NULL; MemPool* MemPool::defaultMemPool = NULL; // Initialize process memory pool (called from InstanceControl). -void MemoryPool::init() +void MemoryPool::initDefaultPool() { - static char mtxBuffer[sizeof(Mutex) + ALLOC_ALIGNMENT]; - cache_mutex = new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) mtxBuffer)) Mutex; + alignas(alignof(Mutex)) static char mtxBuffer[sizeof(Mutex)]; + cache_mutex = new(mtxBuffer) Mutex; - static char msBuffer[sizeof(MemoryStats) + ALLOC_ALIGNMENT]; - default_stats_group = - new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) msBuffer)) MemoryStats; + alignas(alignof(MemoryStats)) static char msBuffer[sizeof(MemoryStats)]; + default_stats_group = new(msBuffer) MemoryStats; - static char mpBuffer[sizeof(MemoryPool) + ALLOC_ALIGNMENT]; - defaultMemoryManager = new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) mpBuffer)) MemoryPool(MemPool::init()); + alignas(alignof(MemoryPool)) static char mpBuffer[sizeof(MemoryPool)]; + defaultMemoryManager = new(mpBuffer) MemoryPool(MemPool::initDefaultPool()); } // Should be last routine, called by InstanceControl, // being therefore the very last routine in firebird module. -void MemoryPool::cleanup() +void MemoryPool::cleanupDefaultPool() { #ifdef VALGRIND_FIX_IT VALGRIND_DISCARD( @@ -2047,7 +2071,7 @@ void MemoryPool::cleanup() if (defaultMemoryManager) { //defaultMemoryManager->~MemoryPool(); - MemPool::cleanup(); + MemPool::cleanupDefaultPool(); defaultMemoryManager = NULL; } @@ -2065,15 +2089,23 @@ void MemoryPool::cleanup() } -MemPool::MemPool() - : pool_destroying(false), parent_redirect(false), stats(MemoryPool::default_stats_group), parent(NULL) +MemPool::MemPool(MemoryStats& s, ExtentsCache* cache) + : pool_destroying(false), + parent_redirect(false), + stats(&s), + parent(NULL), + extentsCache(cache) { fb_assert(offsetof(MemBlock, body) == MEM_ALIGN(offsetof(MemBlock, body))); initialize(); } -MemPool::MemPool(MemPool& p, MemoryStats& s) - : pool_destroying(false), parent_redirect(true), stats(&s), parent(&p) +MemPool::MemPool(MemPool& p, MemoryStats& s, ExtentsCache* cache) + : pool_destroying(false), + parent_redirect(true), + stats(&s), + parent(&p), + extentsCache(cache) { initialize(); } @@ -2133,7 +2165,7 @@ MemPool::~MemPool(void) { MemBigHunk* hunk = bigHunks; bigHunks = hunk->next; - releaseRaw(pool_destroying, hunk, hunk->length); + releaseRaw(pool_destroying, hunk, hunk->length, extentsCache); } if (parent) @@ -2210,7 +2242,7 @@ MemoryPool* MemoryPool::createPool(MemoryPool* parentPool, MemoryStats& stats) if (!parentPool) parentPool = getDefaultMemoryPool(); - MemPool* p = FB_NEW_POOL(*parentPool) MemPool(*(parentPool->pool), stats); + MemPool* p = FB_NEW_POOL(*parentPool) MemPool(*(parentPool->pool), stats, &defaultExtentsCache); return FB_NEW_POOL(*parentPool) MemoryPool(p); } @@ -2461,7 +2493,7 @@ void MemPool::releaseBlock(MemBlock* block, bool decrUsage) noexcept MemBigHunk* hunk = (MemBigHunk*)(((UCHAR*)block) - MemBigHunk::hdrSize()); SemiDoubleLink::remove(hunk); decrement_mapping(FB_ALIGN(hunk->length, get_map_page_size())); - releaseRaw(pool_destroying, hunk, hunk->length, false); + releaseRaw(pool_destroying, hunk, hunk->length, nullptr); } void MemPool::memoryIsExhausted(void) @@ -2474,12 +2506,12 @@ void* MemPool::allocRaw(size_t size) #ifndef USE_VALGRIND if (size == DEFAULT_ALLOCATION) { - MutexLockGuard guard(*cache_mutex, "MemPool::allocRaw"); - if (extents_cache.hasData()) + MutexLockGuard guard(cache_mutex, "MemPool::allocRaw"); + if (extentsCache->count) { // Use most recently used object to encourage caching increment_mapping(size); - return extents_cache.pop(); + return extentsCache->data[--extentsCache->count]; } } #endif @@ -2497,7 +2529,7 @@ void* MemPool::allocRaw(size_t size) void* result = NULL; if (failedList) { - MutexLockGuard guard(*cache_mutex, "MemPool::allocRaw"); + MutexLockGuard guard(cache_mutex, "MemPool::allocRaw"); for (FailedBlock* fb = failedList; fb; fb = fb->next) { if (fb->blockSize == size) @@ -2568,20 +2600,20 @@ void MemPool::releaseExtent(bool destroying, void* block, size_t size, MemPool* { if (pool) pool->decrement_mapping(size); - releaseRaw(true, block, size, pool); + releaseRaw(true, block, size, (pool ? pool->extentsCache : nullptr)); } } -void MemPool::releaseRaw(bool destroying, void* block, size_t size, bool use_cache) noexcept +void MemPool::releaseRaw(bool destroying, void* block, size_t size, ExtentsCache* extentsCache) noexcept { #ifndef USE_VALGRIND - if (use_cache && (size == DEFAULT_ALLOCATION)) + if (extentsCache && (size == DEFAULT_ALLOCATION)) { - MutexLockGuard guard(*cache_mutex, "MemPool::releaseRaw"); - if (extents_cache.getCount() < extents_cache.getCapacity()) + MutexLockGuard guard(cache_mutex, "MemPool::releaseRaw"); + if (extentsCache->count < MAP_CACHE_SIZE) { - extents_cache.push(block); + extentsCache->data[extentsCache->count++] = block; return; } } @@ -2599,7 +2631,7 @@ void MemPool::releaseRaw(bool destroying, void* block, size_t size, bool use_cac if (destroying) { // Synchronize delayed free queue using extents mutex - MutexLockGuard guard(*cache_mutex, "MemPool::releaseRaw"); + MutexLockGuard guard(cache_mutex, "MemPool::releaseRaw"); // Extend circular buffer if possible if (delayedExtentCount < FB_NELEM(delayedExtents)) @@ -2656,7 +2688,7 @@ void MemPool::releaseRaw(bool destroying, void* block, size_t size, bool use_cac FailedBlock* failed = (FailedBlock*) block; failed->blockSize = size; - MutexLockGuard guard(*cache_mutex, "MemPool::releaseRaw"); + MutexLockGuard guard(cache_mutex, "MemPool::releaseRaw"); SemiDoubleLink::push(&failedList, failed); return; @@ -2817,25 +2849,6 @@ MemoryPool& AutoStorage::getAutoMemoryPool() return *p; } -#ifdef LIBC_CALLS_NEW -void* MemoryPool::globalAlloc(size_t s ALLOC_PARAMS) -{ - if (!defaultMemoryManager) - { - // this will do all required init, including processMemoryPool creation - static Firebird::InstanceControl dummy; - fb_assert(defaultMemoryManager); - } - - return defaultMemoryManager->allocate(s ALLOC_PASS_ARGS); -} -#endif // LIBC_CALLS_NEW - -void MemoryPool::globalFree(void* block) noexcept -{ - MemPool::globalFree(block); -} - void* MemoryPool::allocate(size_t size ALLOC_PARAMS) { return pool->allocate(size ALLOC_PASS_ARGS); @@ -2924,6 +2937,159 @@ void MemoryPool::unregisterFinalizer(Finalizer*& finalizer) } +class ExternalMemoryHandler +{ +friend class MemoryPool; + +private: + struct Objects + { + MemoryStats memoryStats; + MemPool memPool{memoryStats, &externalExtentsCache}; + MemoryPool memoryPool{&memPool}; + }; + + static ExternalMemoryHandler* instance; + +public: + enum class State : UCHAR + { + ALIVE, + DEAD, + DYING + }; + +public: + ExternalMemoryHandler() + { + Mutex::initMutexes(); + +#ifdef MEM_DEBUG_EXTERNAL + printf("ExternalMemoryHandler::ExternalMemoryHandler()\n"); +#endif + + instance = this; + + new(objectsBuffer) Objects(); + + MemoryPool::externalMemoryManager = &objects().memoryPool; + + atexit([] { + const auto currentUsage = instance->objects().memoryStats.getCurrentUsage(); + +#ifdef MEM_DEBUG_EXTERNAL + printf("ExternalMemoryHandler atexit: %" SIZEFORMAT "\n", currentUsage); +#endif + + ExternalMemoryHandler::printContents("atexit"); + + if (currentUsage == 0) + ExternalMemoryHandler::free(); + else + instance->state = State::DYING; + }); + } + + void revive() + { +#ifdef MEM_DEBUG_EXTERNAL + printf("ExternalMemoryHandler::revive()\n"); +#endif + new(this) ExternalMemoryHandler(); + } + + static void printContents(const char* moment) + { +#if defined(MEM_DEBUG) && defined(DEBUG_GDS_ALLOC) + if (!MemoryPool::externalMemoryManager) + return; + + static bool alreadyPrinted = false; + Firebird::AutoPtr file; + + { // scope + char name[PATH_MAX]; + + if (os_utils::getCurrentModulePath(name, sizeof(name))) + strncat(name, ".memdebug.external.log", sizeof(name) - 1); + else + strcpy(name, "memdebug.external.log"); + + file = os_utils::fopen(name, alreadyPrinted ? "at" : "w+t"); + } + + if (file) + { + fprintf(file, "********* Moment: %s\n", moment); + + MemoryPool::externalMemoryManager->print_contents(file, + Firebird::MemoryPool::PRINT_USED_ONLY | Firebird::MemoryPool::PRINT_RECURSIVE); + file = NULL; + alreadyPrinted = true; + } +#endif + } + + static void free() + { + if (instance->state != State::DEAD) + { + instance->state = State::DEAD; + instance->objects().~Objects(); + instance->~ExternalMemoryHandler(); + instance = nullptr; + + MemPool::cleanupExternalPool(); + } + + MemoryPool::externalMemoryManager = nullptr; + } + + inline Objects& objects() + { + return *(Objects*) objectsBuffer; + } + + alignas(alignof(Objects)) char objectsBuffer[sizeof(Objects)]; + State state = State::ALIVE; +}; + +ExternalMemoryHandler* ExternalMemoryHandler::instance = nullptr; + +void initExternalMemoryPool() +{ + static ExternalMemoryHandler handler; + + if (handler.state == ExternalMemoryHandler::State::DEAD) + handler.revive(); +} + + +void MemoryPool::globalFree(void* block) noexcept +{ + auto pool = MemPool::getPoolFromPointer(block); + + MemPool::globalFree(block); + + if (auto externalMemoryHandler = ExternalMemoryHandler::instance; + externalMemoryHandler && + externalMemoryHandler->state == ExternalMemoryHandler::State::DYING && + pool == &externalMemoryHandler->objects().memPool) + { + const auto currentUsage = externalMemoryHandler->objects().memoryStats.getCurrentUsage(); + +#ifdef MEM_DEBUG_EXTERNAL + printf("MemoryPool::globalFree() - dying ExternalMemoryHandler: %" SIZEFORMAT "\n", currentUsage); +#endif + + ExternalMemoryHandler::printContents("globalFree"); + + if (currentUsage == 0) + ExternalMemoryHandler::free(); + } +} + + #if defined(DEV_BUILD) void AutoStorage::ProbeStack() const { @@ -2949,14 +3115,15 @@ void AutoStorage::ProbeStack() const // Global operator "delete" is always redefined by firebird, // in a case when we actually need "new" only with file/line information // this version should be also present as a pair for "delete". -#ifdef DEBUG_GDS_ALLOC + void* operator new(size_t s) { - return MemoryPool::globalAlloc(s ALLOC_ARGS); + return getExternalMemoryPool()->allocate(s ALLOC_ARGS); } + void* operator new[](size_t s) { - return MemoryPool::globalAlloc(s ALLOC_ARGS); + return getExternalMemoryPool()->allocate(s ALLOC_ARGS); } void operator delete(void* mem) noexcept @@ -2968,5 +3135,3 @@ void operator delete[](void* mem) noexcept { MemoryPool::globalFree(mem); } - -#endif // DEBUG_GDS_ALLOC diff --git a/src/common/classes/alloc.h b/src/common/classes/alloc.h index 44d9e0ea46..cf52648855 100644 --- a/src/common/classes/alloc.h +++ b/src/common/classes/alloc.h @@ -59,11 +59,11 @@ #include #ifdef DEBUG_GDS_ALLOC -#define FB_NEW new(__FILE__, __LINE__) +#define FB_NEW new(*getDefaultMemoryPool(), __FILE__, __LINE__) #define FB_NEW_POOL(pool) new(pool, __FILE__, __LINE__) #define FB_NEW_RPT(pool, count) new(pool, count, __FILE__, __LINE__) #else // DEBUG_GDS_ALLOC -#define FB_NEW new +#define FB_NEW new(*getDefaultMemoryPool()) #define FB_NEW_POOL(pool) new(pool) #define FB_NEW_RPT(pool, count) new(pool, count) #endif // DEBUG_GDS_ALLOC @@ -159,6 +159,8 @@ private: class MemoryPool { +friend class ExternalMemoryHandler; + private: MemPool* pool; @@ -174,6 +176,7 @@ public: enum RecommendedBufferSize { MAX_MEDIUM_BLOCK_SIZE = 64384 }; // MediumLimits::TOP_LIMIT - 128 static MemoryPool* defaultMemoryManager; + static MemoryPool* externalMemoryManager; public: // Create memory pool instance @@ -193,14 +196,10 @@ public: void* calloc(size_t size ALLOC_PARAMS); -#ifdef LIBC_CALLS_NEW - static void* globalAlloc(size_t s ALLOC_PARAMS); -#else static void* globalAlloc(size_t s ALLOC_PARAMS) { return defaultMemoryManager->allocate(s ALLOC_PASS_ARGS); } -#endif // LIBC_CALLS_NEW void* allocate(size_t size ALLOC_PARAMS); @@ -218,8 +217,8 @@ public: void setStatsGroup(MemoryStats& stats) noexcept; // Initialize and finalize global memory pool - static void init(); - static void cleanup(); + static void initDefaultPool(); + static void cleanupDefaultPool(); // Initialize context pool static void contextPoolInit(); @@ -282,6 +281,8 @@ private: friend class MemPool; }; +void initExternalMemoryPool(); + } // namespace Firebird static inline Firebird::MemoryPool* getDefaultMemoryPool() noexcept @@ -290,6 +291,16 @@ static inline Firebird::MemoryPool* getDefaultMemoryPool() noexcept return Firebird::MemoryPool::defaultMemoryManager; } +static inline Firebird::MemoryPool* getExternalMemoryPool() noexcept +{ + using namespace Firebird; + + if (!MemoryPool::externalMemoryManager) + initExternalMemoryPool(); + + return MemoryPool::externalMemoryManager; +} + namespace Firebird { // Class intended to manage execution context pool stack @@ -341,16 +352,12 @@ private: using Firebird::MemoryPool; // operators new and delete -extern void* operator new(size_t s ALLOC_PARAMS); -extern void* operator new[](size_t s ALLOC_PARAMS); -extern void operator delete(void* mem ALLOC_PARAMS) noexcept; -extern void operator delete[](void* mem ALLOC_PARAMS) noexcept; - inline void* operator new(size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS) { return pool.allocate(s ALLOC_PASS_ARGS); } + inline void* operator new[](size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS) { return pool.allocate(s ALLOC_PASS_ARGS); @@ -360,6 +367,7 @@ inline void operator delete(void* mem, Firebird::MemoryPool& pool ALLOC_PARAMS) { MemoryPool::globalFree(mem); } + inline void operator delete[](void* mem, Firebird::MemoryPool& pool ALLOC_PARAMS) noexcept { MemoryPool::globalFree(mem); @@ -370,6 +378,7 @@ inline void operator delete(void* mem, std::size_t s ALLOC_PARAMS) noexcept { MemoryPool::globalFree(mem); } + inline void operator delete[](void* mem, std::size_t s ALLOC_PARAMS) noexcept { MemoryPool::globalFree(mem); @@ -390,16 +399,6 @@ namespace Firebird class GlobalStorage { public: - void* operator new(size_t size ALLOC_PARAMS) - { - return getDefaultMemoryPool()->allocate(size ALLOC_PASS_ARGS); - } - - void operator delete(void* mem) - { - getDefaultMemoryPool()->deallocate(mem); - } - MemoryPool& getPool() const { return *getDefaultMemoryPool(); diff --git a/src/common/classes/init.cpp b/src/common/classes/init.cpp index 27080dee41..fa1c998395 100644 --- a/src/common/classes/init.cpp +++ b/src/common/classes/init.cpp @@ -31,12 +31,13 @@ #include "../common/dllinst.h" #include "../common/os/os_utils.h" -#ifdef HAVE_DLADDR -#ifndef _GNU_SOURCE -#define _GNU_SOURCE +#ifdef WIN_NT +#include + +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH +#endif #endif -#include -#endif // HAVE_DLADDR // Setting this define helps (with AV at exit time) detect globals // with destructors, declared not using InstanceControl. @@ -96,36 +97,14 @@ namespace Firebird::AutoPtr file; { // scope - Firebird::PathName name = "memdebug.log"; -#ifdef HAVE_DLADDR - Dl_info path; - if (dladdr((void*) &allClean, &path)) - { - name = path.dli_fname; - name += ".memdebug.log"; - } - else - { - fprintf(stderr, "dladdr: %s\n", dlerror()); - } -#elif defined(WIN_NT) - HMODULE hmod = 0; - GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - (LPCTSTR) &allClean, - &hmod); + char name[PATH_MAX]; - if (hmod) - { - char moduleName[MAX_PATH]; - DWORD len = GetModuleFileName(hmod, moduleName, MAX_PATH); - if (len < MAX_PATH) - { - name = moduleName; - name += ".memdebug.log"; - } - } -#endif // HAVE_DLADDR - file = os_utils::fopen(name.c_str(), "w+t"); + if (os_utils::getCurrentModulePath(name, sizeof(name))) + strncat(name, ".memdebug.log", sizeof(name) - 1); + else + strcpy(name, "memdebug.log"); + + file = os_utils::fopen(name, "w+t"); } #endif // DEBUG_GDS_ALLOC @@ -154,7 +133,7 @@ namespace file = NULL; } #endif - Firebird::MemoryPool::cleanup(); + Firebird::MemoryPool::cleanupDefaultPool(); } catch (...) { @@ -193,7 +172,7 @@ namespace } Firebird::Mutex::initMutexes(); - Firebird::MemoryPool::init(); + Firebird::MemoryPool::initDefaultPool(); Firebird::StaticMutex::create(); #ifdef DEBUG_INIT diff --git a/src/common/classes/init.h b/src/common/classes/init.h index 7bb2952cad..beb07d52d8 100644 --- a/src/common/classes/init.h +++ b/src/common/classes/init.h @@ -304,12 +304,12 @@ template class StaticInstanceAllocator { private: - char buf[sizeof(T) + FB_ALIGNMENT]; + alignas(alignof(T)) char buf[sizeof(T)]; public: T* create() { - return new((void*) FB_ALIGN(buf, FB_ALIGNMENT)) T(); + return new(buf) T(); } static void destroy(T*) diff --git a/src/common/classes/locks.cpp b/src/common/classes/locks.cpp index daf607d6b1..1f4f482d0d 100644 --- a/src/common/classes/locks.cpp +++ b/src/common/classes/locks.cpp @@ -33,6 +33,7 @@ #include "../../common/classes/locks.h" #include "../../common/ThreadStart.h" +#include namespace Firebird { @@ -50,15 +51,18 @@ pthread_mutexattr_t Mutex::attr; void Mutex::initMutexes() { - // Throw exceptions on errors, but they will not be processed in init - // (first constructor). Better logging facilities are required here. - int rc = pthread_mutexattr_init(&attr); - if (rc < 0) - system_call_failed::raise("pthread_mutexattr_init", rc); + static std::once_flag onceFlag; + std::call_once(onceFlag, [] { + // Throw exceptions on errors, but they will not be processed in init + // (first constructor). Better logging facilities are required here. + int rc = pthread_mutexattr_init(&attr); + if (rc < 0) + system_call_failed::raise("pthread_mutexattr_init", rc); - rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - if (rc < 0) - system_call_failed::raise("pthread_mutexattr_settype", rc); + rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + if (rc < 0) + system_call_failed::raise("pthread_mutexattr_settype", rc); + }); } #endif diff --git a/src/common/classes/locks.h b/src/common/classes/locks.h index 7baae6abc0..cda84ae1e4 100644 --- a/src/common/classes/locks.h +++ b/src/common/classes/locks.h @@ -331,6 +331,13 @@ public: lock->enter(aReason); } + RaiiLockGuard(M* aLock, const char* aReason) + : lock(aLock) + { + if (lock) + lock->enter(aReason); + } + ~RaiiLockGuard() { try diff --git a/src/common/os/os_utils.h b/src/common/os/os_utils.h index 55cc996aa3..3288e1e971 100644 --- a/src/common/os/os_utils.h +++ b/src/common/os/os_utils.h @@ -81,6 +81,8 @@ namespace os_utils bool isIPv6supported(); + bool getCurrentModulePath(char* buffer, size_t bufferSize); + // force descriptor to have O_CLOEXEC set int open(const char* pathname, int flags, mode_t mode = DEFAULT_OPEN_MODE); void setCloseOnExec(int fd); // posix only diff --git a/src/common/os/posix/os_utils.cpp b/src/common/os/posix/os_utils.cpp index a23a3dedca..3c19ce28b5 100644 --- a/src/common/os/posix/os_utils.cpp +++ b/src/common/os/posix/os_utils.cpp @@ -43,6 +43,14 @@ #ifdef HAVE_SYS_STAT_H #include #endif + +#ifdef HAVE_DLADDR +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#endif // HAVE_DLADDR + #ifdef HAVE_FCNTL_H #include #endif @@ -335,6 +343,21 @@ bool isIPv6supported() #endif } +bool getCurrentModulePath(char* buffer, size_t bufferSize) +{ +#ifdef HAVE_DLADDR + Dl_info path; + + if (dladdr((void*) &getCurrentModulePath, &path)) + { + strncpy(buffer, path.dli_fname, bufferSize); + return true; + } +#endif + + return false; +} + // setting flag is not absolutely required, therefore ignore errors here void setCloseOnExec(int fd) { diff --git a/src/common/os/win32/os_utils.cpp b/src/common/os/win32/os_utils.cpp index 3e2a962105..85d7c1e118 100644 --- a/src/common/os/win32/os_utils.cpp +++ b/src/common/os/win32/os_utils.cpp @@ -380,6 +380,23 @@ bool isIPv6supported() return false; } +bool getCurrentModulePath(char* buffer, size_t bufferSize) +{ + HMODULE hmod = 0; + + GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCTSTR) &getCurrentModulePath, + &hmod); + + if (hmod) + { + GetModuleFileName(hmod, buffer, bufferSize); + return true; + } + + return false; +} + int open(const char* pathname, int flags, mode_t mode) { return ::_open(pathname, flags, mode); diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index ae564eac6e..e8f6557f9d 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -11519,7 +11519,7 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G const MetaName objName(object ? object->second : ""); bool crdb = false; - AutoPtr privileges(new char[MAX(strlen(ALL_PRIVILEGES), strlen(privs ? privs : "")) + 1]); + AutoPtr privileges(FB_NEW char[MAX(strlen(ALL_PRIVILEGES), strlen(privs ? privs : "")) + 1]); strcpy(privileges, privs ? privs : ""); if (strcmp(privileges, "A") == 0) diff --git a/src/yvalve/why.cpp b/src/yvalve/why.cpp index faf5fda103..9d6e68379b 100644 --- a/src/yvalve/why.cpp +++ b/src/yvalve/why.cpp @@ -137,12 +137,8 @@ private: // Fool-proof requested by Alex // Private memory operators to be sure that this class is used in heap only with launcher -#ifdef DEBUG_GDS_ALLOC - void* operator new (size_t s, const char* file, int line) { return MemoryPool::globalAlloc(s, file, line); } - void operator delete (void* mem, const char* file, int line) { MemoryPool::globalFree(mem); } -#else - void* operator new (size_t s) { return MemoryPool::globalAlloc(s); } -#endif + void* operator new (size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS) { return pool.allocate(s ALLOC_PASS_ARGS); } + void operator delete (void* mem, Firebird::MemoryPool& ALLOC_PARAMS) { MemoryPool::globalFree(mem); } void operator delete (void* mem) { MemoryPool::globalFree(mem); } public: