문제

STL 큐를 입력 대기열로 사용하고 있습니다. std :: 문자열이 포함되어 있습니다. 버클리 소켓을 사용하여 소켓에서 입력 문자열을 읽고 있습니다. 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-> 입력은 단순히 입력 문자열을 큐에 밀어 넣습니다.

// 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]

줄이 끈이 제정신이라고 말할 수 있으므로 대기열이 질식시킬 수있는 이유는 전혀 모릅니다. 나는 그것을 계속 찌르고 내가 무엇을 나타 내는지 볼 것입니다. 그러나 스택 오버플로 커뮤니티가 이것에 대해 제공 할 수있는 통찰력에 정말 감사합니다.

편집 지속적인 찌르기 결과를 추가하려면 :

P-> 입력으로 이동하는 문자열에 BUF를 넣는 다른 두 가지 방법을 시도했습니다.

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 (서명되지 않은 정수 유형)는 0보다 작은 값에 대해 비교되었습니다. ssize_t (서명 된 정수 유형)와 변화가없는 직선 int로 변경되었습니다. 여전히 충돌합니다. 감사합니다 Chris, 답이 아니라 여전히 좋은 캐치!

대답했다: 어리석게도 프로그램의 둥지에서 소켓 클래스에서 플레이어 *P를 설정하는 것을 잊었습니다. P는 소켓과 포함하는 플레이어 간의 후면 링크입니다. 나는 우리가 충돌하기 전에 플레이어를 깊이 깊게 만들었 기 때문에 P가 괜찮다고 가정 했으므로, 그것은 문자열이나 대기열과 관련이 있어야했습니다. 바보 나. 감사합니다 Chris!

도움이 되었습니까?

해결책

size_t 서명되지 않은 유형이며 n a size_t 따라서이 비교는 결코 사실이 아닙니다.

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

만약에 read 보고 -1, 이건이 else if 버퍼를 정말 큰 버퍼로 조작 할 것입니다.

else if(n > 0) {

내가 강조한 문제가 문제를 일으키는 지 확실하지 않지만 고칠 가치가 있습니다.

편집하다

좋아, 그것이 문제가 아니었지만 충돌의 시점에서 추측하는 것은 Player 바늘 p null이었다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top