Push Call to STL Queue < std :: string > causa Segfault cuando la cadena se lee fuera del socket

StackOverflow https://stackoverflow.com/questions/1618244

Pregunta

Estoy usando una cola de STL como una cola de entrada, contiene std :: strings, a las que he asignado un alias como String usando typedef. Estoy leyendo la cadena de entrada de un zócalo - usando los zócalos de Berkeley. Se lee en una matriz de búfer de caracteres y luego se usa para establecer una cadena que se pasa a la cola. Solo sucede con la cola de entrada: la cola de salida, que no recibe sus cadenas desde la lectura del socket, funciona bien.

Aquí está el código relevante:

// 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 función stripNewline es una función de utilidad para eliminar las nuevas líneas del final de la entrada recibida. Me puse esto para ayudar en la depuración, no estaba allí cuando apareció la falla de seguridad:

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

Aquí es donde se origina la entrada y se alimenta en la entrada p- > como una cadena. La entrada p- > simplemente empuja la cadena de entrada a la cola:

// 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 cola de entrada se define aquí dentro de la clase del jugador junto con la cola de salida, que funciona bien:

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

La cadena se define simplemente como un typedef de std :: string:

typedef std::string String;

EDIT : arreglado al revés typedef, lo que obtengo por escribirlo desde la memoria cuando estaba distraído, era correcto en el código.

La salida anterior a la falla de segmentación y la salida de catchsegv es la siguiente:

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]

Lo más cerca que puedo decir es que la Cadena está sana, así que no tengo idea de qué podría hacer que la cola se ahogue. Seguiré haciéndolo y veré lo que aparece, pero realmente apreciaría cualquier información que la comunidad de Stack Overflow pueda ofrecer en este caso.

EDITADO para agregar los resultados de la búsqueda continua:

He intentado otros dos métodos para colocar buf en la cadena que va a p- > input:

p->input(String(buf));

y

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

Ambos tuvieron el mismo resultado. He intentado enviar el búfer a caracteres estándar por carácter para asegurarme de que no haya ningún personaje extraño que se cuela:

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

El resultado fue:

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

Así que todavía no hay ideas. Es toda la memoria estática local, así que no es un problema de memoria dinámica a menos que sea realmente extraño (por supuesto, la memoria dinámica === problemas extraños, por lo que sigue siendo una posibilidad).

Además: originalmente se comparaba size_t (un tipo entero sin signo) para valores menores que cero. Se cambió tanto a ssize_t (tipo de entero con signo) como a solo un int directo sin cambios, aún se bloquea. Gracias Chris, no es la respuesta, pero sigue siendo una buena captura!

Respondido : Tontamente, en mi nido de un programa, olvidé configurar Player * p en la clase Socket. P es el enlace de vuelta entre el zócalo y el jugador que lo contiene. Asumí que p estaba bien porque lo estábamos haciendo tan profundo en el jugador antes de estrellarnos, y por lo tanto tenía que ser algo con la Cadena o la cola. Tonto de mí. ¡Gracias Chris!

¿Fue útil?

Solución

size_t es un tipo sin firma, n es un size_t por lo que esta comparación nunca será cierta.

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

Si read devuelve -1 , este else if intentará manipular el búfer como un búfer realmente grande:

else if(n > 0) {

No estoy seguro de si los problemas que he resaltado están causando un problema, pero vale la pena solucionarlos.

Editar

Está bien, resulta que ese no era el problema, pero al adivinar desde el punto de la caída podría haber sido (¡y era!) que el puntero Player p era nulo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top