1

hope you're having a good day.

I'm working on a class to wrap the Berkley C Networking API, so far I've only gotten a TCP server/client going.

The issue I'm having ironically is not with the networking, but with the stack and heap. Perhaps I simply don't understand it fully, but when I use something like: ClientSocket *mysock = new ClientSocket(); And just call functions using the -> operator, it works perfectly fine - my SocketException class gets caught no problem, if an error occurs.

But, when I use: ClientSocket mysock; And any exceptions get thrown while calling a function using the . operator, it shows: terminate called after throwing an instance of 'SocketException' Aborted And just throws me back to a terminal prompt.

Forgot to add, I am wrapping the calls in try/catch blocks.

I'm aware that the first example is using the 'new' keyword to return a pointer to the new ClientSocket instance on the heap, and the second is for the stack, but I don't know the problem.

I'm thinking that I'm missing something about pointers/references/stack/heap, but I have no idea what is happening. The code often runs just fine, but if any exceptions are thrown.... >:(

EDIT: On the links page, Client.cxx and Server.cxx are the example files! Thanks for pointing that out, Eric. Help with this would be greatly appreciated. The sources for this project are at:
links to all the files: http://furryhead.co.cc/problem.html
(I couldn't paste more than 2 links, and I have 4 files so this will have to do until someone can merge the links into my post) Beware: Socket.cxx is rather large, as it contains ServerSocket, ClientSocket, and SocketException definitions.

The commands to compile all the above files are:
g++ -c Socket.cxx -o Socket.o
g++ -c Server.cxx -o Server.o
g++ -c Client.cxx -o Client.o
g++ Server.o Socket.o -o server
g++ Client.o Socket.o -o client

Thanks!

Little update, as per Jon's recommendation, I looked up the docs for the socket functions and it now has better error reporting - I check the 'errno' variable and throw an exception based on that. (That, and I don't set it to nonblocking... ;) ) - Just wanted to update and say thanks! :D

trincot
  • 317,000
  • 35
  • 244
  • 286
FurryHead
  • 1,479
  • 3
  • 16
  • 19
  • 1
    Write a small testcase reproducing the problem, and include the code in your question - this gets you better help quicker. – Erik Mar 13 '11 at 00:02
  • I did - on the links page it's Client.cxx and Server.cxx - Sorry I didn't make that clear – FurryHead Mar 13 '11 at 00:03
  • That isn't a small testcase included in the question - that's a link to several external source files. – Erik Mar 13 '11 at 00:05
  • Yes, Client.cxx and Server.cxx ARE the testcases. I posted them on paste.pocoo.org to make it easier, for kicks and giggles I suppose. – FurryHead Mar 13 '11 at 00:16

2 Answers2

7

To me this sounds like an exception being thrown for a legitimate reason, and during stack unwinding some object's (possibly the ClientSocket's?) destructor throws. Since the runtime cannot resolve this situation in any meaningful way (two exceptions "thrown" at the same time), the terminate function is called and the program is shut down.

The unanswered question is why some destructor would throw if the object it belongs to is allocated on the stack. But to answer this question requires more data. Perhaps you can dig a little deeper and test my hypothesis?

By the way, if this is indeed the case, and since no destructor should ever throw anything, we can conclude that the offending class is fatally flawed.

Update: seems I was on the money.

Your class Socket's destructor calls close, and close can throw. This is a serious programming error. You should wrap the close call in the destructor in

try {
    close();
}
catch(...)
{ /* this space intentionally left blank */ }

and the crash will go away.

Second update (not crashing anymore)

If recv is returning -1, this means that the socket is in non-blocking mode and there is no data currently available to be received. That's not an error, but a feature. You shouldn't be throwing an exception there. What you should be doing exactly depends on whether you want to use the socket in blocking or non-blocking mode.

Community
  • 1
  • 1
Jon
  • 428,835
  • 81
  • 738
  • 806
  • This might be it. In the socket's destructors, I call the close() method of the sockets which can throw an exception. I'll check that out. – FurryHead Mar 13 '11 at 00:05
  • Aaaaah, you got it. Now I'm getting a slightly more useful error. I didn't realize you can't catch exceptions from a destructor... But now I can't read the socket :\ http://uppit.com/124gypyiqrdp/src.zip EDIT: When I call recv() it can't read for some reason. – FurryHead Mar 13 '11 at 00:11
  • Specifically: `code` char buffer[bufsize+1]; bzero(buffer,bufsize); int ret = 0; ret = ::recv(sockfd, buffer, bufsize-1, 0); if (ret == -1) throw SocketException("Error reading socket.");`code` ---- I get the "Error reading socket" exception thrown – FurryHead Mar 13 '11 at 00:12
  • @FurryHead: Updated my answer. You shouldn't be throwing when `recv` returns -1. See its documentation, and decide between blocking and non-blocking sockets. – Jon Mar 13 '11 at 00:19
  • Aaaaaaah. When it's on the heap, it blocks. I assumed that was the default behavior. Thank you a lot! You guys rock :D – FurryHead Mar 13 '11 at 00:20
0

Jon has already solved the terminate problem, but there is another problem in the original code.

The reason that a dynamically allocated object seemed to work is that when there is an exception elsewhere, it is leaked and the destructor is never called. While this avoids the double-exception problem, it causes another set later...

Bo Persson
  • 90,663
  • 31
  • 146
  • 203