Instantiation of QAxObject generated by dumpcpp segfault with minGw C++ -o2 or -o3 flag
-
Qt version: 5.12.10, Mingw version 7.3.0 32bit for C++
I wanted to interface with an application using the COM layer, this application was delivered with a .tlb file so I used Qt's dumpcpp to generate header and source file.
To use the generated class, I first get an IUnknown from windows ROT and then instantiate the classes I need from a class I used an interface.
My code looks like this :
Code instantiating my class:
//Initialize COM, load the ROT, get the monikers and for each monikers //Check if the monikers name is the one we want if (!wcsncmp(monikerDisplayName, appComIdentifier, wcslen(appComIdentifier))) { qDebug() << "Found app"; IUnknown *currentObject = nullptr; if (rot->GetObject(currentMoniker, ¤tObject) == S_OK) { AppCommunication appCom(static_cast<app::IApplicationInterface *>(new QAxObject(currentObject))); // Use the class instance with some method calls } }
The AppCommunication class:
Header file:
class AppCommunication : public IAppCommunication { public: AppCommunication(app::IApplicationInterface *applicationInterface); ~AppCommunication() override = default; private: app::appApplication appApplication; app::appJob appJob; };
cpp file:
AppCommunication::AppCommunication(app::IApplicationInterface *applicationInterface) : appApplication(applicationInterface), appJob(static_cast<app::IJobInterface *>(new QAxObject(appApplication.CreateJobObject()))) // ^ // | // Segfault here { }
All the classes under the app namespace are the ones generated by the dumpcpp tool.
This works perfectly fine with the optimization flags -o0 or -o1 in the compiler but when I set -o2 or -o3 my program crashes.
From what I could trace this is the instantiation of the appJob (not the fetching of the JobInterface) that causes the crash.
I consider Qt's code and Qt's generated code to be robust/validated enough so I think this error must be me having an undefined behaviour. But I can not see what I did wrong here.
When I try to use gdb integrated with Qt I get "SIGSEGV signal received" and with dr memory "UNADRESSABLE ACCESS: executing 0x00000000-0x00000001 1byte(s) #0 <not in a module> (0x00000000)"
I managed to find a way to avoid the issue. What I have found is that if I use a pointer instead of the class by itself it works fine:
Header file:
class AppCommunication : public IAppCommunication { public: AppCommunication(app::IApplicationInterface *applicationInterface); ~AppCommunication() override = default; private: app::appApplication appApplication; app::appJob *appJob; };
cpp file:
AppCommunication::AppCommunication(app::IApplicationInterface *applicationInterface) : appApplication(applicationInterface), appJob(new app::appJob(static_cast<app::IJobInterface *>(new QAxObject(appApplication.CreateJobObject())))) { }
And this also work with a unique_ptr instead of the raw pointer so this is the route I will take.
I am not a huge fan of using a pointer instead of the base class just because It does not crash with O2 and I would love to understant what I did wrong but I can not figure where my mistake is (honestly I am starting to think it might be a compiler issue...)
-
The mistake was on me.
After getting the IUnknown * from the COM, we have to get a IDispatch * from it and then instantiate directly the classes:
//Initialize COM, load the ROT, get the monikers and for each monikers //Check if the monikers name is the one we want if (!wcsncmp(monikerDisplayName, appComIdentifier, wcslen(appComIdentifier))) { qDebug() << "Found app"; IUnknown *currentObject = nullptr; if (rot->GetObject(currentMoniker, ¤tObject) == S_OK) { //Add the get dispatch part IDispatch *currentObjectDispatch = nullptr; HRESULT hr = currentObject->QueryInterface(IID_IDispatch, (void **)¤tObjectDispatch); if (FAILED(hr)) { return; } //Get the interface directly without static cast AppCommunication appCom(new app::IApplicationInterface(currentObject)); // Use the class instance with some method calls } }
And do the same on the class we retrieve in the ctor:
AppCommunication::AppCommunication(app::IApplicationInterface *applicationInterface) : appApplication(applicationInterface), appJob(new app::IJobInterface(appApplication.CreateJobObject())) { }