将调用推送到 STL 队列从套接字读取字符串时导致段错误

发布于 2024-08-08 18:07:39 字数 4516 浏览 2 评论 0原文

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

下面是相关代码:

// 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 函数是一个实用函数,用于去除末尾的换行符 收到的输入。我把它放进去是为了帮助调试,当段错误第一次出现时它并不存在:

// 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->input 中。 p->input 只是将输入字符串推入队列:

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

输入队列与输出队列一起在玩家类内部定义,工作正常:

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

字符串简单地定义为 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]

就我所知,字符串是正常的,所以我不知道什么会导致队列阻塞。我将继续探索它,看看会发现什么,但我真的很感激 Stack Overflow 社区可以提供有关此问题的任何见解。

编辑添加继续戳的结果:

我尝试了另外两种方法将 buf 放入到 p->input 的字符串中:

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

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

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

回答:我愚蠢地在程序的嵌套中忘记在 Socket 类中设置 Player *p 。 P 是 Socket 和包含它的 Player 之间的反向链接。我认为 p 没问题,因为我们在崩溃之前将其深入到玩家中,因此它必须是字符串或队列中的东西。愚蠢的我。谢谢克里斯!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

杀手六號 2024-08-15 18:07:39

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

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

如果read返回-1,那么这个else if将尝试将缓冲区作为一个真正大的缓冲区来操作:

else if(n > 0) {

我不确定是否我强调的问题正在引起问题,但值得解决。

编辑

好吧,事实证明这不是问题,但从崩溃的角度来看,可能(而且确实是!) Player 指针 < code>p 为空。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文