Push Call to STL Queue < std :: string > causa Segfault quando String viene letto dal socket
-
06-07-2019 - |
Domanda
Sto usando una coda STL come coda di input, che contiene std :: stringhe, che ho impostato come stringa usando un typedef. Sto leggendo la stringa di input da un socket - usando i socket Berkeley. Viene letto in un array di buffer di caratteri e quindi utilizzato per impostare una stringa che viene passata alla coda. Succede solo per la coda di input - la coda di output, che non riceve le sue stringhe dal socket letto, funziona bene.
Ecco il codice pertinente:
// 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);
}
}
La funzione stripNewline è una funzione di utilità per eliminare le righe dalla fine l'input ricevuto. L'ho inserito per facilitare il debug, non era presente quando è apparso il 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;
}
}
Qui è dove ha origine l'input ed è inserito in p- > input come una stringa. p- > input inserisce semplicemente la stringa di input nella coda:
// 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);
}
La coda di ingresso è definita qui all'interno della classe del giocatore insieme alla coda di uscita, che funziona bene:
std::queue<String> inQ;
std::queue<String> outQ;
La stringa è definita semplicemente come un typedef di std :: string:
typedef std::string String;
EDIT : risolto errore di battitura all'indietro, quello che ottengo per scriverlo dalla memoria quando distratto, era corretto nel codice.
L'output prima dell'errore di segmentazione e l'output di catchsegv è il seguente:
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]
Quasi come posso dire che String è sano, quindi non ho idea di cosa potrebbe far soffocare la coda. Continuerò a frugarlo e vedrò cosa mi presenterò, ma apprezzerei davvero tutte le intuizioni che la community di Stack Overflow può offrire su questo.
MODIFICATO per aggiungere i risultati della ricerca continua:
Ho provato altri due metodi per inserire buf nella stringa che va in input p- >
p->input(String(buf));
e
String in;
in.assign(buf);
p->input(in);
Entrambi hanno avuto lo stesso risultato. Ho provato a inviare il buffer allo standard carattere per carattere per assicurarmi che nessun personaggio strano si intrufolasse:
printf("Printing buf to determine sanity: \n");
for(int i = 0; buf[i] != 0; i++) {
printf("%d: %c\n", i, buf[i]);
}
Il risultato è stato:
Printing buf to determine sanity:
0: T
1: e
2: s
3: t
Quindi ancora nessuna idea. È tutta memoria statica locale, quindi non è un problema di memoria dymanic a meno che non sia davvero strano (ovviamente, memoria dinamica === strani problemi, quindi è ancora una possibilità).
Inoltre: originariamente aveva size_t (un tipo intero senza segno) che veniva confrontato per valori inferiori a zero. Modificato sia in un ssize_t (tipo intero con segno) che in un semplice int senza modifiche - continua a bloccarsi. Grazie Chris, non la risposta ma comunque una buona cattura!
Risposto : scioccamente, nel mio nido di un programma, ho dimenticato di impostare Player * p nella classe Socket. P è il collegamento posteriore tra il Socket e il Player che lo contiene. Avevo supposto che p andasse bene perché lo stavamo trasformando così profondamente nel giocatore prima di andare in crash, e quindi doveva essere qualcosa con la stringa o la coda. Sciocco me Grazie Chris!
Soluzione
size_t
è un tipo senza segno, n
è un size_t
quindi questo confronto non sarà mai vero.
if ((n = read(descriptor, buf, READ_SIZE)) < 0) {
Se read
restituisce -1
, questo altrimenti if
proverà a manipolare il buffer come un buffer veramente grande:
else if(n > 0) {
Non sono sicuro se i problemi che ho evidenziato stiano causando un problema, ma vale la pena risolverli.
Modifica
OK, si scopre che quello non era il problema, ma indovinando dal punto dello schianto avrebbe potuto essere (ed era!) che il puntatore Player
p era null.