diff options
Diffstat (limited to 'libs/libmdbx')
-rw-r--r-- | libs/libmdbx/src/README.md | 7 | ||||
-rw-r--r-- | libs/libmdbx/src/dll.vcxproj | 50 | ||||
-rw-r--r-- | libs/libmdbx/src/mdbx.h | 2 | ||||
-rw-r--r-- | libs/libmdbx/src/src/bits.h | 10 | ||||
-rw-r--r-- | libs/libmdbx/src/src/lck-posix.c | 14 | ||||
-rw-r--r-- | libs/libmdbx/src/src/lck-windows.c | 62 | ||||
-rw-r--r-- | libs/libmdbx/src/src/mdbx.c | 294 | ||||
-rw-r--r-- | libs/libmdbx/src/src/osal.c | 182 | ||||
-rw-r--r-- | libs/libmdbx/src/src/osal.h | 109 | ||||
-rw-r--r-- | libs/libmdbx/src/src/tools/mdbx_chk.c | 18 | ||||
-rw-r--r-- | libs/libmdbx/src/src/tools/mdbx_chk.vcxproj | 2 | ||||
-rw-r--r-- | libs/libmdbx/src/src/tools/mdbx_copy.vcxproj | 2 | ||||
-rw-r--r-- | libs/libmdbx/src/src/tools/mdbx_dump.c | 7 | ||||
-rw-r--r-- | libs/libmdbx/src/src/tools/mdbx_dump.vcxproj | 2 | ||||
-rw-r--r-- | libs/libmdbx/src/src/tools/mdbx_load.c | 15 | ||||
-rw-r--r-- | libs/libmdbx/src/src/tools/mdbx_load.vcxproj | 2 | ||||
-rw-r--r-- | libs/libmdbx/src/src/tools/mdbx_stat.c | 4 | ||||
-rw-r--r-- | libs/libmdbx/src/src/tools/mdbx_stat.vcxproj | 2 | ||||
-rw-r--r-- | libs/libmdbx/src/src/tools/wingetopt.c | 4 |
19 files changed, 531 insertions, 257 deletions
diff --git a/libs/libmdbx/src/README.md b/libs/libmdbx/src/README.md index 7c07de316e..a2a6ab7ac3 100644 --- a/libs/libmdbx/src/README.md +++ b/libs/libmdbx/src/README.md @@ -32,7 +32,12 @@ libmdbx 6. [Asynchronous lazy data flushing](https://sites.fas.harvard.edu/~cs265/papers/kathuria-2008.pdf) to disk(s); 7. etc... -Don't miss [Java Native Interface](https://github.com/castortech/mdbxjni) by [Castor Technologies](https://castortech.com/). +Don't miss libmdbx for other runtimes. + +| Runtime | GitHub | Author | +| ------------- | ------------- | ------------- | +| JVM | [mdbxjni](https://github.com/castortech/mdbxjni) | [Castor Technologies](https://castortech.com/) | +| .NET | [mdbx.NET](https://github.com/wangjia184/mdbx.NET) | [Jerry Wang](https://github.com/wangjia184) | ----- diff --git a/libs/libmdbx/src/dll.vcxproj b/libs/libmdbx/src/dll.vcxproj index 746de67bd9..812e1e65a8 100644 --- a/libs/libmdbx/src/dll.vcxproj +++ b/libs/libmdbx/src/dll.vcxproj @@ -73,6 +73,7 @@ <TargetName>mdbx</TargetName> <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> <IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</IntDir> + <CustomBuildBeforeTargets>PreLinkEvent</CustomBuildBeforeTargets> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <LinkIncremental>false</LinkIncremental> @@ -80,22 +81,25 @@ <TargetName>mdbx</TargetName> <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> <IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</IntDir> + <CustomBuildBeforeTargets>PreLinkEvent</CustomBuildBeforeTargets> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <LinkIncremental>true</LinkIncremental> <TargetName>mdbx</TargetName> <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> <IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</IntDir> + <CustomBuildBeforeTargets>PreLinkEvent</CustomBuildBeforeTargets> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <LinkIncremental>false</LinkIncremental> <TargetName>mdbx</TargetName> <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> <IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</IntDir> + <CustomBuildBeforeTargets>PreLinkEvent</CustomBuildBeforeTargets> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> - <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBMDBX_EXPORTS;%(PreprocessorDefinitions);MDBX_DEBUG=1</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBMDBX_EXPORTS;MDBX_BUILD_DLL;MDBX_AVOID_CRT;%(PreprocessorDefinitions);MDBX_DEBUG=1</PreprocessorDefinitions> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <WarningLevel>EnableAllWarnings</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> @@ -107,11 +111,18 @@ <TargetMachine>MachineX86</TargetMachine> <GenerateDebugInformation>true</GenerateDebugInformation> <SubSystem>Windows</SubSystem> + <AdditionalDependencies>ntdll.lib;$(IntermediateOutputPath)mdbx_ntdll_extra.lib;kernel32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> </Link> + <CustomBuildStep> + <Message>Generate fake-library mdbx_ntdll_extra.lib for $(PlatformTarget)</Message> + <Outputs>$(IntermediateOutputPath)mdbx_ntdll_extra.lib</Outputs> + <Inputs>$(ProjectDir)src/ntdll.def</Inputs> + <Command>lib.exe /def:%(Inputs) /out:%(Outputs) /machine:$(PlatformTarget)</Command> + </CustomBuildStep> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> - <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBMDBX_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBMDBX_EXPORTS;MDBX_BUILD_DLL;MDBX_AVOID_CRT;%(PreprocessorDefinitions)</PreprocessorDefinitions> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <WarningLevel>EnableAllWarnings</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> @@ -122,6 +133,9 @@ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> <OmitFramePointers>true</OmitFramePointers> <WholeProgramOptimization>true</WholeProgramOptimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <BufferSecurityCheck>false</BufferSecurityCheck> + <AssemblerOutput>All</AssemblerOutput> </ClCompile> <Link> <TargetMachine>MachineX86</TargetMachine> @@ -130,7 +144,15 @@ <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> + <AdditionalDependencies>ntdll.lib;$(IntermediateOutputPath)mdbx_ntdll_extra.lib;kernel32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> </Link> + <CustomBuildStep> + <Message>Generate fake-library mdbx_ntdll_extra.lib for $(PlatformTarget)</Message> + <Outputs>$(IntermediateOutputPath)mdbx_ntdll_extra.lib</Outputs> + <Inputs>$(ProjectDir)src/ntdll.def</Inputs> + <Command>lib.exe /def:%(Inputs) /out:%(Outputs) /machine:$(PlatformTarget)</Command> + </CustomBuildStep> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> @@ -140,15 +162,24 @@ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> <WarningLevel>EnableAllWarnings</WarningLevel> - <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;LIBMDBX_EXPORTS;%(PreprocessorDefinitions);MDBX_DEBUG=1</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;LIBMDBX_EXPORTS;MDBX_BUILD_DLL;MDBX_AVOID_CRT;%(PreprocessorDefinitions);MDBX_DEBUG=1</PreprocessorDefinitions> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <StringPooling>true</StringPooling> <TreatWarningAsError>true</TreatWarningAsError> </ClCompile> + <Link> + <AdditionalDependencies>ntdll.lib;$(IntermediateOutputPath)mdbx_ntdll_extra.lib;kernel32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <CustomBuildStep> + <Message>Generate fake-library mdbx_ntdll_extra.lib for $(PlatformTarget)</Message> + <Outputs>$(IntermediateOutputPath)mdbx_ntdll_extra.lib</Outputs> + <Inputs>$(ProjectDir)src/ntdll.def</Inputs> + <Command>lib.exe /def:%(Inputs) /out:%(Outputs) /machine:$(PlatformTarget)</Command> + </CustomBuildStep> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> - <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;LIBMDBX_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;LIBMDBX_EXPORTS;MDBX_BUILD_DLL;MDBX_AVOID_CRT;%(PreprocessorDefinitions)</PreprocessorDefinitions> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <StringPooling>true</StringPooling> <Optimization>Full</Optimization> @@ -158,10 +189,21 @@ <OmitFramePointers>true</OmitFramePointers> <WholeProgramOptimization>true</WholeProgramOptimization> <WarningLevel>EnableAllWarnings</WarningLevel> + <FunctionLevelLinking>true</FunctionLevelLinking> + <BufferSecurityCheck>false</BufferSecurityCheck> + <AssemblerOutput>All</AssemblerOutput> </ClCompile> <Link> <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> + <AdditionalDependencies>ntdll.lib;$(IntermediateOutputPath)mdbx_ntdll_extra.lib;kernel32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> </Link> + <CustomBuildStep> + <Message>Generate fake-library mdbx_ntdll_extra.lib for $(PlatformTarget)</Message> + <Outputs>$(IntermediateOutputPath)mdbx_ntdll_extra.lib</Outputs> + <Inputs>$(ProjectDir)src/ntdll.def</Inputs> + <Command>lib.exe /def:%(Inputs) /out:%(Outputs) /machine:$(PlatformTarget)</Command> + </CustomBuildStep> </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="src\lck-windows.c" /> diff --git a/libs/libmdbx/src/mdbx.h b/libs/libmdbx/src/mdbx.h index 283f595df6..120d6847e4 100644 --- a/libs/libmdbx/src/mdbx.h +++ b/libs/libmdbx/src/mdbx.h @@ -212,6 +212,7 @@ extern LIBMDBX_API const mdbx_version_info mdbx_version; extern LIBMDBX_API const mdbx_build_info mdbx_build; #if defined(_WIN32) || defined(_WIN64) +#ifndef MDBX_BUILD_DLL /* Dll initialization callback for ability to dynamically load MDBX DLL by * LoadLibrary() on Windows versions before Windows Vista. This function MUST be @@ -227,6 +228,7 @@ extern LIBMDBX_API const mdbx_build_info mdbx_build; void LIBMDBX_API NTAPI mdbx_dll_callback(PVOID module, DWORD reason, PVOID reserved); #endif /* MDBX_CONFIG_MANUAL_TLS_CALLBACK */ +#endif /* MDBX_BUILD_DLL */ #endif /* Windows */ /* The name of the lock file in the DB environment */ diff --git a/libs/libmdbx/src/src/bits.h b/libs/libmdbx/src/src/bits.h index d1c27bc5ab..3d3e392180 100644 --- a/libs/libmdbx/src/src/bits.h +++ b/libs/libmdbx/src/src/bits.h @@ -476,10 +476,10 @@ typedef struct MDBX_lockinfo { (uint16_t)(MDBX_LOCKINFO_WHOLE_SIZE + MDBX_CACHELINE_SIZE - 1)) #define MDBX_DATA_MAGIC ((MDBX_MAGIC << 8) + MDBX_DATA_VERSION) -#define MDBX_DATA_DEBUG ((MDBX_MAGIC << 8) + 255) +#define MDBX_DATA_MAGIC_DEVEL ((MDBX_MAGIC << 8) + 255) #define MDBX_LOCK_MAGIC ((MDBX_MAGIC << 8) + MDBX_LOCK_VERSION) -#define MDBX_LOCK_DEBUG ((MDBX_MAGIC << 8) + 255) +#define MDBX_LOCK_MAGIC_DEVEL ((MDBX_MAGIC << 8) + 255) #ifndef MDBX_ASSUME_MALLOC_OVERHEAD #define MDBX_ASSUME_MALLOC_OVERHEAD (sizeof(void *) * 2u) @@ -870,6 +870,9 @@ void mdbx_panic(const char *fmt, ...) #endif /* NDEBUG */ #endif /* MDBX_DEBUG */ +LIBMDBX_API void mdbx_assert_fail(const MDBX_env *env, const char *msg, + const char *func, int line); + #define mdbx_print(fmt, ...) \ mdbx_debug_log(MDBX_DBG_PRINT, NULL, 0, fmt, ##__VA_ARGS__) @@ -969,6 +972,9 @@ void mdbx_panic(const char *fmt, ...) /* assert(3) variant in transaction context */ #define mdbx_tassert(txn, expr) mdbx_assert((txn)->mt_env, expr) +#undef assert +#define assert(expr) mdbx_assert(NULL, expr) + /*----------------------------------------------------------------------------*/ /* Internal prototypes */ diff --git a/libs/libmdbx/src/src/lck-posix.c b/libs/libmdbx/src/src/lck-posix.c index 0aa9d85078..9743955311 100644 --- a/libs/libmdbx/src/src/lck-posix.c +++ b/libs/libmdbx/src/src/lck-posix.c @@ -126,7 +126,8 @@ int mdbx_rpid_check(MDBX_env *env, mdbx_pid_t pid) { /*---------------------------------------------------------------------------*/ -static int mdbx_mutex_failed(MDBX_env *env, pthread_mutex_t *mutex, int rc); +static int mdbx_mutex_failed(MDBX_env *env, pthread_mutex_t *mutex, + const int rc); int __cold mdbx_lck_init(MDBX_env *env) { pthread_mutexattr_t ma; @@ -297,9 +298,10 @@ int __cold mdbx_lck_seize(MDBX_env *env) { #endif static int __cold mdbx_mutex_failed(MDBX_env *env, pthread_mutex_t *mutex, - int rc) { + const int err) { + int rc = err; #if MDBX_USE_ROBUST - if (rc == EOWNERDEAD) { + if (err == EOWNERDEAD) { /* We own the mutex. Clean up after dead previous owner. */ int rlocked = (env->me_lck && mutex == &env->me_lck->mti_rmutex); @@ -331,10 +333,8 @@ static int __cold mdbx_mutex_failed(MDBX_env *env, pthread_mutex_t *mutex, } #endif /* MDBX_USE_ROBUST */ - mdbx_error("mutex (un)lock failed, %s", mdbx_strerror(rc)); - if (rc != EDEADLK) { + mdbx_error("mutex (un)lock failed, %s", mdbx_strerror(err)); + if (rc != EDEADLK) env->me_flags |= MDBX_FATAL_ERROR; - rc = MDBX_PANIC; - } return rc; } diff --git a/libs/libmdbx/src/src/lck-windows.c b/libs/libmdbx/src/src/lck-windows.c index 7da0755916..c019a6d547 100644 --- a/libs/libmdbx/src/src/lck-windows.c +++ b/libs/libmdbx/src/src/lck-windows.c @@ -26,11 +26,29 @@ static void mdbx_winnt_import(void); +#ifdef MDBX_BUILD_DLL +/* DEBUG/CHECKED builds still require MSVC's CRT for runtime checks. + * + * Therefore we don't define dll's entry point for debug/checked builds by MSVC. + * In this case MSVC's will automatically use DllMainCRTStartup() from CRT + * library, which also automatically call DllMain() from our mdbx.dll + * + * On the other side, for RELEASE builds + * we explicitly define DllMain() as the entry point and don't linking with + * any CRT libraries (IgnoreAllDefaultLibraries = Yes). */ +#if !defined(_MSC_VER) || defined(NDEBUG) +#pragma comment(linker, "/ENTRY:DllMain") +#endif + +BOOL APIENTRY DllMain(HANDLE module, DWORD reason, LPVOID reserved) +#else #if !MDBX_CONFIG_MANUAL_TLS_CALLBACK static #endif /* !MDBX_CONFIG_MANUAL_TLS_CALLBACK */ void NTAPI - mdbx_dll_callback(PVOID module, DWORD reason, PVOID reserved) { + mdbx_dll_callback(PVOID module, DWORD reason, PVOID reserved) +#endif /* MDBX_BUILD_DLL */ +{ (void)reserved; switch (reason) { case DLL_PROCESS_ATTACH: @@ -47,9 +65,12 @@ static mdbx_rthc_thread_dtor(module); break; } +#ifdef MDBX_BUILD_DLL + return TRUE; +#endif } -#if !MDBX_CONFIG_MANUAL_TLS_CALLBACK +#if !defined(MDBX_BUILD_DLL) && !MDBX_CONFIG_MANUAL_TLS_CALLBACK /* *INDENT-OFF* */ /* clang-format off */ #if defined(_MSC_VER) @@ -87,7 +108,7 @@ static #endif /* *INDENT-ON* */ /* clang-format on */ -#endif /* !MDBX_CONFIG_MANUAL_TLS_CALLBACK */ +#endif /* !defined(MDBX_BUILD_DLL) && !MDBX_CONFIG_MANUAL_TLS_CALLBACK */ /*----------------------------------------------------------------------------*/ @@ -191,12 +212,12 @@ static int suspend_and_append(mdbx_handle_array_t **array, const DWORD ThreadId) { const unsigned limit = (*array)->limit; if ((*array)->count == limit) { - void *ptr = realloc((limit > ARRAY_LENGTH((*array)->handles)) - ? *array - : /* don't free initial array on the stack */ NULL, - sizeof(mdbx_handle_array_t) + - sizeof(HANDLE) * - (limit * 2 - ARRAY_LENGTH((*array)->handles))); + void *ptr = mdbx_realloc( + (limit > ARRAY_LENGTH((*array)->handles)) + ? *array + : /* don't free initial array on the stack */ NULL, + sizeof(mdbx_handle_array_t) + + sizeof(HANDLE) * (limit * 2 - ARRAY_LENGTH((*array)->handles))); if (!ptr) return MDBX_ENOMEM; if (limit == ARRAY_LENGTH((*array)->handles)) @@ -205,12 +226,19 @@ static int suspend_and_append(mdbx_handle_array_t **array, (*array)->limit = limit * 2; } - HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, ThreadId); + HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, + FALSE, ThreadId); if (hThread == NULL) return GetLastError(); + if (SuspendThread(hThread) == -1) { + int err = GetLastError(); + DWORD ExitCode; + if (err == /* workaround for Win10 UCRT bug */ ERROR_ACCESS_DENIED || + !GetExitCodeThread(hThread, &ExitCode) || ExitCode != STILL_ACTIVE) + err = MDBX_SUCCESS; CloseHandle(hThread); - return GetLastError(); + return err; } (*array)->handles[(*array)->count++] = hThread; @@ -295,9 +323,15 @@ int mdbx_suspend_threads_before_remap(MDBX_env *env, int mdbx_resume_threads_after_remap(mdbx_handle_array_t *array) { int rc = MDBX_SUCCESS; for (unsigned i = 0; i < array->count; ++i) { - if (ResumeThread(array->handles[i]) == -1) - rc = GetLastError(); - CloseHandle(array->handles[i]); + const HANDLE hThread = array->handles[i]; + if (ResumeThread(hThread) == -1) { + const int err = GetLastError(); + DWORD ExitCode; + if (err != /* workaround for Win10 UCRT bug */ ERROR_ACCESS_DENIED && + GetExitCodeThread(hThread, &ExitCode) && ExitCode == STILL_ACTIVE) + rc = err; + } + CloseHandle(hThread); } return rc; } diff --git a/libs/libmdbx/src/src/mdbx.c b/libs/libmdbx/src/src/mdbx.c index 0d06f1a191..b0111895bf 100644 --- a/libs/libmdbx/src/src/mdbx.c +++ b/libs/libmdbx/src/src/mdbx.c @@ -1,4 +1,4 @@ -/* +/* * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru> * and other libmdbx authors: please see AUTHORS file. * All rights reserved. @@ -40,9 +40,6 @@ /*----------------------------------------------------------------------------*/ /* Internal inlines */ -#undef assert -#define assert(expr) mdbx_assert(NULL, expr) - static __inline bool mdbx_is_power2(size_t x) { return (x & (x - 1)) == 0; } static __inline size_t mdbx_roundup2(size_t value, size_t granularity) { @@ -531,7 +528,7 @@ __cold void mdbx_rthc_global_dtor(void) { rthc_limit = rthc_count = 0; if (rthc_table != rthc_table_static) - free(rthc_table); + mdbx_free(rthc_table); rthc_table = nullptr; mdbx_rthc_unlock(); @@ -560,8 +557,8 @@ __cold int mdbx_rthc_alloc(mdbx_thread_key_t *key, MDBX_reader *begin, rthc_limit); if (rthc_count == rthc_limit) { rthc_entry_t *new_table = - realloc((rthc_table == rthc_table_static) ? nullptr : rthc_table, - sizeof(rthc_entry_t) * rthc_limit * 2); + mdbx_realloc((rthc_table == rthc_table_static) ? nullptr : rthc_table, + sizeof(rthc_entry_t) * rthc_limit * 2); if (new_table == nullptr) { rc = MDBX_ENOMEM; goto bailout; @@ -609,7 +606,7 @@ __cold void mdbx_rthc_remove(const mdbx_thread_key_t key) { if (--rthc_count > 0) rthc_table[i] = rthc_table[rthc_count]; else if (rthc_table != rthc_table_static) { - free(rthc_table); + mdbx_free(rthc_table); rthc_table = rthc_table_static; rthc_limit = RTHC_INITIAL_LIMIT; } @@ -641,7 +638,7 @@ static __inline pgno_t bytes2pnl(const size_t bytes) { static MDBX_PNL mdbx_pnl_alloc(size_t size) { const size_t bytes = pnl2bytes(size); - MDBX_PNL pl = malloc(bytes); + MDBX_PNL pl = mdbx_malloc(bytes); if (likely(pl)) { #if __GLIBC_PREREQ(2, 12) const size_t bytes = malloc_usable_size(pl); @@ -656,7 +653,7 @@ static MDBX_PNL mdbx_pnl_alloc(size_t size) { static void mdbx_pnl_free(MDBX_PNL pl) { if (likely(pl)) - free(pl - 1); + mdbx_free(pl - 1); } /* Shrink the PNL to the default size if it has grown larger */ @@ -668,7 +665,7 @@ static void mdbx_pnl_shrink(MDBX_PNL *ppl) { if (unlikely(MDBX_PNL_ALLOCLEN(*ppl) > MDBX_PNL_INITIAL + MDBX_CACHELINE_SIZE / sizeof(pgno_t))) { const size_t bytes = pnl2bytes(MDBX_PNL_INITIAL); - MDBX_PNL pl = realloc(*ppl - 1, bytes); + MDBX_PNL pl = mdbx_realloc(*ppl - 1, bytes); if (likely(pl)) { #if __GLIBC_PREREQ(2, 12) const size_t bytes = malloc_usable_size(pl); @@ -694,7 +691,7 @@ static int mdbx_pnl_reserve(MDBX_PNL *ppl, const size_t wanna) { ? wanna + wanna - allocated : MDBX_PNL_MAX; const size_t bytes = pnl2bytes(size); - MDBX_PNL pl = realloc(*ppl - 1, bytes); + MDBX_PNL pl = mdbx_realloc(*ppl - 1, bytes); if (likely(pl)) { #if __GLIBC_PREREQ(2, 12) const size_t bytes = malloc_usable_size(pl); @@ -935,7 +932,7 @@ static __inline size_t bytes2txl(const size_t bytes) { static MDBX_TXL mdbx_txl_alloc(void) { const size_t bytes = txl2bytes(MDBX_TXL_INITIAL); - MDBX_TXL tl = malloc(bytes); + MDBX_TXL tl = mdbx_malloc(bytes); if (likely(tl)) { #if __GLIBC_PREREQ(2, 12) const size_t bytes = malloc_usable_size(tl); @@ -950,7 +947,7 @@ static MDBX_TXL mdbx_txl_alloc(void) { static void mdbx_txl_free(MDBX_TXL tl) { if (likely(tl)) - free(tl - 1); + mdbx_free(tl - 1); } static int mdbx_txl_reserve(MDBX_TXL *ptl, const size_t wanna) { @@ -967,7 +964,7 @@ static int mdbx_txl_reserve(MDBX_TXL *ptl, const size_t wanna) { ? wanna + wanna - allocated : MDBX_TXL_MAX; const size_t bytes = txl2bytes(size); - MDBX_TXL tl = realloc(*ptl - 1, bytes); + MDBX_TXL tl = mdbx_realloc(*ptl - 1, bytes); if (likely(tl)) { #if __GLIBC_PREREQ(2, 12) const size_t bytes = malloc_usable_size(tl); @@ -1328,7 +1325,7 @@ const char *__cold mdbx_strerror_r(int errnum, char *buf, size_t buflen) { if (!msg) { if (!buflen || buflen > INT_MAX) return NULL; -#ifdef _MSC_VER +#if defined(_WIN32) || defined(_WIN64) size_t size = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (DWORD)buflen, @@ -1357,7 +1354,7 @@ const char *__cold mdbx_strerror_r(int errnum, char *buf, size_t buflen) { const char *__cold mdbx_strerror(int errnum) { const char *msg = __mdbx_strerr(errnum); if (!msg) { -#ifdef _MSC_VER +#if defined(_WIN32) || defined(_WIN64) static char buffer[1024]; size_t size = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, @@ -1389,6 +1386,28 @@ void __cold mdbx_debug_log(int type, const char *function, int line, if (mdbx_debug_logger) mdbx_debug_logger(type, function, line, fmt, args); else { +#if defined(_WIN32) || defined(_WIN64) + if (IsDebuggerPresent()) { + int prefix_len = 0; + char *prefix = nullptr; + if (function && line > 0) + prefix_len = mdbx_asprintf(&prefix, "%s:%d ", function, line); + else if (function) + prefix_len = mdbx_asprintf(&prefix, "%s: ", function); + else if (line > 0) + prefix_len = mdbx_asprintf(&prefix, "%d: ", line); + if (prefix_len > 0 && prefix) { + OutputDebugStringA(prefix); + mdbx_free(prefix); + } + char *msg = nullptr; + int msg_len = mdbx_vasprintf(&msg, fmt, args); + if (msg_len > 0 && msg) { + OutputDebugStringA(msg); + mdbx_free(msg); + } + } +#else if (function && line > 0) fprintf(stderr, "%s:%d ", function, line); else if (function) @@ -1397,6 +1416,7 @@ void __cold mdbx_debug_log(int type, const char *function, int line, fprintf(stderr, "%d: ", line); vfprintf(stderr, fmt, args); fflush(stderr); +#endif } va_end(args); } @@ -1577,7 +1597,7 @@ static MDBX_page *mdbx_page_malloc(MDBX_txn *txn, unsigned num) { env->me_dpages = np->mp_next; } else { size = pgno2bytes(env, num); - np = malloc(size); + np = mdbx_malloc(size); if (unlikely(!np)) { txn->mt_flags |= MDBX_TXN_ERROR; return np; @@ -1615,7 +1635,7 @@ static void mdbx_dpage_free(MDBX_env *env, MDBX_page *dp, unsigned pages) { } else { /* large pages just get freed directly */ VALGRIND_MEMPOOL_FREE(env, dp); - free(dp); + mdbx_free(dp); } } @@ -1639,7 +1659,9 @@ static size_t bytes_align2os_bytes(const MDBX_env *env, size_t bytes) { static void __cold mdbx_kill_page(MDBX_env *env, MDBX_page *mp) { const size_t len = env->me_psize - PAGEHDRSZ; - void *ptr = (env->me_flags & MDBX_WRITEMAP) ? &mp->mp_data : alloca(len); + void *ptr = (env->me_flags & MDBX_WRITEMAP) + ? &mp->mp_data + : (void *)((uint8_t *)env->me_pbuf + env->me_psize); memset(ptr, 0x6F /* 'o', 111 */, len); if (ptr != &mp->mp_data) (void)mdbx_pwrite(env->me_fd, ptr, len, @@ -2273,18 +2295,20 @@ bailout: VALGRIND_CREATE_BLOCK(env->me_map, env->me_mapsize, "mdbx"); } #endif - } else if (rc != MDBX_RESULT_TRUE) { - mdbx_error("failed resize datafile/mapping: " - "present %" PRIuPTR " -> %" PRIuPTR ", " - "limit %" PRIuPTR " -> %" PRIuPTR ", errcode %d", - env->me_dbgeo.now, size_bytes, env->me_dbgeo.upper, limit_bytes, - rc); } else { - mdbx_notice("unable resize datafile/mapping: " - "present %" PRIuPTR " -> %" PRIuPTR ", " - "limit %" PRIuPTR " -> %" PRIuPTR ", errcode %d", - env->me_dbgeo.now, size_bytes, env->me_dbgeo.upper, limit_bytes, - rc); + if (rc != MDBX_RESULT_TRUE) { + mdbx_error("failed resize datafile/mapping: " + "present %" PRIuPTR " -> %" PRIuPTR ", " + "limit %" PRIuPTR " -> %" PRIuPTR ", errcode %d", + env->me_dbgeo.now, size_bytes, env->me_dbgeo.upper, + limit_bytes, rc); + } else { + mdbx_notice("unable resize datafile/mapping: " + "present %" PRIuPTR " -> %" PRIuPTR ", " + "limit %" PRIuPTR " -> %" PRIuPTR ", errcode %d", + env->me_dbgeo.now, size_bytes, env->me_dbgeo.upper, + limit_bytes, rc); + } if (!env->me_dxb_mmap.address) { env->me_flags |= MDBX_FATAL_ERROR; if (env->me_txn) @@ -2299,7 +2323,7 @@ bailout: if (suspended) { err = mdbx_resume_threads_after_remap(suspended); if (suspended != &array_onstack) - free(suspended); + mdbx_free(suspended); } #else int err = mdbx_fastmutex_release(&env->me_remap_guard); @@ -3025,7 +3049,7 @@ static int mdbx_cursor_shadow(MDBX_txn *src, MDBX_txn *dst) { if (mc->mc_xcursor) size += sizeof(MDBX_xcursor); for (; mc; mc = bk->mc_next) { - bk = malloc(size); + bk = mdbx_malloc(size); if (unlikely(!bk)) return MDBX_ENOMEM; *bk = *mc; @@ -3082,11 +3106,11 @@ static void mdbx_cursors_eot(MDBX_txn *txn, unsigned merge) { *mx = *(MDBX_xcursor *)(bk + 1); } bk->mc_signature = 0; - free(bk); + mdbx_free(bk); } if (stage == MDBX_MC_WAIT4EOT) { mc->mc_signature = 0; - free(mc); + mdbx_free(mc); } else { mc->mc_signature = MDBX_MC_READY4CLOSE; mc->mc_flags = 0 /* reset C_UNTRACK */; @@ -3139,6 +3163,16 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) { rc = mdbx_rdt_lock(env); if (unlikely(MDBX_IS_ERROR(rc))) return rc; + if (unlikely(env->me_flags & MDBX_FATAL_ERROR)) { + mdbx_rdt_unlock(env); + return MDBX_PANIC; + } +#if defined(_WIN32) || defined(_WIN64) + if (unlikely(!env->me_map)) { + mdbx_rdt_unlock(env); + return MDBX_EPERM; + } +#endif /* Windows */ rc = MDBX_SUCCESS; if (unlikely(env->me_live_reader != env->me_pid)) { @@ -3237,6 +3271,16 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) { rc = mdbx_txn_lock(env, F_ISSET(flags, MDBX_TRYTXN)); if (unlikely(rc)) return rc; + if (unlikely(env->me_flags & MDBX_FATAL_ERROR)) { + mdbx_txn_unlock(env); + return MDBX_PANIC; + } +#if defined(_WIN32) || defined(_WIN64) + if (unlikely(!env->me_map)) { + mdbx_txn_unlock(env); + return MDBX_EPERM; + } +#endif /* Windows */ mdbx_jitter4testing(false); MDBX_meta *meta = mdbx_meta_head(env); @@ -3296,8 +3340,11 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) { goto bailout; } rc = mdbx_mapresize(env, txn->mt_end_pgno, upper_pgno); - if (rc != MDBX_SUCCESS) + if (rc != MDBX_SUCCESS) { + if (rc == MDBX_RESULT_TRUE) + rc = MDBX_MAP_RESIZED; goto bailout; + } } txn->mt_owner = mdbx_thread_self(); return MDBX_SUCCESS; @@ -3345,6 +3392,7 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags, if (unlikely(!env || !ret)) return MDBX_EINVAL; + *ret = NULL; if (unlikely(env->me_signature != MDBX_ME_SIGNATURE)) return MDBX_EBADSIGN; @@ -3354,8 +3402,12 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags, if (unlikely(env->me_flags & MDBX_FATAL_ERROR)) return MDBX_PANIC; +#if !defined(_WIN32) && !defined(_WIN64) + /* Don't check env->me_map until lock to avoid race with re-mapping for + * shrinking */ if (unlikely(!env->me_map)) return MDBX_EPERM; +#endif /* Windows */ flags &= MDBX_TXN_BEGIN_FLAGS; flags |= env->me_flags & MDBX_WRITEMAP; @@ -3366,16 +3418,21 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags, if (parent) { if (unlikely(parent->mt_signature != MDBX_MT_SIGNATURE)) - return MDBX_EINVAL; + return MDBX_EBADSIGN; if (unlikely(parent->mt_owner != mdbx_thread_self())) return MDBX_THREAD_MISMATCH; +#if defined(_WIN32) || defined(_WIN64) + if (unlikely(!env->me_map)) + return MDBX_EPERM; +#endif /* Windows */ + /* Nested transactions: Max 1 child, write txns only, no writemap */ flags |= parent->mt_flags; - if (unlikely(flags & (MDBX_RDONLY | MDBX_WRITEMAP | MDBX_TXN_BLOCKED))) { + if (unlikely(flags & (MDBX_RDONLY | MDBX_WRITEMAP | MDBX_TXN_BLOCKED))) return (parent->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EINVAL : MDBX_BAD_TXN; - } + /* Child txns save MDBX_pgstate and use own copy of cursors */ size = env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + 1); size += tsize = sizeof(MDBX_ntxn); @@ -3392,7 +3449,7 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags, return MDBX_BUSY; goto renew; } - if (unlikely((txn = malloc(size)) == NULL)) { + if (unlikely((txn = mdbx_malloc(size)) == NULL)) { mdbx_debug("calloc: %s", "failed"); return MDBX_ENOMEM; } @@ -3407,11 +3464,12 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags, unsigned i; txn->mt_cursors = (MDBX_cursor **)(txn->mt_dbs + env->me_maxdbs); txn->mt_dbiseqs = parent->mt_dbiseqs; - txn->mt_rw_dirtylist = malloc(sizeof(MDBX_DP) * (MDBX_DPL_TXNFULL + 1)); + txn->mt_rw_dirtylist = + mdbx_malloc(sizeof(MDBX_DP) * (MDBX_DPL_TXNFULL + 1)); if (!txn->mt_rw_dirtylist || !(txn->mt_befree_pages = mdbx_pnl_alloc(MDBX_PNL_INITIAL))) { - free(txn->mt_rw_dirtylist); - free(txn); + mdbx_free(txn->mt_rw_dirtylist); + mdbx_free(txn); return MDBX_ENOMEM; } txn->mt_txnid = parent->mt_txnid; @@ -3452,10 +3510,12 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags, rc = mdbx_txn_renew0(txn, flags); } - if (unlikely(rc)) { + if (unlikely(rc != MDBX_SUCCESS)) { if (txn != env->me_txn0) - free(txn); + mdbx_free(txn); } else { + mdbx_assert(env, + (txn->mt_flags & ~(MDBX_TXN_RDONLY | MDBX_TXN_WRITEMAP)) == 0); txn->mt_signature = MDBX_MT_SIGNATURE; *ret = txn; mdbx_debug("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO @@ -3516,7 +3576,7 @@ static void mdbx_dbis_update(MDBX_txn *txn, int keep) { mdbx_assert(env, env->me_dbflags[i] == 0); env->me_dbiseqs[i]++; env->me_dbxs[i].md_name.iov_base = NULL; - free(ptr); + mdbx_free(ptr); } } } @@ -3601,7 +3661,7 @@ static int mdbx_txn_end(MDBX_txn *txn, unsigned mode) { env->me_pgstate = ((MDBX_ntxn *)txn)->mnt_pgstate; mdbx_pnl_free(txn->mt_befree_pages); mdbx_pnl_free(txn->mt_spill_pages); - free(txn->mt_rw_dirtylist); + mdbx_free(txn->mt_rw_dirtylist); } mdbx_pnl_free(pghead); @@ -3610,7 +3670,7 @@ static int mdbx_txn_end(MDBX_txn *txn, unsigned mode) { mdbx_assert(env, txn == env->me_txn0 || txn->mt_owner == 0); if ((mode & MDBX_END_FREE) != 0 && txn != env->me_txn0) { txn->mt_signature = 0; - free(txn); + mdbx_free(txn); } return MDBX_SUCCESS; @@ -3646,7 +3706,7 @@ int mdbx_txn_abort(MDBX_txn *txn) { if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE)) return MDBX_EBADSIGN; - if (unlikely(txn->mt_owner && txn->mt_owner != mdbx_thread_self())) + if (unlikely(txn->mt_owner != mdbx_thread_self())) return MDBX_THREAD_MISMATCH; if (F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY)) @@ -4498,7 +4558,7 @@ static int mdbx_page_flush(MDBX_txn *txn, pgno_t keep) { /* Write previous page(s) */ rc = mdbx_pwritev(env->me_fd, iov, n, wpos, wsize); if (unlikely(rc != MDBX_SUCCESS)) { - mdbx_debug("Write error: %s", strerror(rc)); + mdbx_debug("Write error: %s", mdbx_strerror(rc)); return rc; } n = 0; @@ -4691,7 +4751,7 @@ int mdbx_txn_commit(MDBX_txn *txn) { pn >>= 1; y = mdbx_dpl_search(dst, pn); if (y <= dst->length && dst[y].pgno == pn) { - free(dst[y].ptr); + mdbx_free(dst[y].ptr); while (y < dst->length) { dst[y] = dst[y + 1]; y++; @@ -4726,11 +4786,11 @@ int mdbx_txn_commit(MDBX_txn *txn) { while (yp < dst[x].pgno) dst[i--] = dst[x--]; if (yp == dst[x].pgno) - free(dst[x--].ptr); + mdbx_free(dst[x--].ptr); } mdbx_tassert(txn, i == x); dst->length = len; - free(txn->mt_rw_dirtylist); + mdbx_free(txn->mt_rw_dirtylist); parent->mt_dirtyroom = txn->mt_dirtyroom; if (txn->mt_spill_pages) { if (parent->mt_spill_pages) { @@ -4754,7 +4814,7 @@ int mdbx_txn_commit(MDBX_txn *txn) { parent->mt_child = NULL; mdbx_pnl_free(((MDBX_ntxn *)txn)->mnt_pgstate.mf_reclaimed_pglist); txn->mt_signature = 0; - free(txn); + mdbx_free(txn); return rc; } @@ -4836,8 +4896,10 @@ int mdbx_txn_commit(MDBX_txn *txn) { rc = mdbx_sync_locked( env, env->me_flags | txn->mt_flags | MDBX_SHRINK_ALLOWED, &meta); } - if (unlikely(rc != MDBX_SUCCESS)) + if (unlikely(rc != MDBX_SUCCESS)) { + env->me_flags |= MDBX_FATAL_ERROR; goto fail; + } if (likely(env->me_lck)) env->me_lck->mti_readers_refresh_flag = false; @@ -4905,7 +4967,8 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta, mdbx_info("meta[%u] was updated, re-read it", meta_number); } - if (page.mp_meta.mm_magic_and_version != MDBX_DATA_MAGIC && page.mp_meta.mm_magic_and_version != MDBX_DATA_DEBUG) { + if (page.mp_meta.mm_magic_and_version != MDBX_DATA_MAGIC && + page.mp_meta.mm_magic_and_version != MDBX_DATA_MAGIC_DEVEL) { mdbx_error("meta[%u] has invalid magic/version %" PRIx64, meta_number, page.mp_meta.mm_magic_and_version); return ((page.mp_meta.mm_magic_and_version >> 8) != MDBX_MAGIC) @@ -5466,7 +5529,7 @@ static void __cold mdbx_setup_pagesize(MDBX_env *env, const size_t pagesize) { } int __cold mdbx_env_create(MDBX_env **penv) { - MDBX_env *env = calloc(1, sizeof(MDBX_env)); + MDBX_env *env = mdbx_calloc(1, sizeof(MDBX_env)); if (!env) return MDBX_ENOMEM; @@ -5513,7 +5576,7 @@ int __cold mdbx_env_create(MDBX_env **penv) { return MDBX_SUCCESS; bailout: - free(env); + mdbx_free(env); *penv = nullptr; return rc; } @@ -5867,13 +5930,13 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) { return err; } - void *buffer = calloc(NUM_METAS, env->me_psize); + void *buffer = mdbx_calloc(NUM_METAS, env->me_psize); if (!buffer) return MDBX_ENOMEM; meta = mdbx_init_metas(env, buffer)->mp_meta; err = mdbx_pwrite(env->me_fd, buffer, env->me_psize * NUM_METAS, 0); - free(buffer); + mdbx_free(buffer); if (unlikely(err != MDBX_SUCCESS)) return err; @@ -6168,9 +6231,7 @@ static int __cold mdbx_setup_lck(MDBX_env *env, char *lck_pathname, mdbx_assert(env, env->me_fd != INVALID_HANDLE_VALUE); mdbx_assert(env, env->me_lfd == INVALID_HANDLE_VALUE); - const int open_flags = - (env->me_flags & MDBX_EXCLUSIVE) ? O_RDWR : O_RDWR | O_CREAT; - int err = mdbx_openfile(lck_pathname, open_flags, mode, &env->me_lfd, + int err = mdbx_openfile(lck_pathname, O_RDWR | O_CREAT, mode, &env->me_lfd, (env->me_flags & MDBX_EXCLUSIVE) ? true : false); if (err != MDBX_SUCCESS) { if (!(err == MDBX_ENOFILE && (env->me_flags & MDBX_EXCLUSIVE)) && @@ -6277,7 +6338,8 @@ static int __cold mdbx_setup_lck(MDBX_env *env, char *lck_pathname, env->me_lck->mti_magic_and_version = MDBX_LOCK_MAGIC; env->me_lck->mti_os_and_format = MDBX_LOCK_FORMAT; } else { - if (env->me_lck->mti_magic_and_version != MDBX_LOCK_MAGIC && env->me_lck->mti_magic_and_version != MDBX_LOCK_DEBUG) { + if (env->me_lck->mti_magic_and_version != MDBX_LOCK_MAGIC && + env->me_lck->mti_magic_and_version != MDBX_LOCK_MAGIC_DEVEL) { mdbx_error("lock region has invalid magic/version"); return ((env->me_lck->mti_magic_and_version >> 8) != MDBX_MAGIC) ? MDBX_INVALID @@ -6333,7 +6395,7 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags, } else { len_full = len + sizeof(MDBX_LOCKNAME) + len + sizeof(MDBX_DATANAME); } - char *lck_pathname = malloc(len_full); + char *lck_pathname = mdbx_malloc(len_full); if (!lck_pathname) return MDBX_ENOMEM; @@ -6357,7 +6419,8 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags, MDBX_COALESCE | MDBX_LIFORECLAIM | MDBX_NOMEMINIT); } else { if (!((env->me_free_pgs = mdbx_pnl_alloc(MDBX_PNL_INITIAL)) && - (env->me_dirtylist = calloc(MDBX_DPL_TXNFULL + 1, sizeof(MDBX_DP))))) + (env->me_dirtylist = + mdbx_calloc(MDBX_DPL_TXNFULL + 1, sizeof(MDBX_DP))))) rc = MDBX_ENOMEM; } @@ -6367,9 +6430,9 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags, goto bailout; env->me_path = mdbx_strdup(path); - env->me_dbxs = calloc(env->me_maxdbs, sizeof(MDBX_dbx)); - env->me_dbflags = calloc(env->me_maxdbs, sizeof(env->me_dbflags[0])); - env->me_dbiseqs = calloc(env->me_maxdbs, sizeof(env->me_dbiseqs[0])); + env->me_dbxs = mdbx_calloc(env->me_maxdbs, sizeof(MDBX_dbx)); + env->me_dbflags = mdbx_calloc(env->me_maxdbs, sizeof(env->me_dbflags[0])); + env->me_dbiseqs = mdbx_calloc(env->me_maxdbs, sizeof(env->me_dbiseqs[0])); if (!(env->me_dbxs && env->me_path && env->me_dbflags && env->me_dbiseqs)) { rc = MDBX_ENOMEM; goto bailout; @@ -6448,7 +6511,8 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags, size = tsize + env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + sizeof(unsigned) + 1); - if ((env->me_pbuf = calloc(1, env->me_psize)) && (txn = calloc(1, size))) { + if ((env->me_pbuf = mdbx_calloc(2, env->me_psize)) && + (txn = mdbx_calloc(1, size))) { txn->mt_dbs = (MDBX_db *)((char *)txn + tsize); txn->mt_cursors = (MDBX_cursor **)(txn->mt_dbs + env->me_maxdbs); txn->mt_dbiseqs = (unsigned *)(txn->mt_cursors + env->me_maxdbs); @@ -6486,7 +6550,7 @@ bailout: mdbx_env_close0(env); env->me_flags = saved_me_flags | MDBX_FATAL_ERROR; } - free(lck_pathname); + mdbx_free(lck_pathname); return rc; } @@ -6499,18 +6563,18 @@ static void __cold mdbx_env_close0(MDBX_env *env) { /* Doing this here since me_dbxs may not exist during mdbx_env_close */ if (env->me_dbxs) { for (unsigned i = env->me_maxdbs; --i >= CORE_DBS;) - free(env->me_dbxs[i].md_name.iov_base); - free(env->me_dbxs); + mdbx_free(env->me_dbxs[i].md_name.iov_base); + mdbx_free(env->me_dbxs); } - free(env->me_pbuf); - free(env->me_dbiseqs); - free(env->me_dbflags); - free(env->me_path); - free(env->me_dirtylist); + mdbx_free(env->me_pbuf); + mdbx_free(env->me_dbiseqs); + mdbx_free(env->me_dbflags); + mdbx_free(env->me_path); + mdbx_free(env->me_dirtylist); if (env->me_txn0) { mdbx_txl_free(env->me_txn0->mt_lifo_reclaimed); - free(env->me_txn0); + mdbx_free(env->me_txn0); } mdbx_pnl_free(env->me_free_pgs); @@ -6578,7 +6642,7 @@ int __cold mdbx_env_close_ex(MDBX_env *env, int dont_sync) { ASAN_UNPOISON_MEMORY_REGION(&dp->mp_next, sizeof(dp->mp_next)); VALGRIND_MAKE_MEM_DEFINED(&dp->mp_next, sizeof(dp->mp_next)); env->me_dpages = dp->mp_next; - free(dp); + mdbx_free(dp); } mdbx_env_close0(env); @@ -6595,7 +6659,7 @@ int __cold mdbx_env_close_ex(MDBX_env *env, int dont_sync) { env->me_pid = 0; env->me_signature = 0; - free(env); + mdbx_free(env); return rc; } @@ -6927,13 +6991,20 @@ mapped: p = pgno2page(env, pgno); done: - if (unlikely(p->mp_pgno != pgno)) + if (unlikely(p->mp_pgno != pgno)) { + mdbx_error("mismatch pgno %" PRIaPGNO " (actual) != %" PRIaPGNO + " (expected)", + p->mp_pgno, pgno); return MDBX_CORRUPTED; + } if (unlikely(p->mp_upper < p->mp_lower || PAGEHDRSZ + p->mp_upper > env->me_psize) && - !IS_OVERFLOW(p)) + !IS_OVERFLOW(p)) { + mdbx_error("invalid page lower(%u)/upper(%u), pg-limit %u", p->mp_lower, + p->mp_upper, env->me_psize - PAGEHDRSZ); return MDBX_CORRUPTED; + } /* TODO: more checks here, including p->mp_validator */ *ret = p; @@ -9393,10 +9464,10 @@ int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) { : sizeof(MDBX_cursor); MDBX_cursor *mc; - if (likely((mc = malloc(size)) != NULL)) { + if (likely((mc = mdbx_malloc(size)) != NULL)) { int rc = mdbx_cursor_init(mc, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) { - free(mc); + mdbx_free(mc); return rc; } if (txn->mt_cursors) { @@ -9508,7 +9579,7 @@ void mdbx_cursor_close(MDBX_cursor *mc) { *prev = mc->mc_next; } mc->mc_signature = 0; - free(mc); + mdbx_free(mc); } else { /* cursor closed before nested txn ends */ mdbx_cassert(mc, mc->mc_signature == MDBX_MC_SIGNATURE); @@ -11248,7 +11319,7 @@ static int __cold mdbx_env_cwalk(mdbx_copy *my, pgno_t *pg, int flags) { return rc; /* Make cursor pages writable */ - buf = ptr = malloc(pgno2bytes(my->mc_env, mc.mc_snum)); + buf = ptr = mdbx_malloc(pgno2bytes(my->mc_env, mc.mc_snum)); if (buf == NULL) return MDBX_ENOMEM; @@ -11373,7 +11444,7 @@ static int __cold mdbx_env_cwalk(mdbx_copy *my, pgno_t *pg, int flags) { } } done: - free(buf); + mdbx_free(buf); return rc; } @@ -11545,7 +11616,7 @@ int __cold mdbx_env_copy(MDBX_env *env, const char *dest_path, unsigned flags) { } else { size_t len = strlen(dest_path); len += sizeof(MDBX_DATANAME); - dxb_pathname = malloc(len); + dxb_pathname = mdbx_malloc(len); if (!dxb_pathname) return MDBX_ENOMEM; sprintf(dxb_pathname, "%s" MDBX_DATANAME, dest_path); @@ -11578,7 +11649,7 @@ int __cold mdbx_env_copy(MDBX_env *env, const char *dest_path, unsigned flags) { } if (dxb_pathname != dest_path) - free(dxb_pathname); + mdbx_free(dxb_pathname); return rc; } @@ -11897,7 +11968,7 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags, int err = mdbx_fastmutex_acquire(&env->me_dbi_lock); if (unlikely(err != MDBX_SUCCESS)) { - free(namedup); + mdbx_free(namedup); return err; } @@ -11961,7 +12032,7 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags, if (unlikely(rc != MDBX_SUCCESS)) { mdbx_tassert(txn, (dbflag & DB_CREAT) == 0); bailout: - free(namedup); + mdbx_free(namedup); } else { txn->mt_dbiseqs[slot] = (env->me_dbiseqs[slot] += 1); txn->mt_dbflags[slot] = (uint8_t)dbflag; @@ -12032,7 +12103,7 @@ static int mdbx_dbi_close_locked(MDBX_env *env, MDBX_dbi dbi) { mdbx_compiler_barrier(); env->me_dbiseqs[dbi]++; env->me_dbxs[dbi].md_name.iov_base = NULL; - free(ptr); + mdbx_free(ptr); return MDBX_SUCCESS; } @@ -12391,7 +12462,14 @@ int __cold mdbx_reader_check0(MDBX_env *env, int rdt_locked, int *dead) { } const unsigned snap_nreaders = lck->mti_numreaders; - mdbx_pid_t *pids = alloca((snap_nreaders + 1) * sizeof(mdbx_pid_t)); + mdbx_pid_t pidsbuf_onstask[142]; + mdbx_pid_t *const pids = + (snap_nreaders < ARRAY_LENGTH(pidsbuf_onstask)) + ? pidsbuf_onstask + : mdbx_malloc((snap_nreaders + 1) * sizeof(mdbx_pid_t)); + if (unlikely(!pids)) + return MDBX_ENOMEM; + pids[0] = 0; int rc = MDBX_SUCCESS, count = 0; @@ -12457,6 +12535,9 @@ int __cold mdbx_reader_check0(MDBX_env *env, int rdt_locked, int *dead) { if (rdt_locked < 0) mdbx_rdt_unlock(env); + if (pids != pidsbuf_onstask) + mdbx_free(pids); + if (dead) *dead = count; return rc; @@ -12747,9 +12828,20 @@ static int __cold mdbx_env_walk(mdbx_walk_ctx_t *ctx, const char *dbi, MDBX_db db; memcpy(&db, NODEDATA(node), sizeof(db)); - char *name = memcpy(alloca(namelen + 1), NODEKEY(node), namelen); - name[namelen] = 0; - rc = mdbx_env_walk(ctx, name, db.md_root, deep + 1); + + char namebuf_onstask[142]; + char *const name = (namelen < sizeof(namebuf_onstask)) + ? namebuf_onstask + : mdbx_malloc(namelen + 1); + if (name) { + memcpy(name, NODEKEY(node), namelen); + name[namelen] = 0; + rc = mdbx_env_walk(ctx, name, db.md_root, deep + 1); + if (name != namebuf_onstask) + mdbx_free(name); + } else { + rc = MDBX_ENOMEM; + } } break; case F_SUBDATA | F_DUPDATA /* dupsorted sub-tree */: { @@ -13276,6 +13368,14 @@ int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result, if (unlikely(TXN_DBI_CHANGED(txn, dbi))) return MDBX_BAD_DBI; + if (unlikely(txn->mt_dbflags[dbi] & DB_STALE)) { + MDBX_cursor_couple cx; + /* Stale, must read the DB's root. cursor_init does it for us. */ + int rc = mdbx_cursor_init(&cx.outer, txn, dbi); + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + } + MDBX_db *dbs = &txn->mt_dbs[dbi]; if (likely(result)) *result = dbs->md_seq; diff --git a/libs/libmdbx/src/src/osal.c b/libs/libmdbx/src/src/osal.c index 738a179465..b39eea4be8 100644 --- a/libs/libmdbx/src/src/osal.c +++ b/libs/libmdbx/src/src/osal.c @@ -53,6 +53,9 @@ static int ntstatus2errcode(NTSTATUS status) { * declare them here. Using these APIs also means we must link to * ntdll.dll, which is not linked by default in user code. */ #pragma comment(lib, "ntdll.lib") +#ifdef MDBX_AVOID_CRT +#pragma comment(lib, "mdbx_ntdll_extra.lib") +#endif extern NTSTATUS NTAPI NtCreateSection( OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, @@ -137,6 +140,15 @@ typedef struct _FILE_PROVIDER_EXTERNAL_INFO_V1 { #define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS)0xC0000010L) #endif +#ifndef FILE_DEVICE_FILE_SYSTEM +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#endif + +#ifndef FSCTL_GET_EXTERNAL_BACKING +#define FSCTL_GET_EXTERNAL_BACKING \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 196, METHOD_BUFFERED, FILE_ANY_ACCESS) +#endif + #endif /* _WIN32 || _WIN64 */ /*----------------------------------------------------------------------------*/ @@ -145,13 +157,8 @@ typedef struct _FILE_PROVIDER_EXTERNAL_INFO_V1 { /* Prototype should match libc runtime. ISO POSIX (2003) & LSB 3.1 */ __nothrow __noreturn void __assert_fail(const char *assertion, const char *file, unsigned line, const char *function); -#else -__extern_C __declspec(dllimport) void __cdecl _assert(char const *message, - char const *filename, - unsigned line); #endif /* _MSC_VER */ -#ifndef mdbx_assert_fail void __cold mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func, int line) { #if MDBX_DEBUG @@ -165,49 +172,57 @@ void __cold mdbx_assert_fail(const MDBX_env *env, const char *msg, if (mdbx_debug_logger) mdbx_debug_log(MDBX_DBG_ASSERT, func, line, "assert: %s\n", msg); -#ifndef _MSC_VER - __assert_fail(msg, "mdbx", line, func); + else { +#if defined(_WIN32) || defined(_WIN64) + char *message = nullptr; + const int num = mdbx_asprintf(&message, "\r\nMDBX-ASSERTION: %s, %s:%u", + msg, func ? func : "unknown", line); + if (num < 1 || !message) + message = "<troubles with assertion-message preparation>"; + OutputDebugStringA(message); + if (IsDebuggerPresent()) + DebugBreak(); #else - _assert(msg, func, line); -#endif /* _MSC_VER */ + __assert_fail(msg, "mdbx", line, func); +#endif + } + +#if defined(_WIN32) || defined(_WIN64) + FatalExit(ERROR_UNHANDLED_ERROR); +#else + abort(); +#endif } -#endif /* mdbx_assert_fail */ __cold void mdbx_panic(const char *fmt, ...) { va_list ap; va_start(ap, fmt); -#ifdef _MSC_VER - if (IsDebuggerPresent()) { - OutputDebugStringA("\r\n" FIXME "\r\n"); - FatalExit(ERROR_UNHANDLED_ERROR); - } -#elif _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L || \ - (__GLIBC_PREREQ(1, 0) && !__GLIBC_PREREQ(2, 10) && defined(_GNU_SOURCE)) - vdprintf(STDERR_FILENO, fmt, ap); -#else -#error FIXME -#endif + + char *message = nullptr; + const int num = mdbx_vasprintf(&message, fmt, ap); va_end(ap); + if (num < 1 || !message) + message = "<troubles with panic-message preparation>"; + +#if defined(_WIN32) || defined(_WIN64) + OutputDebugStringA("\r\nMDBX-PANIC: "); + OutputDebugStringA(message); + if (IsDebuggerPresent()) + DebugBreak(); + FatalExit(ERROR_UNHANDLED_ERROR); +#else + __assert_fail(message, "mdbx", 0, "panic"); abort(); +#endif } /*----------------------------------------------------------------------------*/ -#ifndef mdbx_asprintf -int mdbx_asprintf(char **strp, const char *fmt, ...) { - va_list ap, ones; - - va_start(ap, fmt); +#ifndef mdbx_vasprintf +int mdbx_vasprintf(char **strp, const char *fmt, va_list ap) { + va_list ones; va_copy(ones, ap); -#ifdef _MSC_VER - int needed = _vscprintf(fmt, ap); -#elif defined(vsnprintf) || defined(_BSD_SOURCE) || _XOPEN_SOURCE >= 500 || \ - defined(_ISOC99_SOURCE) || _POSIX_C_SOURCE >= 200112L int needed = vsnprintf(nullptr, 0, fmt, ap); -#else -#error FIXME -#endif - va_end(ap); if (unlikely(needed < 0 || needed >= INT_MAX)) { *strp = nullptr; @@ -215,34 +230,44 @@ int mdbx_asprintf(char **strp, const char *fmt, ...) { return needed; } - *strp = malloc(needed + 1); + *strp = mdbx_malloc(needed + 1); if (unlikely(*strp == nullptr)) { va_end(ones); +#if defined(_WIN32) || defined(_WIN64) SetLastError(MDBX_ENOMEM); +#else + errno = MDBX_ENOMEM; +#endif return -1; } -#if defined(vsnprintf) || defined(_BSD_SOURCE) || _XOPEN_SOURCE >= 500 || \ - defined(_ISOC99_SOURCE) || _POSIX_C_SOURCE >= 200112L int actual = vsnprintf(*strp, needed + 1, fmt, ones); -#else -#error FIXME -#endif va_end(ones); assert(actual == needed); if (unlikely(actual < 0)) { - free(*strp); + mdbx_free(*strp); *strp = nullptr; } return actual; } +#endif /* mdbx_vasprintf */ + +#ifndef mdbx_asprintf +int mdbx_asprintf(char **strp, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int rc = mdbx_vasprintf(strp, fmt, ap); + va_end(ap); + return rc; +} #endif /* mdbx_asprintf */ #ifndef mdbx_memalign_alloc int mdbx_memalign_alloc(size_t alignment, size_t bytes, void **result) { -#if _MSC_VER - *result = _aligned_malloc(bytes, alignment); +#if defined(_WIN32) || defined(_WIN64) + (void)alignment; + *result = VirtualAlloc(NULL, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); return *result ? MDBX_SUCCESS : MDBX_ENOMEM /* ERROR_OUTOFMEMORY */; #elif __GLIBC_PREREQ(2, 16) || __STDC_VERSION__ >= 201112L *result = memalign(alignment, bytes); @@ -258,14 +283,26 @@ int mdbx_memalign_alloc(size_t alignment, size_t bytes, void **result) { #ifndef mdbx_memalign_free void mdbx_memalign_free(void *ptr) { -#if _MSC_VER - _aligned_free(ptr); +#if defined(_WIN32) || defined(_WIN64) + VirtualFree(ptr, 0, MEM_RELEASE); #else - free(ptr); + mdbx_free(ptr); #endif } #endif /* mdbx_memalign_free */ +#ifndef mdbx_strdup +char *mdbx_strdup(const char *str) { + if (!str) + return NULL; + size_t bytes = strlen(str) + 1; + char *dup = mdbx_malloc(bytes); + if (dup) + memcpy(dup, str, bytes); + return dup; +} +#endif /* mdbx_strdup */ + /*----------------------------------------------------------------------------*/ int mdbx_condmutex_init(mdbx_condmutex_t *condmutex) { @@ -797,33 +834,47 @@ int mdbx_check4nonlocal(mdbx_filehandle_t handle, int flags) { } if (mdbx_GetVolumeInformationByHandleW && mdbx_GetFinalPathNameByHandleW) { - WCHAR PathBuffer[INT16_MAX]; + WCHAR *PathBuffer = mdbx_malloc(sizeof(WCHAR) * INT16_MAX); + if (!PathBuffer) + return MDBX_ENOMEM; + + int rc = MDBX_SUCCESS; DWORD VolumeSerialNumber, FileSystemFlags; if (!mdbx_GetVolumeInformationByHandleW(handle, PathBuffer, INT16_MAX, &VolumeSerialNumber, NULL, - &FileSystemFlags, NULL, 0)) - return GetLastError(); + &FileSystemFlags, NULL, 0)) { + rc = GetLastError(); + goto bailout; + } if ((flags & MDBX_RDONLY) == 0) { - if (FileSystemFlags & (FILE_SEQUENTIAL_WRITE_ONCE | - FILE_READ_ONLY_VOLUME | FILE_VOLUME_IS_COMPRESSED)) - return ERROR_REMOTE_STORAGE_MEDIA_ERROR; + if (FileSystemFlags & + (FILE_SEQUENTIAL_WRITE_ONCE | FILE_READ_ONLY_VOLUME | + FILE_VOLUME_IS_COMPRESSED)) { + rc = ERROR_REMOTE_STORAGE_MEDIA_ERROR; + goto bailout; + } } if (!mdbx_GetFinalPathNameByHandleW(handle, PathBuffer, INT16_MAX, - FILE_NAME_NORMALIZED | VOLUME_NAME_NT)) - return GetLastError(); + FILE_NAME_NORMALIZED | + VOLUME_NAME_NT)) { + rc = GetLastError(); + goto bailout; + } if (_wcsnicmp(PathBuffer, L"\\Device\\Mup\\", 12) == 0) { - if (!(flags & MDBX_EXCLUSIVE)) - return ERROR_REMOTE_STORAGE_MEDIA_ERROR; + if (!(flags & MDBX_EXCLUSIVE)) { + rc = ERROR_REMOTE_STORAGE_MEDIA_ERROR; + goto bailout; + } } else if (mdbx_GetFinalPathNameByHandleW(handle, PathBuffer, INT16_MAX, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS)) { UINT DriveType = GetDriveTypeW(PathBuffer); if (DriveType == DRIVE_NO_ROOT_DIR && - wcsncmp(PathBuffer, L"\\\\?\\", 4) == 0 && - wcsncmp(PathBuffer + 5, L":\\", 2) == 0) { + _wcsnicmp(PathBuffer, L"\\\\?\\", 4) == 0 && + _wcsnicmp(PathBuffer + 5, L":\\", 2) == 0) { PathBuffer[7] = 0; DriveType = GetDriveTypeW(PathBuffer + 4); } @@ -837,7 +888,7 @@ int mdbx_check4nonlocal(mdbx_filehandle_t handle, int flags) { case DRIVE_REMOTE: default: if (!(flags & MDBX_EXCLUSIVE)) - return ERROR_REMOTE_STORAGE_MEDIA_ERROR; + rc = ERROR_REMOTE_STORAGE_MEDIA_ERROR; // fall through case DRIVE_REMOVABLE: case DRIVE_FIXED: @@ -845,6 +896,9 @@ int mdbx_check4nonlocal(mdbx_filehandle_t handle, int flags) { break; } } + bailout: + mdbx_free(PathBuffer); + return rc; } #else (void)handle; @@ -1019,11 +1073,11 @@ int mdbx_mresize(int flags, mdbx_mmap_t *map, size_t size, size_t limit) { &ReservedSize, MEM_RESERVE, PAGE_NOACCESS); if (!NT_SUCCESS(status)) { ReservedAddress = NULL; - if (status != /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018 || - limit == map->length) + if (status != /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018) goto bailout_ntstatus /* no way to recovery */; - /* assume we can change base address if mapping size changed */ + /* assume we can change base address if mapping size changed or prev address + * couldn't be used */ map->address = NULL; } @@ -1080,8 +1134,8 @@ retry_mapview:; if (!NT_SUCCESS(status)) { if (status == /* STATUS_CONFLICTING_ADDRESSES */ 0xC0000018 && - map->address && limit != map->length) { - /* try remap at another base address, but only if the limit is changing */ + map->address) { + /* try remap at another base address */ map->address = NULL; goto retry_mapview; } diff --git a/libs/libmdbx/src/src/osal.h b/libs/libmdbx/src/src/osal.h index 065128103e..50416d960c 100644 --- a/libs/libmdbx/src/src/osal.h +++ b/libs/libmdbx/src/src/osal.h @@ -28,10 +28,16 @@ #pragma warning(disable : 4577) /* 'noexcept' used with no exception handling \ * mode specified; termination on exception is \ * not guaranteed. Specify /EHsc */ +#endif /* _MSC_VER (warnings) */ + +#if defined(_WIN32) || defined(_WIN64) #if !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS #endif -#endif /* _MSC_VER (warnings) */ +#if !defined(_NO_CRT_STDIO_INLINE) && defined(MDBX_BUILD_DLL) +#define _NO_CRT_STDIO_INLINE +#endif +#endif /* Windows */ /*----------------------------------------------------------------------------*/ /* C99 includes */ @@ -84,7 +90,47 @@ typedef struct { HANDLE event; } mdbx_condmutex_t; typedef CRITICAL_SECTION mdbx_fastmutex_t; + +#ifdef MDBX_AVOID_CRT +#ifndef mdbx_malloc +static inline void *mdbx_malloc(size_t bytes) { + return LocalAlloc(LMEM_FIXED, bytes); +} +#endif /* mdbx_malloc */ + +#ifndef mdbx_calloc +static inline void *mdbx_calloc(size_t nelem, size_t size) { + return LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, nelem * size); +} +#endif /* mdbx_calloc */ + +#ifndef mdbx_realloc +static inline void *mdbx_realloc(void *ptr, size_t bytes) { + return LocalReAlloc(ptr, bytes, LMEM_MOVEABLE); +} +#endif /* mdbx_realloc */ + +#ifndef mdbx_free +#define mdbx_free LocalFree +#endif /* mdbx_free */ #else +#define mdbx_malloc malloc +#define mdbx_calloc calloc +#define mdbx_realloc realloc +#define mdbx_free free +#define mdbx_strdup _strdup +#endif /* MDBX_AVOID_CRT */ + +#ifndef snprintf +#define snprintf _snprintf /* ntdll */ +#endif + +#ifndef vsnprintf +#define vsnprintf _vsnprintf /* ntdll */ +#endif + +#else /*----------------------------------------------------------------------*/ + #include <pthread.h> #include <signal.h> #include <sys/file.h> @@ -103,6 +149,11 @@ typedef struct { pthread_cond_t cond; } mdbx_condmutex_t; typedef pthread_mutex_t mdbx_fastmutex_t; +#define mdbx_malloc malloc +#define mdbx_calloc calloc +#define mdbx_realloc realloc +#define mdbx_free free +#define mdbx_strdup strdup #endif /* Platform */ /* *INDENT-OFF* */ @@ -379,36 +430,14 @@ static __inline void mdbx_invalidate_cache(void *addr, size_t nbytes) { /*----------------------------------------------------------------------------*/ /* libc compatibility stuff */ -#ifndef mdbx_assert_fail -void mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func, - int line); -#endif /* mdbx_assert_fail */ - #if __GLIBC_PREREQ(2, 1) #define mdbx_asprintf asprintf +#define mdbx_vasprintf vasprintf #else -int mdbx_asprintf(char **strp, const char *fmt, ...); -#endif - -#ifdef _MSC_VER - -#ifndef snprintf -#define snprintf(buffer, buffer_size, format, ...) \ - _snprintf_s(buffer, buffer_size, _TRUNCATE, format, __VA_ARGS__) -#endif /* snprintf */ - -#ifndef vsnprintf -#define vsnprintf(buffer, buffer_size, format, args) \ - _vsnprintf_s(buffer, buffer_size, _TRUNCATE, format, args) -#endif /* vsnprintf */ - -#ifdef _ASSERTE -#undef assert -#define assert _ASSERTE +__printf_args(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...); +int mdbx_vasprintf(char **strp, const char *fmt, va_list ap); #endif -#endif /* _MSC_VER */ - /*----------------------------------------------------------------------------*/ /* OS abstraction layer stuff */ @@ -428,13 +457,9 @@ static __inline size_t mdbx_syspagesize(void) { #endif } -static __inline char *mdbx_strdup(const char *str) { -#ifdef _MSC_VER - return _strdup(str); -#else - return strdup(str); +#ifndef mdbx_strdup +LIBMDBX_API char *mdbx_strdup(const char *str); #endif -} static __inline int mdbx_get_errno(void) { #if defined(_WIN32) || defined(_WIN64) @@ -445,8 +470,12 @@ static __inline int mdbx_get_errno(void) { return rc; } +#ifndef mdbx_memalign_alloc int mdbx_memalign_alloc(size_t alignment, size_t bytes, void **result); +#endif +#ifndef mdbx_memalign_free void mdbx_memalign_free(void *ptr); +#endif int mdbx_condmutex_init(mdbx_condmutex_t *condmutex); int mdbx_condmutex_lock(mdbx_condmutex_t *condmutex); @@ -564,14 +593,12 @@ int mdbx_rpid_set(MDBX_env *env); int mdbx_rpid_clear(MDBX_env *env); #if defined(_WIN32) || defined(_WIN64) -typedef struct MDBX_srwlock { - union { - struct { - long volatile readerCount; - long volatile writerCount; - }; - RTL_SRWLOCK native; +typedef union MDBX_srwlock { + struct { + long volatile readerCount; + long volatile writerCount; }; + RTL_SRWLOCK native; } MDBX_srwlock; typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *); @@ -652,6 +679,7 @@ static __inline uint32_t mdbx_atomic_add32(volatile uint32_t *p, uint32_t v) { return __sync_fetch_and_add(p, v); #else #ifdef _MSC_VER + STATIC_ASSERT(sizeof(volatile long) == sizeof(volatile uint32_t)); return _InterlockedExchangeAdd((volatile long *)p, v); #endif #ifdef __APPLE__ @@ -692,7 +720,8 @@ static __inline bool mdbx_atomic_compare_and_swap32(volatile uint32_t *p, return __sync_bool_compare_and_swap(p, c, v); #else #ifdef _MSC_VER - return c == _InterlockedCompareExchange((volatile long*)p, v, c); + STATIC_ASSERT(sizeof(volatile long) == sizeof(volatile uint32_t)); + return c == _InterlockedCompareExchange((volatile long *)p, v, c); #endif #ifdef __APPLE__ return c == OSAtomicCompareAndSwap32Barrier(c, v, (volatile int32_t *)p); diff --git a/libs/libmdbx/src/src/tools/mdbx_chk.c b/libs/libmdbx/src/src/tools/mdbx_chk.c index ddaff0ab4b..6614bdb219 100644 --- a/libs/libmdbx/src/src/tools/mdbx_chk.c +++ b/libs/libmdbx/src/src/tools/mdbx_chk.c @@ -1,4 +1,4 @@ -/* mdbx_chk.c - memory-mapped database check tool */ +/* mdbx_chk.c - memory-mapped database check tool */ /* * Copyright 2015-2018 Leonid Yuriev <leo@yuriev.ru> @@ -141,12 +141,12 @@ static void static void pagemap_cleanup(void) { for (int i = CORE_DBS; ++i < MAX_DBI;) { if (walk.dbi[i].name) { - free((void *)walk.dbi[i].name); + mdbx_free((void *)walk.dbi[i].name); walk.dbi[i].name = NULL; } } - free(walk.pagemap); + mdbx_free(walk.pagemap); walk.pagemap = NULL; } @@ -164,7 +164,7 @@ static walk_dbi_t *pagemap_lookup_dbi(const char *dbi_name, bool silent) { return NULL; } - dbi->name = strdup(dbi_name); + dbi->name = mdbx_strdup(dbi_name); if (verbose > 1 && !silent) { print(" - found '%s' area\n", dbi_name); fflush(NULL); @@ -190,7 +190,7 @@ static void break; if (!p) { - p = calloc(1, sizeof(*p)); + p = mdbx_calloc(1, sizeof(*p)); p->caption = msg; p->pr_next = problems_list; problems_list = p; @@ -233,7 +233,7 @@ static uint64_t problems_pop(struct problem *list) { count += problems_list->count; print("%s%s (%" PRIu64 ")", i ? ", " : "", problems_list->caption, problems_list->count); - free(problems_list); + mdbx_free(problems_list); problems_list = p; } print("\n"); @@ -497,13 +497,13 @@ static int handle_maindb(const uint64_t record_number, const MDBX_val *key, return handle_userdb(record_number, key, data); } - name = malloc(key->iov_len + 1); + name = mdbx_malloc(key->iov_len + 1); memcpy(name, key->iov_base, key->iov_len); name[key->iov_len] = '\0'; userdb_count++; rc = process_db(~0u, name, handle_userdb, false); - free(name); + mdbx_free(name); if (rc != MDBX_INCOMPATIBLE) return rc; @@ -1093,7 +1093,7 @@ int main(int argc, char *argv[]) { print("Traversal b-tree by txn#%" PRIaTXN "...\n", txn->mt_txnid); fflush(NULL); - walk.pagemap = calloc((size_t)lastpgno, sizeof(*walk.pagemap)); + walk.pagemap = mdbx_calloc((size_t)lastpgno, sizeof(*walk.pagemap)); if (!walk.pagemap) { rc = errno ? errno : MDBX_ENOMEM; error("calloc failed, error %d %s\n", rc, mdbx_strerror(rc)); diff --git a/libs/libmdbx/src/src/tools/mdbx_chk.vcxproj b/libs/libmdbx/src/src/tools/mdbx_chk.vcxproj index d4cc420d36..e6c2686286 100644 --- a/libs/libmdbx/src/src/tools/mdbx_chk.vcxproj +++ b/libs/libmdbx/src/src/tools/mdbx_chk.vcxproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="Debug|Win32"> diff --git a/libs/libmdbx/src/src/tools/mdbx_copy.vcxproj b/libs/libmdbx/src/src/tools/mdbx_copy.vcxproj index 6910060fcb..d47513c204 100644 --- a/libs/libmdbx/src/src/tools/mdbx_copy.vcxproj +++ b/libs/libmdbx/src/src/tools/mdbx_copy.vcxproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="Debug|Win32"> diff --git a/libs/libmdbx/src/src/tools/mdbx_dump.c b/libs/libmdbx/src/src/tools/mdbx_dump.c index c854e0ad15..d16215622e 100644 --- a/libs/libmdbx/src/src/tools/mdbx_dump.c +++ b/libs/libmdbx/src/src/tools/mdbx_dump.c @@ -203,7 +203,8 @@ int main(int argc, char *argv[]) { break; case 'f': if (freopen(optarg, "w", stdout) == NULL) { - fprintf(stderr, "%s: %s: reopen: %s\n", prog, optarg, strerror(errno)); + fprintf(stderr, "%s: %s: reopen: %s\n", prog, optarg, + mdbx_strerror(errno)); exit(EXIT_FAILURE); } break; @@ -292,7 +293,7 @@ int main(int argc, char *argv[]) { if (memchr(key.iov_base, '\0', key.iov_len)) continue; count++; - str = malloc(key.iov_len + 1); + str = mdbx_malloc(key.iov_len + 1); memcpy(str, key.iov_base, key.iov_len); str[key.iov_len] = '\0'; rc = mdbx_dbi_open(txn, str, 0, &db2); @@ -307,7 +308,7 @@ int main(int argc, char *argv[]) { } mdbx_dbi_close(env, db2); } - free(str); + mdbx_free(str); if (rc) continue; } diff --git a/libs/libmdbx/src/src/tools/mdbx_dump.vcxproj b/libs/libmdbx/src/src/tools/mdbx_dump.vcxproj index b44eb19328..6978a2c22d 100644 --- a/libs/libmdbx/src/src/tools/mdbx_dump.vcxproj +++ b/libs/libmdbx/src/src/tools/mdbx_dump.vcxproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="Debug|Win32"> diff --git a/libs/libmdbx/src/src/tools/mdbx_load.c b/libs/libmdbx/src/src/tools/mdbx_load.c index a18b50c491..697e3e166f 100644 --- a/libs/libmdbx/src/src/tools/mdbx_load.c +++ b/libs/libmdbx/src/src/tools/mdbx_load.c @@ -110,8 +110,8 @@ static void readhdr(void) { if (ptr) *ptr = '\0'; if (subname) - free(subname); - subname = strdup((char *)dbuf.iov_base + STRLENOF("database=")); + mdbx_free(subname); + subname = mdbx_strdup((char *)dbuf.iov_base + STRLENOF("database=")); } else if (!strncmp(dbuf.iov_base, "type=", STRLENOF("type="))) { if (strncmp((char *)dbuf.iov_base + STRLENOF("type="), "btree", STRLENOF("btree"))) { @@ -237,7 +237,7 @@ static int readline(MDBX_val *out, MDBX_val *buf) { /* Is buffer too short? */ while (c1[len - 1] != '\n') { - buf->iov_base = realloc(buf->iov_base, buf->iov_len * 2); + buf->iov_base = mdbx_realloc(buf->iov_base, buf->iov_len * 2); if (!buf->iov_base) { Eof = 1; fprintf(stderr, "%s: line %" PRIiSIZE ": out of memory, line too long\n", @@ -340,7 +340,8 @@ int main(int argc, char *argv[]) { break; case 'f': if (freopen(optarg, "r", stdin) == NULL) { - fprintf(stderr, "%s: %s: reopen: %s\n", prog, optarg, strerror(errno)); + fprintf(stderr, "%s: %s: reopen: %s\n", prog, optarg, + mdbx_strerror(errno)); exit(EXIT_FAILURE); } break; @@ -348,7 +349,7 @@ int main(int argc, char *argv[]) { envflags |= MDBX_NOSUBDIR; break; case 's': - subname = strdup(optarg); + subname = mdbx_strdup(optarg); break; case 'N': putflags = MDBX_NOOVERWRITE | MDBX_NODUPDATA; @@ -378,7 +379,7 @@ int main(int argc, char *argv[]) { #endif /* !WINDOWS */ dbuf.iov_len = 4096; - dbuf.iov_base = malloc(dbuf.iov_len); + dbuf.iov_base = mdbx_malloc(dbuf.iov_len); if (!(mode & NOHDR)) readhdr(); @@ -418,7 +419,7 @@ int main(int argc, char *argv[]) { } kbuf.iov_len = mdbx_env_get_maxkeysize(env) * 2 + 2; - kbuf.iov_base = malloc(kbuf.iov_len); + kbuf.iov_base = mdbx_malloc(kbuf.iov_len); while (!Eof) { if (user_break) { diff --git a/libs/libmdbx/src/src/tools/mdbx_load.vcxproj b/libs/libmdbx/src/src/tools/mdbx_load.vcxproj index 6af6cc457c..05a100fc64 100644 --- a/libs/libmdbx/src/src/tools/mdbx_load.vcxproj +++ b/libs/libmdbx/src/src/tools/mdbx_load.vcxproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="Debug|Win32"> diff --git a/libs/libmdbx/src/src/tools/mdbx_stat.c b/libs/libmdbx/src/src/tools/mdbx_stat.c index a219b9ec0e..95a6cdd23c 100644 --- a/libs/libmdbx/src/src/tools/mdbx_stat.c +++ b/libs/libmdbx/src/src/tools/mdbx_stat.c @@ -356,13 +356,13 @@ int main(int argc, char *argv[]) { MDBX_dbi db2; if (memchr(key.iov_base, '\0', key.iov_len)) continue; - str = malloc(key.iov_len + 1); + str = mdbx_malloc(key.iov_len + 1); memcpy(str, key.iov_base, key.iov_len); str[key.iov_len] = '\0'; rc = mdbx_dbi_open(txn, str, 0, &db2); if (rc == MDBX_SUCCESS) printf("Status of %s\n", str); - free(str); + mdbx_free(str); if (rc) continue; rc = mdbx_dbi_stat(txn, db2, &mst, sizeof(mst)); diff --git a/libs/libmdbx/src/src/tools/mdbx_stat.vcxproj b/libs/libmdbx/src/src/tools/mdbx_stat.vcxproj index 1adcefde89..4027491d39 100644 --- a/libs/libmdbx/src/src/tools/mdbx_stat.vcxproj +++ b/libs/libmdbx/src/src/tools/mdbx_stat.vcxproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="Debug|Win32"> diff --git a/libs/libmdbx/src/src/tools/wingetopt.c b/libs/libmdbx/src/src/tools/wingetopt.c index 6ed6dc3cc8..7feb223fc1 100644 --- a/libs/libmdbx/src/src/tools/wingetopt.c +++ b/libs/libmdbx/src/src/tools/wingetopt.c @@ -55,7 +55,7 @@ char *optarg; int getopt(int argc, char *const argv[], const char *opts) { static int sp = 1; int c; - char *cp; + const char *cp; if (sp == 1) { if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') @@ -66,7 +66,7 @@ int getopt(int argc, char *const argv[], const char *opts) { } } optopt = c = argv[optind][sp]; - if (c == ':' || (cp = (char *)strchr(opts, c)) == NULL) { + if (c == ':' || (cp = strchr(opts, c)) == NULL) { ERR(": illegal option -- ", c); if (argv[optind][++sp] == '\0') { optind++; |