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!