推送调用STL队列<std :: string>导致在读取字符串时出现Segfault套接字</std :: string>

时间:2009-10-24 15:15:57

标签: c++ string sockets segmentation-fault

我正在使用STL Queue作为输入队列,它包含std :: strings,我使用typedef将其别名为String。我正在读取套接字上的输入字符串 - 使用Berkeley套接字。它被读入char缓冲区数组,然后用于设置传递给队列的字符串。它只发生在输入队列中 - 输出队列没有从套接字读取接收其字符串,工作正常。

以下是相关代码:

// 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);
 }
}

stripNewline函数是一个实用程序函数,用于从最后删除换行符 收到的输入。我把它放在帮助调试中,当segfault首次出现时它就不存在了:

// 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;
 }
}

这是输入的来源,并作为字符串输入到p->输入。 p-&gt;输入只是将输入字符串推送到队列:

// 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);
}

in队列在这里定义在播放器类中以及out队列,它正常工作:

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

String简单地定义为std :: string的typedef:

typedef std::string String;

编辑:向后修复typedef,我在分心时从内存中写入内容,在代码中是正确的。

分段错误之前的输出和catchsegv的输出如下:

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]

我可以告诉String是理智的,所以我不知道什么可能导致队列窒息。我将继续戳它,看看我发现了什么,但我非常感谢Stack Overflow社区可以提供的任何见解。

EDITTED 添加持续戳戳的结果:

我尝试了另外两种将buf放入字符串的方法,即p-&gt;输入:

p->input(String(buf));

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

两者都有相同的结果。我已经尝试逐个字符地将缓冲区发送到标准输出,以确保没有奇怪的字符潜入:

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

其结果是:

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

所以仍然没有想法。这是所有本地静态内存,所以不是一个动态内存问题,除非它是一个非常奇怪的问题(当然,动态内存= strange奇怪的问题,所以它仍然是一种可能性)。

此外:最初将size_t(无符号整数类型)与小于零的值进行比较。更改为ssize_t(有符号整数类型)和仅直接int而没有更改 - 仍然崩溃。谢谢克里斯,不是答案,但仍然很好!

已回答:我愚蠢地说,在我的程序嵌套中,忘了在Socket类中设置Player * p。 P是Socket和包含它的播放器之间的反向链接。我假设p很好,因为我们在崩溃之前将它深入到播放器中,因此它必须是String或队列的东西。傻我。谢谢克里斯!

1 个答案:

答案 0 :(得分:4)

size_t是无符号类型,nsize_t,因此这种比较永远不会成真。

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

如果read返回-1,则此else if会尝试将缓冲区操作为一个非常大的缓冲区:

else if(n > 0) {

我不确定我所强调的问题是否会导致问题,但是值得修复。

修改

好的,事实证明这不是问题,但从崩溃的角度猜测它可能是(并且是!)Player指针p为空。< / p>