Gwinel / gperftools

Automatically exported from code.google.com/p/gperftools
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

TCMalloc crash in Release with VS2013 #577

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Open gperftools.sln in VS2013
2. Compile release config with platform toolset v120
3. Observe that all unittests are crashing

What is the expected output? What do you see instead?

What version of the product are you using? On what operating system?
GPerfTools-2.1, Win 7 Pro x64

Please provide any additional information below.
Unittests seem to work well in debug. If I switch to platform toolset v100, 
everything works OK in release also.

Seems to be similar to issue 511 ( 
https://code.google.com/p/gperftools/issues/detail?id=511 ), as it is crashing 
during the patching operations.

Original issue reported on code.google.com by shaun.bu...@immersaview.com on 27 Sep 2013 at 6:36

GoogleCodeExporter commented 9 years ago
As soon as I have access to Visual Studio Express 2013 I will be able to look 
at this.

Or I can try help you to look at this.

So first thing is to identify which function patching fails. You can figure it 
out by stepping in debugger.

Once problematic function is identified we'll need to understand why exactly it 
failed. And in order to do that VS's disasm window can be used, which can be 
pointed at address we're trying to patch.

Original comment by alkondratenko on 29 Sep 2013 at 2:42

GoogleCodeExporter commented 9 years ago
I've tried to gather as much information for you as possible this morning, 
please find below my findings.

Cause of the crash is gperftools failing to patch the main executables 
'expand_base' function found within expand.c
void * __cdecl _expand_base (void * pBlock, size_t newsize)

What is interesting to note is that during a separate DLLs patching process, 
this function is successfully patched to the gperftools function - so during 
the main executables patching process, it encounters this function which has 
already been patched.

The disasm of the function during the call to patch the main executable is:

void * __cdecl _expand_base (void * pBlock, size_t newsize)
{
743C05F9  jmp         `anonymous 
namespace'::LibcInfoWithPatchFunctions<1>::Perftools__expand (5B0683B0h)  

It is worthwhile mentioning at this point that the jmp command in this case is 
a E9 opcode jump.

So at this point, everything seems like it should be working except the 
patching function is being provided a different address to patch (it's actually 
a pointer to a mid-point of another function call that just so happens to have 
a return statement).

This suggested that the problem has occurred before the patching process, so I 
found a fancy function called PreamblePatcher::ResolveTargetImpl that from my 
understanding follows the jmp calls until it gets to the necessary function 
that will be performing the actual operation, which is the point where 
gperftools will patch.
The issue with PreamblePatcher::ResolveTargetImpl is it successfully finds the 
_expand_base function (which has already been patched, as per above) but it 
resolves the target address incorrectly.

The target code which I think is the root of the issue is the following inside 
PreamblePatcher::ResolveTargetImpl (line 95):

if (target[0] == ASM_JMP32REL) {
      // target[1-4] holds the place the jmp goes to, but it's
      // relative to the next instruction.
      int relative_offset;   // Windows guarantees int is 4 bytes
      SIDESTEP_ASSERT(sizeof(relative_offset) == 4);
      memcpy(reinterpret_cast<void*>(&relative_offset),
             reinterpret_cast<void*>(target + 1), 4);
      new_target = target + 5 + relative_offset;
    }

This will successfully detect the E9 jmp but looking at the memory for the 
address I was left confused:
0x743C05F9  e9 b2 7d ca e6 cc cc 85 ff 75 17 e8 13 14 f7 ff c7 00 16 00 00 00 e8

So following that relative jmp instruction to the appropriate point in memory I 
was left with a address that wasn't a valid pointer, I've obviously done 
something incorrectly I think as the disasm correctly resolves the instruction 
(as you saw above), but none the less the PreamblePatcher::ResolveTargetImpl 
also incorrectly resolved this address (it returns 0x5C2283B0, where as the 
correct pointer to return should have been 0x5B0683B0 as per the disasm).

Hopefully this information is enough for you to go off, I've had to stop 
debugging for the time being as a urgent task has come up. I'll try to get back 
to debugging more when I can.

Original comment by shaun.bu...@immersaview.com on 30 Sep 2013 at 1:45

GoogleCodeExporter commented 9 years ago
What if _expand_base is actually broken in msvc2013 ?

Can you try some small program that uses it without gperftools ?

Original comment by alkondratenko on 13 Oct 2013 at 2:38

GoogleCodeExporter commented 9 years ago
With recent visual studio 2013 express I'm not seeing this problem.

Original comment by alkondratenko on 5 Jan 2014 at 9:07