c++winapiconstructorx86default-constructor

Could an implicit compiler created default constructor have more than a null body?


Could an implicit compiler created default constructor have more than a null body? According to IBM's website, the answer is: no.

I have this project that's kind of stumping me though:

This is where an instance of a class called StackWalkerToConsole with no defined default constructor gets declared:

void func5()
{
  StackWalkerToConsole sw;
  ...
}

This somehow causes one of the user-defined constructors of its parent class to get called:

StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess)
{
  // The function has a body, I just removed it for clarity's sake.
  ...
}

So I put a breakpoint on this constructor, and using the callstack I looked at the default constructor for StackWalkerToConsole. Since it's not defined in the source code, I could only look at its dissassembly:

StackWalker_VC2017.exe!StackWalkerToConsole::StackWalkerToConsole(void):
0000000140008210  mov         qword ptr [rsp+8],rcx  
0000000140008215  push        rdi  
0000000140008216  sub         rsp,40h  
000000014000821A  call        qword ptr [__imp_GetCurrentProcess (014012E060h)]  
0000000140008220  mov         qword ptr [rsp+30h],rax  
0000000140008225  call        qword ptr [__imp_GetCurrentProcessId (014012E068h)]  
000000014000822B  mov         rcx,qword ptr [rsp+30h]  
0000000140008230  mov         qword ptr [rsp+20h],rcx  
0000000140008235  mov         r9d,eax  
0000000140008238  xor         r8d,r8d  
000000014000823B  mov         edx,3Fh  
0000000140008240  mov         rcx,qword ptr [this]
  
0000000140008245  call        StackWalker::StackWalker (0140002F1Dh)  

000000014000824A  mov         rax,qword ptr [this]  
000000014000824F  lea         rcx,[StackWalkerToConsole::`vftable' (01400ED6C0h)]  
0000000140008256  mov         qword ptr [rax],rcx  
0000000140008259  mov         rax,qword ptr [this]  
000000014000825E  add         rsp,40h  
0000000140008262  pop         rdi 

This compiler defined constructor is calling 2 WinApi functions: GetCurrentProcess and GetCurrentProcessId and calling the user-defined constructor for StackWalker.

Does anyone know why this is? I should mention, the parent class StackWalker does not have any user defined default constructors either.

If further information is required I'd be glad to supply it. Thank you for reading this far.

Edit: This is the github for the code: It's a tiny project, just 1 cpp file and 1 main.cpp file to test it. I'm assuming no one has the time and energy to go through the code, but putting it in here just in case.

In the post I'm referencing Line 41 from main.cpp and Line 929 from StackWalker.cpp


Solution

  • The class you've referenced:

    class StackWalkerToConsole : public StackWalker
    {
    protected:
      virtual void OnOutput(LPCSTR szText) { printf("%s", szText); }
    };
    

    Has an implicitly-declared default constructor that looks similar to this:

    StackWalkerToConsole::StackWalkerToConsole() : StackWalker() {}
    

    Which calls this constructor of StackWalker:

      StackWalker(int    options = OptionsAll,
                  LPCSTR szSymPath = NULL,
                  DWORD  dwProcessId = GetCurrentProcessId(),
                  HANDLE hProcess = GetCurrentProcess());
    

    (StackWalker does have a user-defined default constructor, it's this one that can be called with zero arguments)

    So while there's no body of StackWalkerToConsole's default constructor, its base class is initialized using the default arguments StackWalker(OptionsAll, NULL, GetCurrentProcessId(), GetCurrentProcess()) and the body of the StackWalker constructor is run.