greg7mdp/parallel-hashmap

double free

Closed this issue · 11 comments

Eventually I have checked this error case:
SYMBOL_NAME: ucrtbase!_free_base+0
MODULE_NAME: ucrtbase
IMAGE_NAME: ucrtbase.dll
FAILURE_BUCKET_ID: HEAP_CORRUPTION_ACTIONABLE_BlockNotBusy_DOUBLE_FREE_c0000374_ucrtbase.dll!_free_base
OS_VERSION: 6.3.9600.18217

The stacktrace show this:

ChildEBP RetAddr

00 02278970 77d08aa8 ntdll!RtlReportCriticalFailure+0x83
01 02278980 77d09359 ntdll!RtlpHeapHandleError+0x1c
02 022789b0 77ca5f2d ntdll!RtlpLogHeapFailure+0xa1
03 02278a08 74b5078b ntdll!RtlFreeHeap+0x4467d
04 02278a1c 74b50758 ucrtbase!_free_base+0x1b
05 02278a2c 00272023 ucrtbase!free+0x18
06 02278a38 00246a59 mymodule!operator delete+0xb [d:\agent_work\3\s\src\vctools\crt\vcstartup\src\heap\delete_scalar_size.cpp @ 31]
07 (Inline) -------- mymodule!std::_Deallocate+0x25 [c:\program files (x86)\microsoft visual studio\2017\buildtools\vc\tools\msvc\14.16.27023\include\xmemory0 @ 207]
08 (Inline) -------- mymodule!std::allocator<phmap::priv::Deallocate<4,std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,unsigned long> > >'::2'::M>::deallocate+0x28 [c:\program files (x86)\microsoft visual studio\2017\buildtools\vc\tools\msvc\14.16.27023\include\xmemory0 @ 992]
09 (Inline) -------- mymodule!phmap::allocator_traits<std::allocator<phmap::priv::Deallocate<4,std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,unsigned long> > >'::2'::M> >::deallocate+0x28 [my_buid_server\servico\mymodule\pgm\mymodule_parallel_hashmap\phmap_base.h @ 1483]
0a (Inline) -------- mymodule!phmap::priv::Deallocate+0x2e [my_buid_server\servico\mymodule\pgm\mymodule_parallel_hashmap\phmap_base.h @ 4374]
0b 02278a74 0020d37b mymodule!phmap::priv::raw_hash_set<phmap::priv::FlatHashMapPolicy<std::basic_string<char,std::char_traits,std::allocator >,unsigned long>,phmap::Hash<std::basic_string<char,std::char_traits,std::allocator > >,phmap::EqualTo<std::basic_string<char,std::char_traits,std::allocator > >,std::allocator<std::pair<std::basic_string<char,std::char_traits,std::allocator > const ,unsigned long> > >::resize+0x219 [my_buid_server\servico\mymodule\pgm\mymodule_parallel_hashmap\phmap.h @ 2033]
0c (Inline) -------- mymodule!phmap::priv::raw_hash_set<phmap::priv::FlatHashMapPolicy<std::basic_string<char,std::char_traits,std::allocator >,unsigned long>,phmap::Hash<std::basic_string<char,std::char_traits,std::allocator > >,phmap::EqualTo<std::basic_string<char,std::char_traits,std::allocator > >,std::allocator<std::pair<std::basic_string<char,std::char_traits,std::allocator > const ,unsigned long> > >::prepare_insert+0x59 [my_buid_server\servico\mymodule\pgm\mymodule_parallel_hashmap\phmap.h @ 2201]
0d 02278ae0 0020d1ef mymodule!phmap::priv::raw_hash_set<phmap::priv::FlatHashMapPolicy<std::basic_string<char,std::char_traits,std::allocator >,unsigned long>,phmap::Hash<std::basic_string<char,std::char_traits,std::allocator > >,phmap::EqualTo<std::basic_string<char,std::char_traits,std::allocator > >,std::allocator<std::pair<std::basic_string<char,std::char_traits,std::allocator > const ,unsigned long> > >::find_or_prepare_insert<std::basic_string<char,std::char_traits,std::allocator > >+0x17b [my_buid_server\servico\mymodule\pgm\mymodule_parallel_hashmap\phmap.h @ 2188]
0e 02278b18 00209b7c mymodule!phmap::priv::raw_hash_set<phmap::priv::FlatHashMapPolicy<std::basic_string<char,std::char_traits,std::allocator >,unsigned long>,phmap::Hash<std::basic_string<char,std::char_traits,std::allocator > >,phmap::EqualTo<std::basic_string<char,std::char_traits,std::allocator > >,std::allocator<std::pair<std::basic_string<char,std::char_traits,std::allocator > const ,unsigned long> > >::find_or_prepare_insert<std::basic_string<char,std::char_traits,std::allocator > >+0x4f [my_buid_server\servico\mymodule\pgm\mymodule_parallel_hashmap\phmap.h @ 2193]
0f (Inline) -------- mymodule!phmap::priv::raw_hash_map<phmap::priv::FlatHashMapPolicy<std::basic_string<char,std::char_traits,std::allocator >,unsigned long>,phmap::Hash<std::basic_string<char,std::char_traits,std::allocator > >,phmap::EqualTo<std::basic_string<char,std::char_traits,std::allocator > >,std::allocator<std::pair<std::basic_string<char,std::char_traits,std::allocator > const ,unsigned long> > >::try_emplace_impl+0x10 [my_buid_server\servico\mymodule\pgm\mymodule_parallel_hashmap\phmap.h @ 2469]
10 (Inline) -------- mymodule!phmap::priv::raw_hash_map<phmap::priv::FlatHashMapPolicy<std::basic_string<char,std::char_traits,std::allocator >,unsigned long>,phmap::Hash<std::basic_string<char,std::char_traits,std::allocator > >,phmap::EqualTo<std::basic_string<char,std::char_traits,std::allocator > >,std::allocator<std::pair<std::basic_string<char,std::char_traits,std::allocator > const ,unsigned long> > >::try_emplace+0x10 [my_buid_server\servico\mymodule\pgm\mymodule_parallel_hashmap\phmap.h @ 2410]
11 02278b44 001c6cfa mymodule!phmap::priv::raw_hash_map<phmap::priv::FlatHashMapPolicy<std::basic_string<char,std::char_traits,std::allocator >,unsigned long>,phmap::Hash<std::basic_string<char,std::char_traits,std::allocator > >,phmap::EqualTo<std::basic_string<char,std::char_traits,std::allocator > >,std::allocator<std::pair<std::basic_string<char,std::char_traits,std::allocator > const ,unsigned long> > >::operator[]<std::basic_string<char,std::char_traits,std::allocator >,phmap::priv::FlatHashMapPolicy<std::basic_string<char,std::char_traits,std::allocator >,unsigned long>,0>+0x2c [my_buid_server\servico\mymodule\pgm\mymodule_parallel_hashmap\phmap.h @ 2448]
12 0228e6d0 770c55a0 mymodule!Cmymodule::mymodule+0x427a [my_buid_server\servico\mymodule\pgm\mymodule.cpp @ 2003]
13 0228e75c 770c58d7 oleaut32!DispCallFunc+0x16f
14 0228ea04 001c2a59 oleaut32!CTypeInfo2::Invoke+0x2f7

The code at line 2003:
phmap_count_users["USU_" + m_user_request] ++;

The process is multithreaded with high concurrency load.

Any suggestions on the problem or direction?

The odds are that there is a problem in your code. If you can provide a sample program reproducing the issue, I can have a look at it.

Thanks Greg, but the code is complex and not reproducible at all.
The failure occurs very rarely and causes no need for investigation at this time.
Thank you for your attention.

phmap_count_users["USU_" + m_user_request] ++;

Oh, you can't do that. The returned reference is not thread safe. If Map is the type of your hash_map, try:

phmap_count_users.try_emplace_l("USU_" + m_user_request,
                     [](Map::value_type& v) { ++v.second; },           // called only when key was already present
                     1); //  argument to construct new value is key not present

BTW, what is the type of phmap_count_users?

Hy, to late...
The type is: flat_hash_map<string, unsigned long>

This form of attribution is widely in my source. It was already this way before he started using your library. Failure occurrences are very rare and notably occur at dawn, when there is low use of the service.

The way of accessing the hash map using a reference is not thread-safe (when the hash map can be modified in another thread), regardless of the hash map you are using. You need to protect this access with a mutex.

Failure occurrences are very rare and notably occur at dawn, when there is low use of the service.

Does something else happen at dawn, like some cleanup of the users of the hash map?

This container never have an cleanup!

I try to use member try_emplace_l, but Visual Studio 2019 shows error:
try_emplace_l

but the source contains the implementation of the routine.

Only the parallel_*_hash_map have try_emplace_l

Ok, I find this... my fault.