Diffusion d'un appel vers la file d'attente STL < std :: string > provoque Segfault lorsque String est lu hors du socket

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

Question

J'utilise une file d'attente STL en tant que file d'entrée, elle contient std :: strings, que j'ai alias alias en tant que chaîne utilisant un typedef. Je lis la chaîne d'entrée d'un socket - en utilisant les sockets Berkeley. Il est lu dans un tableau de mémoire tampon de caractères, puis utilisé pour définir une chaîne qui est transmise à la file d'attente. Cela ne se produit que pour la file d'attente d'entrée - la file d'attente de sortie, qui ne reçoit pas ses chaînes à partir de la lecture du socket, fonctionne correctement.

Voici le code correspondant:

// 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 fonction stripNewline est une fonction utilitaire permettant d’effacer les nouvelles lignes de la fin de l'entrée reçue. Je l'ai mis pour aider au débogage, il n'était pas là lorsque le segfault est apparu pour la première fois:

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

C’est ici que l’entrée commence et est introduite dans l’entrée p- > sous forme de chaîne. p- > input insère simplement la chaîne d'entrée dans la file d'attente:

// 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 file d'attente entrante est définie ici à l'intérieur de la classe de joueur, de même que la file d'attente sortante, qui fonctionne correctement:

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

String est simplement défini comme une typedef de std :: string:

typedef std::string String;

ÉDITER : correction de la typedef en arrière, ce que je reçois pour l'écrire de mémoire lorsque distrait, c'était correct dans le code.

La sortie avant l'erreur de segmentation et la sortie de catchsegv est la suivante:

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]

Comme je peux dire que la chaîne est saine, alors je ne sais pas ce qui pourrait causer l'étouffement de la file d'attente. Je vais continuer à le fouiller et voir ce que je vais trouver, mais j'apprécierais vraiment toutes les informations que la communauté Stack Overflow peut offrir à ce sujet.

MODIFIÉ pour ajouter les résultats de la poursuite de la lecture:

J'ai essayé deux autres méthodes pour insérer buf dans la chaîne qui va à l'entrée p: >

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

et

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

Les deux ont eu le même résultat. J'ai essayé d'envoyer la mémoire tampon à un caractère standard caractère par caractère pour m'assurer qu'aucun caractère étrange ne se faufile:

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

Le résultat était:

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

Donc, toujours pas d'idées. C'est toute la mémoire statique locale, donc pas un problème de mémoire dymanique à moins que ce soit vraiment étrange (bien sûr, mémoire dynamique === problèmes étranges, donc c'est toujours une possibilité).

En outre: à l'origine, size_t (un type entier non signé) était comparé à des valeurs inférieures à zéro. Modifié à la fois par ssize_t (type entier signé) et par un simple int sans changement - toujours bloqué. Merci Chris, pas la réponse mais toujours une bonne prise!

Répondu : bêtement, dans mon nid de programme, j'ai oublié de définir Player * p dans la classe Socket. P est le lien de retour entre le socket et le lecteur qui le contient. J'avais supposé que p allait bien parce que nous avions tellement pénétré profondément dans le lecteur avant de planter et qu'il devait donc s'agir de quelque chose avec la chaîne ou la file d'attente. Que je suis bête. Merci Chris!

Était-ce utile?

La solution

size_t est un type non signé, n est un size_t afin que cette comparaison ne soit jamais vraie.

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

Si read renvoie -1 , le sinon si va essayer de manipuler le tampon comme un très gros tampon:

else if(n > 0) {

Je ne sais pas si les problèmes que j'ai soulignés sont à l'origine d'un problème, mais ils méritent d'être corrigés.

Modifier

OK, il s’avère que ce n’était pas le problème, mais en supposant que, dès le moment du crash, il aurait pu (et était!) que le pointeur Player p était nul.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top