Forum: PC-Programmierung C++: Segmentation fault in meinem WebsocketServer


von Daniel A. (daniel-a)


Lesenswert?

Für eine grosse Webseite, welche ich als Privatprojekt am entwickeln 
bin, brauche ich einen Server, welcher das HTTP und das Websocket 
Protokoll unterstützt. Aufgrund grösserer Flexibilität habe ich mich 
entschieden einen eigenen WebsocketServer in C++ zu programmieren. 
Dieser funktioniert auch bereits teilweise, aber leider kommt es beim 
aufrufen einer Seite manchmal zu einem Segmentation fault. Ich konnte 
leider noch nicht herausfinden, was zu diesem Segmentation fault führt, 
und hoffe hier auf Tipps, Hinweise, Kritik und/oder 
Verbesserungsvorschläge.

Den Sourcecode gibt es hier:
  http://87.102.188.235/WebsocketServer.zip

GDB hat mir folgendes verraten:
1
Program received signal SIGSEGV, Segmentation fault.
2
[Switching to Thread 0x7ffff6e92700 (LWP 5005)]
3
0x00000000004052d0 in client::ws_send(void*) ()
4
(gdb) backtrace
5
#0  0x00000000004052d0 in client::ws_send(void*) ()
6
#1  0x00000000004059a5 in task::solve(unsigned char*) ()
7
#2  0x0000000000402eca in c_worker::do_work() ()
8
#3  0x0000000000402ff2 in worker() ()
9
#4  0x00000000004026b0 in callThreadFunc(void*) ()
10
#5  0x00007ffff7bc7b50 in start_thread (arg=<optimized out>) at pthread_create.c:304
11
#6  0x00007ffff6f6f0ed in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
12
#7  0x0000000000000000 in ?? ()

von Dr. Sommer (Gast)


Lesenswert?

Und jetzt erwartest du dass sich jemand gratis den Kopf für dich 
zerbricht und dein Programm auseinander nimmt um deinen Fehler zu 
finden?

Das darfst du schön selber machen. Kompiliere & Linke mit "-g" um 
bessere debug-Informationen zu erhalten. Schaue in GDB nach wo genau der 
Fehler auftritt. Finde heraus was den Fehler verursacht. Verwende 
"valgrind" um Speicherfehler zu finden ( Fehler die nicht sofort zum 
Absturz führen ).

von Dr. Sommer (Gast)


Lesenswert?

1
void forEachFile(const char* path,void(*func)(const char*,const char*)){
2
3
    DIR *dp = opendir(path);
4
    struct dirent *dirp;
5
6
    if(!dp) {
7
      printf("error: failed to opendir \"%s\"",path);
8
      return;
9
    }
10
11
    char* p = (char*)malloc(1024);
12
    while( (dirp=readdir(dp)) ){
13
      if(!dirp->d_name||dirp->d_name[0]=='.'||!dirp->d_name[0])
14
        continue;
15
      sprintf(p,"%s/%s",path,dirp->d_name);
16
      (*func)(p,m_basename(dirp->d_name));
17
    }
18
    free(p);
19
20
    closedir(dp);
21
22
    return;
23
}
1
  FILE* f = fopen(path,"rb");
2
  if(!f){
3
    printf("error: cann't open file %s\n",path);
4
    redirect(buff,"/");
5
    return false;
6
  }
1
        for(unsigned j=0;j<header_field_list_length;j++){
2
          if(!strcmp(header_field_list_names[j],(char*)&buff[n])){
Das nennst du C++ Code?! Das sieht eher nach "schönstem" C aus.
1
    c_worker** _workers = (c_worker**)realloc(workers,(i+1)*sizeof(c_worker*));
Was ist das?! Schonmal von std::vector gehört?
1
  new server("0.0.0.0",80);
Speicher aufräumen, braucht ja keiner?!

etc. etc. ...

von Peter II (Gast)


Lesenswert?

der code ist furchtbar!

Wenig C++ - viel C - viele mögliche fehler!

>  str = (char*)realloc(str,s);
>  str[s-1]=0;

was ist wenn kein Speicher da ist?

> #include "c_worker.cpp"
wer macht denn so etwas?

auch sollte man wenn man schon C++ macht eine string lib benutzen. Dann 
könnte man sich soetwas unlesbares sparen:

> for(a=str+s-1;a>=str  &&(*a==' '||*a==0);a--);

Da ist überhaupt keine sinnvolle Struktur erkennbar.

Warum wird das ganze http Protokoll in Client.cpp zerlegt? Dafür 
schreibt man sich eine http Klasse.

Auch für die Socket sollte man an anfang gleich eine Klasse oder eine 
fertige C++ lib nutzten. So verliert man doch alle Vorteile der 
Fehlerbehandlung von C++

die http Header sind ideal für eine std::map - aber hier wird wieder 
manuell mit listen gearbeitet.


Mit diesen Code würde ich keine Webserver laufen lassen, hier ist es nur 
eine Frage der Zeit bis jemand von außen mit einen Buffer Overflow das 
System lahmlegt oder gleich übernimmt.

Ein fehler wird hier nicht so schnell jemand finden.

von g457 (Gast)


Lesenswert?

Ich tippse auf out-of-Memory - hab mindestens ein leak gefunden [0] das 
gefixt werden will.

Und jetzt wieder zurück zur Glaskugel.

[0] spoiler: [1]
[1] c_worker::buff

von Daniel A. (daniel-a)


Lesenswert?

g457 schrieb:
> hab mindestens ein leak gefunden [0] das
> gefixt werden will.
...
> [1] c_worker::buff

Das ist kein leak, weil:
  a) c_worker::buff nur einmal, bei der Initialisierung speicher 
reserviert
  b) Immer benötigt wird
  c) Das Programm nie beendet wird

von Dr. Sommer (Gast)


Lesenswert?

Dann hoffen wir mal, dass auch in zukünftigen Versionen niemals später 
Worker herausgenommen werden. Denn dann musst du dich ja daran erinnern 
(mit Post-It am Monitor zB) den Speicher dann doch freizugeben.
Alternativ kann man natürlich auch sauberen Code schreiben der auch 
später noch wiederverwendet/modifiziert werden kann:
1
#include <memory>
2
3
static constexpr BUFF_MAX = 1024; // #define ist gefährlich und unnötig, besser Konstanten verwenden
4
class c_worker {
5
  std::unique_ptr<unsigned char[]> buff;
6
...
7
c_worker::c_worker () {
8
  buff = std::unique_ptr<unsigned char[]> (new unsigned char [BUFF_MAX]);
9
}
Und schon wird der "buff" automatisch gelöscht und du sparst dir das 
Post-It.
sizeof(unsigned char) ist übrigens immer 1.

von Daniel A. (daniel-a)


Lesenswert?

Danke für die ganzen Hinweise.

Ich werde diese natürlich berücksichtigen, sobald ich Zeit habe.

von g457 (Gast)


Lesenswert?

> Das ist kein leak, weil:

Doch, ist ein klassischer Leak.

> a) c_worker::buff nur einmal, bei der Initialisierung speicher reserviert

..jede Instanz von c_worker

> b) Immer benötigt wird

..maximal so lange wie die jeweilige Instanz von c_worker lebt.

> c) Das Programm nie beendet wird

Sowas gibts per se nicht.

Glaubs mir. Räum auf, sonst findest Du die anderen Leaks nie.

von hmm... (Gast)


Lesenswert?

Lass mal clang mit dem Analyzer drüber laufen und beseitige ALLE 
Warnungen die geworfen werden. Dann reden wir weiter...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Core dump erstellen lassen und das post-mortem Dump analysieren, z.B. 
mit Debugger.

Je nachdem, was für ein Fehler es ist, kann es kontraproduktiv sein, auf 
Verdacht die Quelle an X Stellen zu ändern.  Wenn die Fehlstelle nicht 
dabei ist (wahrscheinlich) und die Änderungen den Bug lediglich 
maskieren, grüßt spätestens in ein paar Wochen das Murmeltier...

von mar IO (Gast)


Lesenswert?

Schau dir mal POCO http://pocoproject.org an! Hier findest Du schon 
einige Bauteile, die Du gleich verwenden kannst.

WebSocket findest Du in der Doku unter Poco::Net WebSocket.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.