Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

invalid heap arg and leak in VS2015 std::ctype #1864

Closed
derekbruening opened this issue Mar 7, 2016 · 2 comments
Closed

invalid heap arg and leak in VS2015 std::ctype #1864

derekbruening opened this issue Mar 7, 2016 · 2 comments

Comments

@derekbruening
Copy link
Contributor

Running a trivial app built with VS2015:

Error #5: INVALID HEAP ARGUMENT to free 0x016a9d58
#0 replace_free                                             [d:\drmemory_package\common\alloc_replace.c:2706]
#1 std::ctype<>::_Tidy                                      [c:\program files (x86)\microsoft visual studio 14.0\vc\include\xlocale:2503]
#2 std::ctype<>::~ctype<>                                   [c:\program files (x86)\microsoft visual studio 14.0\vc\include\xlocale:2492]
#3 std::ctype<>::`scalar deleting destructor'
#4 std::_Fac_node::~_Fac_node                               [f:\dd\vctools\crt\crtw32\stdcpp\locale0.cpp:28]
#5 std::_Fac_tidy_reg_t::~_Fac_tidy_reg_t                   [f:\dd\vctools\crt\crtw32\stdcpp\locale0.cpp:59]
#6 __crt_seh_guarded_call<>::operator()<>                   [d:\th\minkernel\crts\ucrt\devdiv\vcruntime\inc\internal_shared.h:199]
#7 __acrt_lock_and_call<>                                   [d:\th\minkernel\crts\ucrt\inc\corecrt_internal.h:881]
#8 _execute_onexit_table                                    [d:\th\minkernel\crts\ucrt\src\appcrt\startup\onexit.cpp:221]
#9 common_exit                                              [d:\th\minkernel\crts\ucrt\src\appcrt\startup\exit.cpp:215]
#10 exit                                                     [d:\th\minkernel\crts\ucrt\src\appcrt\startup\exit.cpp:282]
#11 __scrt_common_main_seh                                   [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:273]
#12 KERNEL32.dll!BaseThreadInitThunk                        +0x23     (0x744938f4 <KERNEL32.dll+0x138f4>)
Note: @0:00:00.876 in thread 3400
Note: refers to -1 byte(s) before next malloc
Note: next higher malloc: 0x016a9d58-0x016a9f58
Note: refers to -512 byte(s) beyond last valid byte in prior malloc
Note: prev lower malloc:  0x016a9d58-0x016a9f58

Error #6: LEAK 512 direct bytes 0x016a9d58-0x016a9f58 + 0 indirect bytes
#0 replace_RtlAllocateHeap                             [d:\drmemory_package\common\alloc_replace.c:3764]
#1 _calloc_base                                        [d:\th\minkernel\crts\ucrt\src\appcrt\heap\calloc_base.cpp:30]
#2 _Getctype                                           [f:\dd\vctools\crt\crtw32\stdcpp\_tolower.c:140]
#3 std::_Locinfo::_Getctype                            [c:\program files (x86)\microsoft visual studio 14.0\vc\include\xlocinfo:117]
#4 std::ctype<>::_Init                                 [c:\program files (x86)\microsoft visual studio 14.0\vc\include\xlocale:2497]
#5 std::ctype<>::ctype<>                               [c:\program files (x86)\microsoft visual studio 14.0\vc\include\xlocale:2463]
#6 std::ctype<>::_Getcat                               [c:\program files (x86)\microsoft visual studio 14.0\vc\include\xlocale:2470]
#7 std::use_facet<>                                    [c:\program files (x86)\microsoft visual studio 14.0\vc\include\xlocale:570]
#8 std::basic_ios<>::widen                             [c:\program files (x86)\microsoft visual studio 14.0\vc\include\ios:127]
#9 std::basic_ios<>::init                              [f:\dd\vctools\crt\crtw32\stdhpp\ios:170]
#10 std::basic_ostream<>::basic_ostream<>               [f:\dd\vctools\crt\crtw32\stdhpp\ostream:55]
#11 std::`dynamic initializer for 'cout''               [f:\dd\vctools\crt\crtw32\stdcpp\cout.cpp:18]

Xref #1428.
Xref #500 -- "mismatch b/c operator new calls _nh_malloc_dbg"

It's in our own default arena:

% grep 0x01279d5 drmemory/drmemory/logs/DrMemory-buggy.exe.6116.000/global.6116.log 
replace_RtlAllocateHeap heap=0x00790000 (=> 0x01270000) flags=0x8 size=0x200
        carving out new chunk @0x01279d38 => head=0x01279d40, res=0x01279d58
        replace_alloc_common arena=0x01270000 flags=0x804 request=512, align=8 alloc=512 => 0x01279d58
set range 0x01279d58-0x01279f58 => 0x0
replace_free 0x01279d58
ptr_is_in_arena: 0x01279d58 not found in arena 0x01a70000
Error #5: INVALID HEAP ARGUMENT to free 0x01279d58

process heap=0x00790000
create_Rtl_heap commit=0x20000 reserve=0x400000 flags=0x2 => 0x01270000
adding heap region 0x01270000-0x01670000 arena
set heap region 0x01270000-0x01670000 Heap to 0x01270000

pre-existing Heap for libc set type=0 module=buggy.exe is 0x00000000
create_Rtl_heap commit=0x1000 reserve=0x400000 flags=0x2 => 0x01a70000
adding heap region 0x01a70000-0x01e70000 arena
set heap region 0x01a70000-0x01e70000 Heap to 0x01a70000
new default Heap for libc set type=0 @0x012385e3 modbase=0x011b0000 is 0x01a70000

The bug is that it wants to use buggy.exe's libc arena 0x01a70000 on the
free, yet the alloc used the global arena.

Here's more about the alloc:

malloc 0x012f9d58-0x012f9f58
#0 _calloc_base+0x46 [d:\th\minkernel\crts\ucrt\src\appcrt\heap\calloc_base.cpp:30+0xe] (0x0127ba70 <buggy.exe+0x4ba70>) modid:0
#1 _Getctype+0x19 [f:\dd\vctools\crt\crtw32\stdcpp\_tolower.c:140+0xd] (0x0124161a <buggy.exe+0x1161a>) modid:0
#2 std::_Locinfo::_Getctype+0x11 [c:\program files (x86)\microsoft visual studio 14.0\vc\include\xlocinfo:117+0x8] (0x0123ee92 <buggy.exe+0xee92>) modid:0
#3 std::ctype<>::_Init+0x14 [c:\program files (x86)\microsoft visual studio 14.0\vc\include\xlocale:2497+0xb] (0x0123f0c5 <buggy.exe+0xf0c5>) modid:0
#4 std::ctype<>::ctype<>+0x4d [c:\program files (x86)\microsoft visual studio 14.0\vc\include\xlocale:2463+0xb] (0x0123d17e <buggy.exe+0xd17e>) modid:0
#5 std::ctype<>::_Getcat+0x90 [c:\program files (x86)\microsoft visual studio 14.0\vc\include\xlocale:2470+0x4e] (0x0123edf1 <buggy.exe+0xedf1>) modid:0
#6 std::use_facet<>+0x7c [c:\program files (x86)\microsoft visual studio 14.0\vc\include\xlocale:570+0xc] (0x0123cd5d <buggy.exe+0xcd5d>) modid:0
#7 std::basic_ios<>::widen+0x4c [c:\program files (x86)\microsoft visual studio 14.0\vc\include\ios:127+0x24] (0x01240bcd <buggy.exe+0x10bcd>) modid:0
#8 std::basic_ios<>::init+0x1d [f:\dd\vctools\crt\crtw32\stdhpp\ios:170+0xf] (0x0124361f <buggy.exe+0x1361f>) modid:0
#9 std::basic_ostream<>::basic_ostream<>+0x5c [f:\dd\vctools\crt\crtw32\stdhpp\ostream:55+0x27] (0x01242825 <buggy.exe+0x12825>) modid:0
#10 std::`dynamic initializer for 'cout''+0x12 [f:\dd\vctools\crt\crtw32\stdcpp\cout.cpp:18+0x12] (0x0123b29c <buggy.exe+0xb29c>) modid:0
#11 __scrt_common_main_seh+0x7a [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:230+0xe] (0x0126ab1b <buggy.exe+0x3ab1b>) modid:0
#12 KERNEL32.dll!BaseThreadInitThunk+0x23 (0x744938f4 <KERNEL32.dll+0x138f4>) modid:0

calloc_base.cpp:

        void* const block = HeapAlloc(__acrt_heap, HEAP_ZERO_MEMORY, actual_block_size);

heap_handle.cpp:

// Initializes the heap.  This function must be called during CRT startup, and
// must be called before any user code that might use the heap is executed.
extern "C" bool __cdecl __acrt_initialize_heap()
{
    __acrt_heap = GetProcessHeap();

So this is #1223 where VS2012+ use the process heap: we're supposed to wait for the first invocation of malloc.

Yet our first alloc is:

replace_operator_new 0x8
libc_heap_handle: for 0x01230000 func is 0x00000000
sym lookup of _crtheap in C:\derek\cgo2016\demos\buggy.exe => symcache hit 0 of 1 == 0x0
check_libc_vs_process_heap: modbase 0x01230000 arena 0x01af0000 heap 0x00000000
replace_operator_new size=8 abort_on_oom=1 type=8
        carving out new chunk @0x01af00d8 => head=0x01af00e0, res=0x01af00f8
        replace_alloc_common arena=0x01af0000 flags=0x8 request=8, align=8 alloc=8 => 0x01af00f8
@@@ unique callstack #17
#0 replace_operator_new                              [d:\drmemory_package\common\alloc_replace.c:2899]
#1 std::basic_streambuf<>::basic_streambuf<>         [f:\dd\vctools\crt\crtw32\stdhpp\streambuf:26]
#2 std::`dynamic initializer for 'fout''             [f:\dd\vctools\crt\crtw32\stdcpp\cout.cpp:12]
#3 __scrt_common_main_seh                            [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:230]
#4 KERNEL32.dll!BaseThreadInitThunk                 +0x23     (0x744938f4 <KERNEL32.dll+0x138f4>)

So the culprit is: they renamed _crtheap to __acrt_heap.

@derekbruening
Copy link
Contributor Author

And that fixes it (I did not change the logs: they still say "_crtheap"):

sym lookup of _crtheap in C:\derek\cgo2016\demos\buggy.exe => symcache hit 0 of 1 == 0xaea2c
libc_heap_handle: _crtheap @0x012dea2c => 0x00e30000
symcache_symbol_add: ignoring dup entry _crtheap
check_libc_vs_process_heap: modbase 0x01230000 arena 0x01d80000 heap 0x00e30000
replacing arena for modbase 0x01230000 w/ default arena for set 0x012b85e3

@chura-sk
Copy link

chura-sk commented Jun 9, 2022

Hello,

I experience the same issue (invalid heap + leak, at the same address, but pretending "-1") when using vs2017/vs2019 built projects.
Unfortunately I do not have any simple example (it's some omniorb in VS2019 and project in VS2017).
(Dr. Memory version 2.5.0 build 0)

I'm wondering if this can be fixed in some more fundamental way, as it somehow does not make much sense to me that
x - x = -1 is a problem of a symbol mismatch, or so...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants