Using an external DLL in a Qt Project - c++

I have a DLL containing multiple functions that can fastly perform arithmetic operations on extremely large integers. My test program runs smoothly in my Visual Studio 2019, as follows.
int main()
{
HINSTANCE myDDL = LoadLibrary(L".\\BigIntDLL.dll");
typedef string (*func)(string a, string b);
func expBigInt = (func)GetProcAddress(myDDL, "expBigInt");
string y= expBigInt("2", "10000");//it can calculate 2^10000 and return it as a string
cout << y;
}
So, I moved the code directly into my Qt project as a part in widget.cpp, and also placed the BigIntDLL.dll and .lib in the same directory of the project. The compilation was successful, but when debugging my interface, the program broke with a Segmentation fault error due to a call to the expBigInt function.
void Widget::on_expButton_clicked()
{
getTextEditNum();
Output=expBigInt(Input1,Input2);//crashed here
writeResult(Output);
}
I am not really sure where the real problem is, but I now suspect that I have not successfully called the functions in this DLL, causing some memory issues.

Related

C++/CLI project as static library and different behaviour between VS2013 and VS2015

In an app I'm working on (built with Visual Studio 2015), I have the following structure:
Project A -> Native DLL project. This references project B
Project B -> Native static lib project. This references project C.
Project C -> Static lib project with CLR support turned on.
Project A call a function from Project B, which in turn creates an instance of a class from Project C. The instantiated class has a member which is a wrapper around a managed object.
The problem I'm facing is that when I build the code in Release mode, once the code tries to instantiate the class from Project C, it blows up and says that heap has been corrupted. The place where it blows up seems to be the following function from C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\pureMSILcode.cpp
[System::Diagnostics::DebuggerStepThroughAttribute]
_CRT_SECURITYCRITICAL_ATTRIBUTE
int __clrcall _initterm_e (
_PIFV * pfbegin,
_PIFV * pfend
)
{
int ret = 0;
/*
* walk the table of function pointers from the bottom up, until
* the end is encountered. Do not skip the first entry. The initial
* value of pfbegin points to the first valid entry. Do not try to
* execute what pfend points to. Only entries before pfend are valid.
*/
while ( pfbegin < pfend && ret == 0)
{
/*
* if current table entry is non-NULL, call thru it.
*/
if ( *pfbegin != NULL )
ret = (**pfbegin)();
++pfbegin;
}
return ret;
}
Now here is the thing ... If I turn Project C into a DLL (rather than a static lib) everything works fine. What's more interesting is that all this used to work fine when I built the code in Visual Studio 2013. With VS2015, I don't get any heap corruption if I build the code in debug, but it blows up in release.
I'm aware that having CLR support in a static lib is not the best idea, however I can't seem to find any good information about the issues in having CLR support in a static lib. Additionally this was working all fine in VS2013.
I can just change Project C to be a DLL (which makes more sense when having CLR support), however I would like to understand what has caused the current settings to blow up when converting to VS2015.
The following is a close representation of the relevant code from each project:
Project C:
Foo.h
class FooA
{
public:
FooA();
private:
struct FooAImpl;
std::unique_ptr<FooAImpl> _impl;
};
Foo.cpp
struct FooA::FooAImpl
{
gcroot<ManagedFoo^> managedFoo;
FooAImpl(ManagedFoo^ managedFoo_) :
managedFoo(managedFoo_)
{
}
};
FooA::FooA()
{
_impl = std::unique_ptr<FooAImpl>(new FooAImpl(gcnew ManagedFoo()));
}
Project B:
FooB.h
class FooB
{
public:
Result GetResult();
};
FooB.cpp
Result FooB::GetResult()
{
FooA fooA;
Result r = ...;
return r;
}
Project A
FooC.h
class FooC
{
public:
void Bar();
private:
std::unique_ptr<FooB> m_pFooB;
};
FooC.cpp
void FooC::Bar()
{
Result r = m_pFooB->GetResult();
}
Hope someone has some information around what issues may occur in having a static lib with CLR support. Hope the information I provided describes the problem well.

Visual Studio MFC application

I want to create a MFC project in Visual Studio where, on button action to go through various functions(like 'prime'). I don't know where to write these function and also the global variables i need for them(p and flag). I have searched on the internet and tried more methods(like declaring them in .h files and so on, but didn't worked). Take in my mind that i very new to this. Here is my code:
long int p,flag;
void CMFCApplication1Dlg::OnBnClickedClickMe()
{
flag = prime(p);
//more code
}
int prime(long int pr)
{
//code
}

Shared pointer on x86 and ARM

In a shared library (.so) I define a std::shared_ptr to a class object which is returned to the caller accross the library boundary to the main routine which is a Qt5.4 project. There the pointer is used in a if statement. As the bool operation is the last owner of the shared pointer it is deleted after finishing this operation and the destructor is called.
.so file (an Autotools-project):
#define STD_SHARED_PTR std::shared_ptr
#define STD_WEAK_PTR std::weak_ptr
typedef STD_SHARED_PTR<RenderingControl> RDCH;
typedef STD_WEAK_PTR<RenderingControl> WEAK;
class MediaRenderer {
public:
RDCH rdc();
}
class RenderingControl {
public:
RenderingControl();
virtual ~RenderingControl();
}
RenderingControl::RenderingControl() {
...
}
RendeneringControl::~RenderingControl() {
cerr << "Destructor called" << endl;
}
RDCH MediaRenderer::rdc() {
RDCH rdcl = RDCH(new RenderingControl());
long foo = rdcl.use_count();
WEAK rdc = rdcl;
return rdcl;
}
.cpp (a Qt5.4 project):
typedef STD_SHARED_PTR<RenderingControl> MRDH;
MRDH renderer = MRDH(new MediaRenderer());
if (renderer->rdc()) {
...
return;
}
Everything works fine on a x86 machine compiled with either Qt4.8 or Qt5.4. The destructor is called after finishing the if statement. Cross compiled for an ARM (Raspberry Pi 2) using Qt5.4, however, the destructor is not called. If I additionally add use_count() for debugging, it yields 1 in both the .so and the .cpp file on the x86, but 1 in the .so and 0 in the .cpp for the ARM.
If I compile on ARM using Qt4.8 everything is fine on ARM, too. But why does it not work on ARM using Qt5.4?
Thank you!
Obviously, the reason was different versions of libstdc++ I have on the same system for compiling a autotools project and a Qt project. However, even if I solved the problem by converting the library into an Qt project ensuring the use of the same libstdc++ for both parts, I do not understand why there are different versions on the same machine? Is this a specific feature of Qt? Mayby, anybody could explain...

Visual Studio 2010 debugger points to wrong line

The debugger in Visual Studio 2010 is recently pointing at the wrong lines and/or skipping lines and I have no idea why this is. This is a CUDA project and only happens in CUDA files. I've noticed the following:
It always happens at the same part of the program.
The lines it points to are always the same, i.e. not random.
Putting extra code after the culprit lines changes which lines it points to.
It only happens in .cu-files. Moving the code to a .cpp-file does not recreate the problem.
What I have tried:
Clean and rebuilt the solution.
Install SP1 for MSVC10 and do all possible updates via Windows Updates
Set the compiler to not use optimizations in debug mode for both C/C++ and CUDA C/C++
Manually delete all created files and then rebuild from the solution folder.
Deleting the folder C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files
Recreating the solution only using the source files.
Disabling my extensions.
I've managed to reduce the code to the following which might reproduce the problem. Mind that this code has to be inside a .cu-file and most probably needs to be compiled with the cuda compiler for C/C++. Including boost is not really necessary, but this example does show what problems I'm having. A shorter example is at the back.
#include <boost/numeric/ublas/matrix.hpp>
using boost::numeric::ublas::matrix;
struct foo {
foo() : mat(NULL) {}
matrix<float>* mat;
};
bool func(foo *data) {
bool status; // <- skipped line
status = false;
if (status) {
std::cout << "test\n";
return (status); // <- error reported here
}
int size = data->mat->size1(); // instead of here
return status;
}
int main(int args, char* argv[]) {
func(NULL); // force error by passing NULL pointer
return 0;
}
Does anyone have any idea how to solve this or how this could be happening? It's pretty annoying having to debug this way.
Shorter example only showing the skipping lines. No external libraries necessary.
bool func() {
bool status; // <- skipped line
status = false;
return status;
}
int main(int args, char* argv[]) {
func();
return 0;
}
Since the program only contains CPU instructions and variable declarations of types that have no construction contain no instructions, the debugger will not stop there. It just executes instructions and then uses the debugging information that the compiler provided to find the relevant line of source code.

BOOST Unit Test stack overflow

I am now using Boost Unit Test to perform unit test for my project. Every time I run the unit test, I got a memory stack problem. I debug into the source code of BOOST library, and I find that the problem comes from invoking the following codes in unit_test_suite.hpp file:
void
traverse_test_tree( test_unit_id id, test_tree_visitor& V )
{
global_i = global_i + 1;
std::cout<<global_i<<std::endl;
if( ut_detail::test_id_2_unit_type( id ) == tut_case )
traverse_test_tree( framework::get<test_case>( id ), V );
else
traverse_test_tree( framework::get<test_suite>( id ), V );
}
The error information I have obtained from VC10 is:
Unhandled exception at 0x779815de in TestApplication.exe: 0xC00000FD: Stack overflow.
I was wondering what's wrong with the test program. Thanks!
EDIT Based on the suggestions I looked through my codes, and very strange things happen: if the test suite is defined in same program with main(), it works; however, if the test suite is from a .dll, the error will occur. I list the following codes to illustrate my problem:
boost::unit_test::test_suite* main_global_test_suite;
void Hellotestdll()
{
int i= 1;
int j= 2;
BOOST_CHECK(i == j);
}
boost::unit_test::test_suite* get_abc_test_suite()
{
test_suite* ts = BOOST_TEST_SUITE( "unit_geometric" );
ts->add( BOOST_TEST_CASE( &Hellotestdll ) );
return ts;
}
int main( int argc, char* argv[] )
{
try
{
/**
* Step 1. obtain options
*/
char* optionLine[1024];
int len;
len = obtain_options(optionLine, argc, argv);
/**
* Step 2. perform unit test based on user's options
*/
int test_status=0;
main_global_test_suite = get_abc_test_suite();
test_status = unit_test_main(run_global_test_suite, len, optionLine);
return test_status;
}
catch(std::exception& e)
{
std::cout << e.what() << std::endl;
return 1;
}
catch (const std::string& s)
{
std::cout << s << std::endl;
return 1;
}
catch (...)
{
return 1;
}
}
The above codes work very well. But if the test suite is from a .dll, for example:
// dll_header.h
namespace abc
{
ABC_EXPORT boost::unit_test::test_suite* get_geometric_test_suite();
}
// dll_header.cpp
namespace abc
{
using namespace boost;
using namespace boost::unit_test;
void Hellotestdllabc()
{
int i= 1;
int j= 2;
BOOST_CHECK(i == j);
}
boost::unit_test::test_suite* get_abc_test_suite()
{
test_suite* ts = BOOST_TEST_SUITE( "unit_abc" );
ts->add( BOOST_TEST_CASE( &Hellotestdllabc ) );
return ts;
}
}
Then if I invoke this test suite, with the following codes:
int main( int argc, char* argv[] )
{
............
/**
* Step 2. perform unit test based on user's options
*/
int test_status=0;
main_global_test_suite = abc::get_abc_test_suite();
test_status = unit_test_main(run_global_test_suite, len, optionLine);
return test_status;
}
The annoying stack overflow error will happen.
Summery of the Problems
(1) boost dll with MDd (Succeed)
If I link the boost unit test library (with the definition -DBOOST_ALL_DYN_LINK -DBOOST_TEST_NO_MAIN -DBOOST_TEST_DYN_LINK -DBOOST_ALL_NO_LIB)and the running executable program with the same dynamic run-time library (Multi-thread Debug Dll (MDd)), it will work.
(2) boost dll with MTd (Failed)
If the boost unit test library (with the definition -DBOOST_ALL_DYN_LINK -DBOOST_TEST_NO_MAIN -DBOOST_TEST_DYN_LINK -DBOOST_ALL_NO_LIB)and the running executable program are compiled and link with the same static run-time libray (Multi-thred Debu (MTd)), I will have a crash, but the crash is different from the one I reported above:
(3) boost static lib with MDd (Failed)
If the boost is built as a static library (with the definition of -DBOOST_TEST_NO_MAIN -DBOOST_ALL_NO_LIB), and both the boost library and the executable program are built with the same dynamic run-time library (MDd). The following crash will happen:
(4) boost static lib with MTd (Failed)
If the boost is built as a static library (with the definition of -DBOOST_TEST_NO_MAIN -DBOOST_ALL_NO_LIB), and both the boost library and the executable program are built with the same static run-time library (MTd). The following crash will happen:
ABC_EXPORT boost::unit_test::test_suite* get_geometric_test_suite();
The point of unit tests is to find problems in code early. That worked, it is just that you found the problem very early. Too early to even allow the unit test to run properly.
Functions in a DLL that returns pointers to C++ objects are a problem in general. It will only come to a good end when the layout of the C++ object exactly matches the assumptions made by the compiler when it compiled both your DLL and your EXE. And that the object lives on a heap that both modules have access to, required since the DLL creates the object and your EXE needs to delete it.
To allow the object to be properly deleted, both the DLL and the EXE must share the same CRT version. You will get into trouble when you build your program with /MT, asking for the static version of the CRT. The relevant compiler setting is C/C++, Code Generation, Runtime library setting. Your Debug configuration must use /MDd, your Release configuration must use /MD. For both the EXE and the DLL project, as well as the Boost library when it was compiled. If it is /MTd and /MT then the DLL will have its own copy of the CRT linked into it and will use its own heap to allocate from. The EXE cannot properly delete the object since it uses another heap. Doing so anyway will produce undefined behavior. Anything can happen, you tend to only get lucky when you run your program on a version of Windows that's newer than XP. Vista and up will use a debug heap when you run your unit test with a debugger attached, it invokes a breakpoint when it notices that the pointer passed to ::operator delete is invalid. Be sure to allow the linker to automatically find the correct Boost .lib to link to, don't force it yourself.
Object layout is more likely your problem, unfortunately much harder to diagnose. You stay out of trouble by building your EXE and DLL with the exact same compiler settings. With the additional requirement that they must match the settings that were used to build the Boost libraries. Which certainly is the difficult part, that requires a time machine. Particularly the _HAS_ITERATOR_DEBUGGING macro is a troublemaker, basic STL classes like std::vector will have a different layout that depends on the value of that macro.
I realize this is very vague, but there isn't enough info in the question to truly diagnose this issue. A very basic check you can do is putting the returned boost::unit_test::test_suite pointer in a watch expression. If you suddenly see the members of that object change when you step into Boost code then you know you have an object layout problem. What happens next is highly unpredictable, a stack overflow is certainly possible. Yet another diagnostic is to use the Debug + Windows + Registers window. Ensure that the ESP register value is stable when you step over functions.