views:

337

answers:

1

I'm using an STL Queue as an input queue, it's containing std::strings, which I have aliased as String using a typedef. I'm reading the input string off a socket - using Berkeley sockets. It is read into a char buffer array and then used to set a string which is passed to the queue. It only happens for the input queue - the output queue, which does not receive its Strings from the socket read, works fine.

Here is the relevant code:

// Read from this socket's descriptor and send the input
// to its associated player for queueing and parsing.
void Socket::Read() {
 char buf[READ_SIZE + 1];

 int n = 0;
 if ((n = read(descriptor, buf, READ_SIZE)) < 0) {
  try {
   handleSocketError(__FILE__, __LINE__);
  }
  catch (...) {
   throw ;
  }
 }
 else if(n > 0) {
  buf[n] = 0;
  stripNewline(buf);
  log->log("Input received in Socket::Read: %s.", buf);
  String in = buf;
  p->input(in);
 }
}

The stripNewline function is a utility function to strip the newlines off the end of the input received. I put this in to aid in debugging, it wasn't there when the segfault first showed up:

// A utility function to strip the newlines off the end of
// a string.
void Socket::stripNewline(char *buf) {
 for(int i = strlen(buf); i > 0 && (buf[i] == '\n' || buf[i] == '\r' || buf[i] == 0); i--) {
   buf[i] = 0;
 }
}

This is where the input originates and is fed into p->input as a string. p->input simply pushes the input string onto the queue:

// Push the String in to the tail of the input queue.
void Player::input(String in) {
 log->log("Player is sending input: %s.", in.c_str());
 std::cout << in << std::endl;
 inQ.push(in);
}

The in queue is defined here inside the player class along with the out queue, which is working fine:

std::queue<String> inQ;
std::queue<String> outQ;

String is defined simply as a typedef of std::string:

typedef std::string String;

EDIT: fixed backwards typedef, what I get for writing it from memory when distracted, it was correct in code.

The output before the segmentation fault and the output of catchsegv is the following:

Sat Oct 24 11:02:34 2009:: New connection, waking up.
Sat Oct 24 11:02:34 2009:: Connection attempt begun.  Connection in the read set.
Sat Oct 24 11:02:34 2009:: Player has received output: Welcome to Muddy Reality Alpha version!
.
Sat Oct 24 11:02:35 2009:: Input received in Socket::Read: test.
Sat Oct 24 11:02:35 2009:: Player is sending input: test.
test
Segmentation fault
*** Segmentation fault
Register dump:

 EAX: 0000000c   EBX: 00000080   ECX: 00000000   EDX: 0000000c
 ESI: bfdbf080   EDI: 080497e0   EBP: bfdbee38   ESP: bfdbee20

 EIP: 0805640f   EFLAGS: 00010282

 CS: 0073   DS: 007b   ES: 007b   FS: 0000   GS: 0033   SS: 007b

 Trap: 0000000e   Error: 00000004   OldMask: 00000000
 ESP/signal: bfdbee20   CR2: 00000024

 FPUCW: ffff037f   FPUSW: ffff0000   TAG: ffffffff
 IPOFF: 00000000   CSSEL: 0000   DATAOFF: 00000000   DATASEL: 0000

 ST(0) 0000 0000000000000000   ST(1) 0000 0000000000000000
 ST(2) 0000 0000000000000000   ST(3) 0000 0000000000000000
 ST(4) 0000 0000000000000000   ST(5) 0000 0000000000000000
 ST(6) 0000 0000000000000000   ST(7) 0000 0000000000000000

Backtrace:
/lib/libSegFault.so[0xb7f9e100]
??:0(??)[0xb7fa3400]
/usr/include/c++/4.3/bits/stl_queue.h:226(_ZNSt5queueISsSt5dequeISsSaISsEEE4pushERKSs)[0x805647a]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/player.cpp:73(_ZN6Player5inputESs)[0x805377c]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:159(_ZN6Socket4ReadEv)[0x8050698]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:413(_ZN12ServerSocket4ReadEv)[0x80507ad]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:300(_ZN12ServerSocket4pollEv)[0x8050b44]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/main.cpp:34(main)[0x8049a72]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb7d1b775]
/build/buildd/glibc-2.9/csu/../sysdeps/i386/elf/start.S:122(_start)[0x8049801]

Near as I can tell the String is sane, so I have no idea what could cause the queue to choke. I'm going to keep poking it and see what I turn up, but I would really appreciate any insights the Stack Overflow community can offer on this one.

EDITTED to add the results of continued poking:

I've tried two other methods of putting buf into the String that goes to p->input:

p->input(String(buf));

and

String in;
in.assign(buf);
p->input(in);

Both had the same result. I've tried sending the buffer to standard out character by character to make sure no weird characters sneaked in:

 printf("Printing buf to determine sanity: \n");
 for(int i = 0; buf[i] != 0; i++) {
  printf("%d: %c\n", i, buf[i]);
 }

The result of which was:

Printing buf to determine sanity: 
0: T
1: e
2: s
3: t

So still no ideas. It's all local static memory, so not a dymanic memory issue unless it's a really strange one (of course, dynamic memory === strange issues, so it's still a possibility).

Further: originally had size_t (an unsigned integer type) being compared for values less than zero. Changed to both a ssize_t (signed integer type) and to just a straight int with no change - still crashes. Thanks Chris, not the answer but still a good catch!

Answered: I foolishly, in my nest of a program, forgot to set Player *p in the Socket class. P is the back link between the Socket and the Player containing it. I'd assumed that p was fine because we were making it so deep into player before crashing, and therefore it had to be something with the String or the queue. Silly me. Thanks Chris!

+3  A: 

size_t is an unsigned type, n is a size_t so this comparison will never be true.

if ((n = read(descriptor, buf, READ_SIZE)) < 0) {

If read returns -1, then this else if will try and manipulate the buffer as a really big buffer:

else if(n > 0) {

I'm not sure if the issues that I've highlighted are causing an issue but they are worth fixing.

Edit

OK, it turns out that that wasn't the issue, but guessing from the point of the crash it could have been (and was!) that the Player pointer p was null.

Charles Bailey
I suspect the `typedef` is just a mistranscription, but good catch on the `size_t` vs. `int`.
Adam Rosenfield
Removed `typedef` comment; it's fixed in the Q now.
Charles Bailey
Nice catch on the size_t vs int, however, that wasn't the answer. I changed it to an ssize_t and an int to no avail. I'll edit the code above to reflect that. Also the backwards typedef was just a mistranscription. The post has been editted. Thanks though!
Daniel Bingham