MySQL++ - Run-Time Check Failure #2 - Stack around the variable was corrupted.

Started by
9 comments, last by Tingle 12 years, 7 months ago
Hello, im having issues with MySQL++ and desperately need help.
I'm using Visual Studio 2010, MySQL++ v3.1.0 and MySQL v5.1.59( x86 & x64 );
All Library's have been compiled correctly. This error only occurs in Debug version due to the compiler setting "Both (/RTC1, equiv. to /RTCsu) (/RTC1)" being on.

I've been raging for 2 days over this problem, and traced it down to the fact that ALL mysqlpp variables that are created on stack, as shown in my code, give this error when they get destroyed on leaving the scope.
The code works perfectly and does what its suppose to in both Debug and Release. So the only problems im having, are these errors showing up in Debug. If they are (which I suppose they are) bugs with the VS10Compiler/MySQL/MySQL++ - I would be happy to do some hack/disabling of warnings that effect only this section of my code (haven't figured out how to either). As already said, the code works like a charm.
Note to my code: I also receive this warning if I comment out everything in between the connection and the disconnection.

Thank you for any help that you can offer.

Output:

First-chance exception at 0x000007fefdb4cacd in Launcher.exe: Microsoft C++ exception: mysqlpp::BadQuery at memory location 0x0a04f2a0..
Run-Time Check Failure #2 - Stack around the variable 'conn' was corrupted.


My code:

void CMyClass::Run()
{
// Everything in here is run on its own thread
try
{
mysqlpp::Connection conn( false );
if( !conn.connect( SQL_DATABASE, SQL_SERVER, SQL_USERNAME, SQL_PASSWORD, SQL_PORT ) )
{
Error( "[SQL] Failed to connect to Listening Server, this game will not show up on the Online List!" );
return;
}

// Get the NAT IP and add to Host info
mysqlpp::Query query = conn.query();
query << "SELECT USER();";
mysqlpp::UseQueryResult res = query.use();
mysqlpp::Row row = res.fetch_row();

string sRawIP( row[0].c_str() );
int nFirst = sRawIP.find_first_of( "@" );
sRawIP.erase( 0, nFirst+1 );

for( int i = 0, j = 0; true; i++ )
{
if( !strcmp( string( sRawIP ), "-" ) )
j++;

if( j == 4 )
{
sRawIP.erase( i, sRawIP.size() );
sRawIP.replace( "-", "." );
string sFormatedIP( sRawIP.c_str() );
Info( "[SQL] Formated IP: %s", sFormatedIP.c_str() );
break;
}
}

conn.disconnect();
}
catch( mysqlpp::BadQuery &e )
{
Error( "[SQL] Exception: %s", e.what() );
}
}
Advertisement
Couple things:


if( !strcmp( string( sRawIP ), "-" ) )
j++;




if ( sRawIP == '-' )
j++;




string sRawIP( row[0].c_str() );

[/quote]


string sRawIP = row[0];

Note to my code: I also receive this warning if I comment out everything in between the connection and the disconnection.

Have you tried narrowing your code down to a minimal example? The "CMyClass" suggests you might be using MFC or some other framework. Try creating a vanilla C++ console project with just the connection and try/catch block corrupt the stack. It may also help to trace through the code with a debugger and memory breakpoints to catch when the stack becomes corrupted.

Also a couple of notes on the code:


string sRawIP( row[0].c_str() ); // use instead: string sRawIP = row[0]; or string sRawIp( row[0] );
int nFirst = sRawIP.find_first_of( "@" ); // need to check for the case when nFirst == string::npos (assume the input can be be invalid)
sRawIP.erase( 0, nFirst+1 );

for( int i = 0, j = 0; true; i++ )
{
if( !strcmp( string( sRawIP ), "-" ) ) // err, what? just sRawIP == '-' is needed
j++;

if( j == 4 )
{
sRawIP.erase( i, sRawIP.size() );
sRawIP.replace( "-", "." );
string sFormatedIP( sRawIP.c_str() ); // use instead: sFormatedIP = sRawIP; or string sFormatedIP( sRawIP );
Info( "[SQL] Formated IP: %s", sFormatedIP.c_str() );
break;
}
}

conn.disconnect();
}
catch( mysqlpp::BadQuery &e )
{
Error( "[SQL] Exception: %s", e.what() );
}
}

[/quote]

Also, consider using stringstreams to parse the IP:

if ( /* row.empty() */ )
; // error

const string& in_ip = row[0];
string::pos idx = in_ip.find_first_of( '@' );
if ( idx == string::npos )
; // error

istringstream tokenizer( ip.substr( 0, idx ) );
ostringstream output;

string token;
for ( int i = 0; i < 4; ++i ) {
if ( getline( tokenizer, token, '-' ) ) {
if ( i )
output << '.';
output << token;
} else
; // error
}

string out_ip = output.str();
I get the same error if I do it like this:


void CMyClass::Run()
{
// Everything in here is run on its own thread
try
{
mysqlpp::Connection conn( false );
if( !conn.connect( SQL_DATABASE, SQL_SERVER, SQL_USERNAME, SQL_PASSWORD, SQL_PORT ) )
{
Error( "[SQL] Failed to connect to Listening Server, this game will not show up on the Online List!" );
return;
}

conn.disconnect();
}
catch( mysqlpp::BadQuery &e )
{
Error( "[SQL] Exception: %s", e.what() );
}
}


And I exchanged the Function/Class names for dummy ones.
But thanks for the optimizations.
What is "Error()"?

What if:
void CMyClass::Run()
{
try
{
mysqlpp::Connection conn( false );
}
catch( mysqlpp::BadQuery &e )
{
}
}


// Everything in here is run on its own thread[/quote]
What if you create connection on main thread?


Also, read stuff related to threading here. MySQL API needs to be built specifically for multi-threading.
I run the code you posted, same error: Run-Time Check Failure #2 - Stack around the variable 'conn' was corrupted.
I let it run on the main thread, same error: Run-Time Check Failure #2 - Stack around the variable 'conn' was corrupted.

:/

As already mentioned on my first post, it seems as if the destructors are buggy or there is something wrong with the memory management of the mysqlpp data types.Normal data types are fine.
A quick look at connection.hpp shows it's calling virtual function in constructor.

While not something that would cause problems by itself, it's an idiom which is strongly discouraged.

I had to refresh my knowledge on this, but in theory it does sound like something that could cause 'this' (the stack allocated instance) to be handled incorrectly, potentially leading to the error reported (connect being called on base class not actual connection class).

Details like this are why I have strong distrust of all but most mainstream and heavily maintained/used C++ libraries.
Ok, I've done some more debugging and created a fresh console project. And I received no error.
The only difference in between the two is that one is a DLL project and the other a Console project, but I doubt this is the problem considering the code works, just the memory handling doesn't.
This brings me to the conclusion that the Engine im working with, does some kind of memory management the affects how MySQL++ handles its memory.
The only option I see now is to somehow disable the engines memory manager before the MySQL++ code is run, and re enable it afterwards.
Ive tried undefining and redefining different memory specific defines, which had no effect and still left me with the error.

Is it possible to flip on default memory management and turn it back off during run time?
Or is it maybe possible to temporarily disable this specific warning/error during run time and then reactivate it?

Thank you for your help sofar

Ok, I've done some more debugging and created a fresh console project. And I received no error.
The only difference in between the two is that one is a DLL project and the other a Console project


Static initialization order fiasco.

DLL vs. static linking is characteristic flaw of such problems.

And since static initialization order is undefined by standard, problems categorically show between compiler version changes. I'd rant about use of statics in C++, but I won't.

This brings me to the conclusion that the Engine im working with, does some kind of memory management the affects how MySQL++ handles its memory.[/quote]
Yep.

Is it possible to flip on default memory management and turn it back off during run time?[/quote]
It's C++. ANYTHING is possible. Just very little of it is sane. It's up to what engine offers, C++ standard doesn't specify any of that, it barely even mentioned memory model at all.

Or is it maybe possible to temporarily disable this specific warning/error during run time and then reactivate it?[/quote]
It's not the warning, you're trashing memory. Unless there is a bug in compiler (not impossible), then your application happens to work right now, but that's just luck.

Flaws like this are very common in OO C++ code, even some of the biggest and most prominent projects and just about every project which uses Java OO instead of idiomatic C++ OO.
I see, could you give me an example with my code on how to prevent this?
That would be a lot of help.

Thank you for your support so far, very educational!

Edit: I should note that this only happens in Debug version. In Release it works like a charm
I've tracked the problem back to the mysqlpp_d.dll, the MySQL++ object are crashing on there destructors due to reference counting. It complains about not being capable of accessing the memory of the ref counter, and when it tries to decrease it, it crashes. At least thats what I think happens.

I tried this to make sure everything gets derefrenced and removed in the correct order ( even tho its irrelevant, but helped me track the true problem down I hope ):

{
mysqlpp::Row row;
{
mysqlpp::UseQueryResult res;
{
mysqlpp::Query query = conn.query();
query << "SELECT USER();";
res = query.use();
row = res.fetch_row();
}

if( row.empty() )
{
CryLogAlways( "[SQL] Query Result \'row\'is invalid, this game will not show up on the Online List!" );
return;
}
}
}


It crashes with:

First-chance exception at 0x000007feeef5dd4c (mysqlpp_d.dll) in Launcher.exe: 0xC0000005: Access violation writing location 0x000007feeeff5148.
Unhandled exception at 0x000007feeef5dd4c (mysqlpp_d.dll) in Launcher.exe: 0xC0000005: Access violation writing location 0x000007feeeff5148.


And breakes here:

~RefCountedPointer()
{
if (refs_ && (--(*refs_) == 0)) { // <- here
Destroyer()(counted_);
delete refs_;
}
}

This topic is closed to new replies.

Advertisement