?
Solved

Random C++ MySql Crash / Exception Handling

Posted on 2007-10-01
25
Medium Priority
?
529 Views
Last Modified: 2012-06-21
Greetings,

I'm currently experiencing crashes at random intervals in my win32 c++ app.  What happens is that my program runs fine but will eventually crash every time.  It has gone for as little as 2 minutes without crashing and for as long as an hour or more.

I've narrowed the crash down to a mysql_query() call.  I say that it is this call that is causing the crash because i invariably see printf() ouput right before the crash, and none directly after the crash.

I took some strings that were being passed to the mysql_query call that caused the crash and tested them seperately.  These strings work fine in my testing environment.

It seems like what I'm missing from my program is proper exception handling.  From my java days I recall things like try-catch blocks, but I cant' seem to find good info on this topic for c++/mysql.

The only real idea i have about what would cause such a random crash is the connection to the database.  I am currently establishing the connection in the beginning of the program and I expected it to just stay open.  It is possible that for some reason the connection is dropping and that could theoretically cause a program crash.

Just to clarify what I mean by a "crash": I get one of those nice "This program has encountered a problem and needs to close.  We are sorry for the inconvenience" dialogs with the option to send a report to microsoft.

I do realize that this code looks pretty sloppy with all those printf()s , but I've been debugging.  And i'm also pretty sure that there is an easier way to contcatenate c strings together so if anyone has any pointers on that they would be helpfull.
code:
int DataBase::addMessage(Message *message) {
      char string[MAX_MESSAGE_SIZE];
      int ret;

      printf("Database.addMessage() - prepping string... ");
      string[0] = '\0';
      printf("Done\n");
      printf("Database.addMessage() - concatenating... ");
      strncat_s(string,MAX_MESSAGE_SIZE,"INSERT INTO WWW_Request (Dest_Name, arg, op, result, source, destination) VALUES ('", strlen("INSERT INTO WWW_Request (Dest_Name, arg, op, result, source, destination) VALUES ('"));
      printf("1... ");
      printf("%s ", message->info.destName);
      strncat_s(string,MAX_MESSAGE_SIZE,message->info.destName,strlen(message->info.destName));
      printf("2... ");
      printf("%s ", "','");
      strncat_s(string,MAX_MESSAGE_SIZE,"','",3);
      printf("3... ");
      printf("%s ", message->info.arg);
      strncat_s(string,MAX_MESSAGE_SIZE,message->info.arg,strlen(message->info.arg));
      printf("4... ");
      printf("%s ", "','");
      strncat_s(string,MAX_MESSAGE_SIZE,"','",3);
      printf("5... ");
      printf("%s ", message->info.operation);
      strncat_s(string,MAX_MESSAGE_SIZE,message->info.operation,strlen(message->info.operation));
      printf("6... ");
      printf("%s ", "','");
      strncat_s(string,MAX_MESSAGE_SIZE,"','",3);
      printf("7... ");
      printf("%s ", message->info.result);
      strncat_s(string,MAX_MESSAGE_SIZE,message->info.result,strlen(message->info.result));
      printf("8... ");
      printf("%s ", "','");
      strncat_s(string,MAX_MESSAGE_SIZE,"','",3);
      printf("9... ");
      printf("%s ", message->info.source);
      strncat_s(string,MAX_MESSAGE_SIZE,message->info.source,strlen(message->info.source));
      printf("10... ");
      printf("%s ", "','");
      strncat_s(string,MAX_MESSAGE_SIZE,"','",3);
      printf("11... ");
      printf("%s ", message->info.dest);
      strncat_s(string,MAX_MESSAGE_SIZE,message->info.dest,strlen(message->info.dest));
      printf("12... ");
      printf("%s ", "')");
      strncat_s(string,MAX_MESSAGE_SIZE,"')\0",2);
      printf("Done\n");
      printf("Query String: %s\n", string);
      
      ret = mysql_query(&mysql,string);
      printf("hhhhmmmmmm ... \n");
      if (ret != NULL)
            printf("ret: %i\n", ret);
      else
            printf("*********************************NULL WTF*********************************\n");

      if (ret == 0)
            printf("#######################\n");
      }

      return ret;
}

output:
Database.addMessage() - concatenating... 1... itxt.vibrantmedia.com 2... ',' 3..
. /intellitxt/front.asp?IPID=20&MK=5 4... ',' 5... GET 6... ',' 7... 200 8... ',
' 9... 100.27.23.158:3886:LAN 10... ',' 11... 207.211.21.18:80:WAN 12... ') Done

Query String: INSERT INTO WWW_Request (Dest_Name, arg, op, result, source, desti
nation) VALUES ('itxt.vibrantmedia.com','/intellitxt/front.asp?IPID=20&MK=5','GE
T','200','100.27.23.158:3886:LAN','207.211.21.18:80:WAN')
hhhhmmmmmm ...
*********************************NULL WTF*********************************
#######################
- done
Loop - grabbing ip address... - done
Resolve()
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop - adding message to database... Database.addMessage() - prepping string...
Done
Database.addMessage() - concatenating... 1... itxt.vibrantmedia.com 2... ',' 3..
. /v3/chunks.jsp?cn=5&ipid=20&sid=fd6597e8a9b8c6d05871a797ac511b0d&nbc=0&enc=&ia
 4... ',' 5... GET 6... ',' 7... 200 8... ',' 9... 100.27.23.158:3886:LAN 10...
',' 11... 207.211.21.18:80:WAN 12... ') Done
Query String: INSERT INTO WWW_Request (Dest_Name, arg, op, result, source, desti
nation) VALUES ('itxt.vibrantmedia.com','/v3/chunks.jsp?cn=5&ipid=20&sid=fd6597e
8a9b8c6d05871a797ac511b0d&nbc=0&enc=&ia','GET','200','100.27.23.158:3886:LAN','2
07.211.21.18:80:WAN')
0
Comment
Question by:flockdoom
  • 12
  • 11
  • 2
25 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 19991940
>>I do realize that this code looks pretty sloppy with all those printf()s

It is not the 'printf()'s I'd be concerned about - it is the

strncat_s(string,MAX_MESSAGE_SIZE,message->info.destName,strlen(message->info.destName));

statements that are incorrect. That should in each case be

strncat_s(string,MAX_MESSAGE_SIZE - strlen(string),message->info.destName,strlen(message->info.destName));

The room for storing the string in grows less each call and your above code does not take that into account, thus causing an access violation sooner or later.

BTW, I'd really advise to use a 'std::string' instead, where yo usafely can concatenate with a hearty '+'
0
 
LVL 86

Expert Comment

by:jkr
ID: 19991957
To add to the recommendation - that would then look like

#include <string>
using namespace std;

string str;

str += message->info.destName;
str += message->info.arg;

// etc.


      ret = mysql_query(&mysql,str.c_str());

without having to worry about the buffer at all.
0
 
LVL 86

Expert Comment

by:jkr
ID: 19992011
BTW, to handle the exceptions that you are experiencing, C++ exception handling won't help, since these are Win32 SEH exceptions that a C++ try/catch block won't deal with. See http://www.microsoft.com/msj/0197/exception/exception.aspx ("A Crash Course on the Depths of Win32" Structured Exception Handling"). Basically, that would mean

 try {
     // guarded body of code
 }
 except (filter-expression) {
     // exception-handler block
 }
0
What is SQL Server and how does it work?

The purpose of this paper is to provide you background on SQL Server. It’s your self-study guide for learning fundamentals. It includes both the history of SQL and its technical basics. Concepts and definitions will form the solid foundation of your future DBA expertise.

 

Author Comment

by:flockdoom
ID: 19992154
jkr,

Thanks for the quick response.

That is definately a better way to concat strings.  I changed my code to this:

int DataBase::addMessage(Message *message) {
//      char string[MAX_MESSAGE_SIZE];
      int ret;

      string str;

      str += "INSERT INTO WWW_Request (Dest_Name, arg, op, result, source, destination) VALUES ('";
      str += ",";
      str += message->info.destName;
      str += ",";
      str += message->info.arg;
      str += ",";
      str += message->info.operation;
      str += ",";
      str += message->info.result;
      str += ",";
      str += message->info.source;
      str += ",";
      str += message->info.dest;
      str += ")";

      printf("string length: %i)\n", str.length());
      printf(str.c_str());
      ret = mysql_query(&mysql,str.c_str());
      printf("query with no crash\n");

      return ret;
}

That looks much better but it still crashes.  I will read through that link that you posted
0
 
LVL 86

Expert Comment

by:jkr
ID: 19992168
Um this time it probably crashes because of

printf(str.c_str());

Make that

printf("%s\n",str.c_str());

or use 'cout', i.e.

#include <iostream>
using namespace std;

cout << str << endl;
0
 

Author Comment

by:flockdoom
ID: 19992378
duh ... good call.  Sometimes I forget that c lets you do things you're not supposed to.  I corrected this to:

int DataBase::addMessage(Message *message) {
//      char string[MAX_MESSAGE_SIZE];
      int ret;

      string str;

      str += "INSERT INTO WWW_Request (Dest_Name, arg, op, result, source, destination) VALUES ('";
      str += ",";
      str += message->info.destName;
      str += ",";
      str += message->info.arg;
      str += ",";
      str += message->info.operation;
      str += ",";
      str += message->info.result;
      str += ",";
      str += message->info.source;
      str += ",";
      str += message->info.dest;
      str += ")";

      printf("string length: %i)\n", str.length());
      printf("%s",str.c_str());
      ret = mysql_query(&mysql,str.c_str());
      printf("query with no crash\n");      

      return ret;
}

It does seem like somethign is filling up, however.  It appears that if I send the app a lot of input, it crashed fairly quickly.  I do not believe it is my str that is the culprit, though.  The posted output below shows that the length of str is fluctuating normally and is not just growing.  Its possible that there is something somewhere else that would be affecting this bit of code .... but I don't know what types of things would specifically affect a call to mysql_query()




output:
Loop - grabbing ip address... - done
Resolve()
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop - adding message to database... string length: 222)
INSERT INTO WWW_Request (Dest_Name, arg, op, result, source, destination) VALUES
 (',css.experts-exchange.com,/xp/css/include/zoneAd_584fd9c30f41fabdfc7cda4711ea
445d.css,GET,200,172.27.23.158:4985:LAN,64.156.132.140:80:WAN)query with no cras
h
- done
Loop - grabbing ip address... - done
Resolve()
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop - adding message to database... string length: 203)
INSERT INTO WWW_Request (Dest_Name, arg, op, result, source, destination) VALUES
 (',us.i1.yimg.com,/us.yimg.com/i/us/pim/r/medici/all/rc_wg2w_ne_1.gif,GET,304,1
72.27.23.158:1028:LAN,192.204.11.17:80:WAN)query with no crash
- done
Loop - grabbing ip address... - done
Resolve()
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop - adding message to database... string length: 189)
INSERT INTO WWW_Request (Dest_Name, arg, op, result, source, destination) VALUES
 (',us.i1.yimg.com,/us.yimg.com/i/us/pim/pimstrip_01.gif,GET,304,172.27.23.158:1
029:LAN,192.204.11.17:80:WAN)query with no crash
- done
Loop - grabbing ip address... - done
Resolve()
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop End
Loop Start
Loop - Recieving buffer... Done
Loop - Parsing Message... Done
Loop - adding message to database... string length: 190)
INSERT INTO WWW_Request (Dest_Name, arg, op, result, source, destination) VALUES
 (',www.microsoft.com,/msj/0197/exception/exception.aspx,GET,200,172.27.23.158:4
999:LAN,207.46.192.254:80:WAN)
0
 

Author Comment

by:flockdoom
ID: 19992400
I just noticed that I've got a problem to resolve ... is there a way to edit a post?  haha
0
 
LVL 86

Expert Comment

by:jkr
ID: 19992412
Have you tried running it under a debugger to see where exactly that crashes?
0
 

Author Comment

by:flockdoom
ID: 19992460
I haven't , but thats basically because I really don't know how to use a debugger
0
 
LVL 86

Expert Comment

by:jkr
ID: 19992469
What compiler are you using?
0
 

Author Comment

by:flockdoom
ID: 19992488
ms visual studio 2005

I'm running it in the debugger just to see what happens ... it hasn't crashed yet
0
 
LVL 86

Expert Comment

by:jkr
ID: 19992518
Well, debugging with VC 2005 is quite easy. Hint: If the code runs fine in the debugger, that usually points to uninitialized variables, especially pointres.
0
 

Author Comment

by:flockdoom
ID: 19992618
Ok, it crashed and the debugger brought me right to the mysql_query() call.   It told me :

Unhandled exception at 0x1002fd18 in X.exe: 0xC0000005: Access violation reading location 0x00007265.

Do you have any pointers on how to proceed from here?
0
 
LVL 86

Expert Comment

by:jkr
ID: 19992669
In

      ret = mysql_query(&mysql,str.c_str());

Is 'mysql' valid and initialized? Any chance that the string is to long for that call to handle?
0
 

Author Comment

by:flockdoom
ID: 19992721
mysql is initialized and the connection is made when the DataBase object (the object that contains the addMessage function) is created.  

I can go through 100 calls to addMessage() before a crash happens.

As for string length, according to my output file it last crashed on a 208 length string, where 12 calls earlier it handled a 245 length string with no problems.

I'm going to try putting a call to mysql_ping(&mysql); before trying the mysql_query just to see if the connection is dropping and causing crashes
0
 

Author Comment

by:flockdoom
ID: 19992750
this time it crashed on the mysql_ping() call which was placed before the mysql_query() call ... so it looks like something is happening to my mysql object
0
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 19992794
Where is 'mysql' declared? Any chance it got overwritten?
0
 

Author Comment

by:flockdoom
ID: 19992855
It is the only private variable declared in my DataBase.h header file.

The only times that varialble (mysql) is accessed directly is when DataBase.init() is called (happens once when the thread that declares the DataBase object starts),  when DataBase.conenct() is called (happens right after DataBase.init() is called), and when DataBase.addMessage() is called (in the while(1) { } part of the owning thread).

If it is being overwritten it looks like its being done by another variable
0
 
LVL 86

Expert Comment

by:jkr
ID: 19992886
>>If it is being overwritten it looks like its being done by another variable

Yes, that's what I menat. Any arrays around the declaration? Or near the place where your 'DataBase' is declared?
0
 

Author Comment

by:flockdoom
ID: 19993222
I'm in the process of commenting things out, trying to distill my code down to exactly what it is thats causing the crash.  It just about quitting time, so I'll have to pick this up tommorow.  Thanks for all the help you've been
0
 
LVL 86

Expert Comment

by:jkr
ID: 19993270
Then let's carry on tomorrow ;o)
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 19996580
>>>> Unhandled exception at 0x1002fd18 in X.exe: 0xC0000005:
>>>> Access violation reading location 0x00007265.

>>>> Do you have any pointers on how to proceed from here?

Access violation normally means that there is a invalid pointer (NULL or uninitialized or already deleted). In VS2005 you can force the debugger to stop immediately when an access violation was detected:

- set a breakpoint to a statement at the beginning of your prog,
  e. g. at the DataBase.init().

You set a breakpoint by simply clicking left of the statement into the gray column. Note, if a statement needs more than one line you can set the breakpoint only in the last of these lines.

- start the debugger with F5

it should break at line where you set the breakpoint. You'll see some mini icons for navigating with the debugger. The most left with a little curved arrow pointing to some nested lines is to 'jump into' a function called. The next is to process the current statement and go the next. The third is to proceed until end of function and jump to the calling function, the last is to proceed with the current function until it reached the line where you currently have the cursor set. With the little square you can stop the debugger.

- If the prog is stopped you can go the Debug - Exceptions ... menu.

Here choose WIN32 exceptions and select 'Access Violation' (hilite with the mouse).

You now have some options below the list where you can say what sould happen if the exception was thrown. Choose the most upper option which forces the debugger to break immediately if the access violation occured.

- Proceed with F5 until the program crashes.

The debugger should show you now what statement has caused the access violation. Check all variables especially pointers by hoovering over the variables. If you detect a pointer with NULL (0x00000000) value or with a value like 0xcdcdcdcd or similar, you've found the reason. Sometimes the pointer address looks ok, but the variable it is pointing to has some strange contents "`&[]# ä". Then the pointer is ok but the object it is pointing to is corrupt.  If you find no wrong pointer variable, you should examine the 'this' pointer. You'll see it in one of the watch windows. YouÄll find the watch windows in the menu Debug - Windows .... You should invoke them all when debugging (Watch - Watch1, Auto, Local, Call Stack). If you don't see the 'this' in the Auto window you may type 'this' into watch1 window.

- If you found the wrong pointer you should go up in the function to find
  out where the pointer comes from.

Check whether the pointer was passed via argument list. If yes or if the 'this' was corrupt, you should go 'down' (actually it is going 'up') in the call stack to see the calling function. Here you can examine further. If for example the this was NULL, you have to look at the last statement of the calling function and you will see that it is calling with a pointer that is NULL. You have to 'go up' the call stack until you find out why the pointer was invalid. One of the most likely reasons is that the pointer wasn't initialized, e. g. the initialization was in a if block but the if condition never was true. Or the pointer was the result of a call that failed but where your prog don't check for pointer != NULL after.

Note, if you find functions in the callstack that were not from you but system functions, go up the callstack until you find a function you have written. It is not impossible but very unlikeley that you found a bug in a system function. The chance that it is you who made the bug is much greater.

Regards, Alex
0
 

Author Comment

by:flockdoom
ID: 19998807
So after a bit of digging this morning I found the problem.  Turns out that I had not been bound checking in my Message class (note the DataBase.addMessage(Message *message) signature) and one of my char arrays was not large enough.  Sloppy, sloppy, sloppy.  

itsmeandnobodyelse: I tried your method and I didn't really get anywhere with the debugger.  Basically the only thing I could get out of it was confirmation that my mysql pointer was being overwitten in addition to the 'this' pointer.  I'm not sure exactly what the 'this' poitner being overwritten implies ... other than bad things happening

jkr: Thanks for the string lessons and all the advice
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 19999094
>>>> I tried your method and I didn't really get anywhere with the debugger
Yes, it is not easy and if you have been writing beyond array boundaries, things might have been more difficult.

>>>> the only thing I could get out of it was confirmation that my
>>>> mysql pointer was being overwitten in addition to the 'this' pointer.
You could set a 'conditioned' breakpoint which breaks the code exactly at the statement when a variable was overwritten. It would have brought you to the array loop. But you can't find out all functionality in the very beginning.

>>>> I'm not sure exactly what the 'this' poitner being overwritten implies
If you are within a member function the 'this' points to the class instance the member function was called with:

yourcode.cpp

     char carr[100];
     Database* pdb = new Database(...);
     ...
     if (!pdb->init(....))
     {
          ...
     }

dbcore.cpp

       BOOL Database::init(...)
       {
             ...
             i = 5;
             ...
       }

If you stepped into Database::init, e. g. to statement 'i = 5;' the 'this' pointer points to the object the Database::init was called with. In the sample it is the object created with 'pdb = new Database(...);' in yourcode.cpp. If the 'this' is corrupt it means in the sample that the local variable pdb was corrupt. That can happen if the 'carr' array was written beyond the array boundaries what might overwrite the next variable which was the 'pdb'. Hope, you got an idea what I meant.

Regards, Alex

0
 

Author Comment

by:flockdoom
ID: 19999134
Ahhh, ok, that makes sense about the 'this' pointer.  I wasn't sure what 'this' was referring to.

As for the debugger, I'll have to play with that a bit in order to fully grasp how to use conditional breaks properly
0

Featured Post

Granular recovery for Microsoft Exchange

With Veeam Explorer for Microsoft Exchange you can choose the Exchange Servers and restore points you’re interested in, and Veeam Explorer will present the contents of those mailbox stores for browsing, searching and exporting.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is intended for those who are new to PHP error handling (https://www.experts-exchange.com/articles/11769/And-by-the-way-I-am-New-to-PHP.html).  It addresses one of the most common problems that plague beginning PHP develop…
In this blog post, we’ll look at how using thread_statistics can cause high memory usage.
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
Suggested Courses

862 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question