stl 큐에 호출을 푸시
-
06-07-2019 - |
문제
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이었다.