• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 593
  • Last Modified:

Random C++ MySql Crash / Exception Handling

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
flockdoom
Asked:
flockdoom
  • 12
  • 11
  • 2
1 Solution
 
jkrCommented:
>>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
 
jkrCommented:
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
 
jkrCommented:
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
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

 
flockdoomAuthor Commented:
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
 
jkrCommented:
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
 
flockdoomAuthor Commented:
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
 
flockdoomAuthor Commented:
I just noticed that I've got a problem to resolve ... is there a way to edit a post?  haha
0
 
jkrCommented:
Have you tried running it under a debugger to see where exactly that crashes?
0
 
flockdoomAuthor Commented:
I haven't , but thats basically because I really don't know how to use a debugger
0
 
jkrCommented:
What compiler are you using?
0
 
flockdoomAuthor Commented:
ms visual studio 2005

I'm running it in the debugger just to see what happens ... it hasn't crashed yet
0
 
jkrCommented:
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
 
flockdoomAuthor Commented:
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
 
jkrCommented:
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
 
flockdoomAuthor Commented:
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
 
flockdoomAuthor Commented:
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
 
jkrCommented:
Where is 'mysql' declared? Any chance it got overwritten?
0
 
flockdoomAuthor Commented:
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
 
jkrCommented:
>>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
 
flockdoomAuthor Commented:
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
 
jkrCommented:
Then let's carry on tomorrow ;o)
0
 
itsmeandnobodyelseCommented:
>>>> 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
 
flockdoomAuthor Commented:
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
 
itsmeandnobodyelseCommented:
>>>> 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
 
flockdoomAuthor Commented:
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 12
  • 11
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now