Forum: PC-Programmierung Segfault wird durch printf() unterbunden?


von trustno1 (Gast)


Lesenswert?

Hallo zusammen,
zur Zeit arbeite ich an einem primitiven HTTP Server, für diesen wollte 
ich Funktionen schreiben, welche Logdateien schreiben.

In der Funktion log_error_write() werden mehrere Zeichenketten mit Hilfe 
von string_append() zusammen gesetzt. Da string_append() nur mit 
übergebenen char * umgehen kann, werden vorher die Zeilennummer und der 
Fehlercode mit snprintf() in eine Zeichenkette umgewandelt.

Nun ist das Problem, dass alles problemlos funktioniert, wenn ich nach 
dem snprintf() einen printf() Aufruf durchführe. Dabei ist es auch egal 
was printf() von sich gibt. Wenn ich printf() weglasse, beendet sich das 
Programm mit einem Segmentation Fault.
1
int log_error_write(config *cnf, const char *filename, uint line, uint errno, const char *error)
2
{
3
  if(-1 == cnf->logfile_fd) return 0;
4
  char *log_sequence;
5
  time_t ts;
6
  time(&ts);
7
  
8
  char iline[] = "23", ierrno[] = "555";
9
  
10
  snprintf(ierrno, 4, "%d", errno);
11
  snprintf(iline, 4, "%d", line);
12
  
13
  printf("Eigentlich sinnloser printf() Aufruf... \n");
14
  
15
  log_sequence = string_append(8, "Error: [", ierrno, "] ", " on line ", iline," in file ", filename,"...\r\n");
16
  
17
  if(-1 != write(cnf->logfile_fd, log_sequence, strlen(log_sequence)))
18
  {
19
    printf("Log geschrieben\n");
20
  }
21
  else
22
  {
23
    printf("Log nicht geschrieben\n");
24
  }
25
}
26
27
void *string_append(usint n_strings, ...)
28
{
29
  if(n_strings < 0) return 0;
30
  va_list argptr;
31
  va_list argclone;
32
  
33
  unsigned int len, remember;
34
  char *dest = NULL, *src = NULL, *dest_start = NULL;
35
  
36
  remember = n_strings;
37
  
38
  va_start(argptr, n_strings);
39
  va_copy(argclone, argptr);
40
  
41
  while(n_strings-- > 0)
42
  {
43
    len += strlen(va_arg(argclone, char *));
44
  }
45
  
46
  dest = malloc((sizeof(char) * len)+1);
47
  if(dest == NULL) return (void *)-1;
48
  dest_start = dest;
49
  n_strings = remember;
50
  
51
  while(n_strings-- > 0)
52
  {
53
    src = va_arg(argptr, char *);
54
    while(*src)
55
    {
56
      *dest++ = *src++;  
57
    }
58
  }
59
  *dest = '\0';
60
  dest = dest_start;
61
62
  va_end(argclone);
63
  va_end(argptr);
64
  
65
  return dest;
66
}
67
68
int main(void)
69
{
70
  config cnf;
71
72
  log_open_file(&cnf, "foobar.log");
73
  log_error_write(&cnf, "foobar.c", 23, 676, "Slayer!!!");
74
  return EXIT_SUCCESS;
75
}

Woran liegt das? Wie behebe ich das? Und wahrscheinlich kann man das 
doch auch irgendwie einfacher lösen oder?

Beste vorweihnachtliche Grüße
James

von trustno1 (Gast)


Lesenswert?

Uh die Zeile
1
char iline[] = "23", ierrno[] = "555";

muss eigentlich
1
char iline[5], ierrno[5];

lauten. War jetzt nur für Testzwecke verändert.

von Schorsch (Gast)


Lesenswert?

Woher kommt dein "string_append"?
Das string_append, das ich auf die Schnelle gefunden habe, will als 
ersten Parameter keinen Int, sondern einen char * auf einen Buffer, der 
für den zusamengesetzten String verwendet wird.

von Schorsch (Gast)


Lesenswert?

Arg... weiterlesen hätte geholfen...
Ignorier mich einfach.

von Karl H. (kbuchegg)


Lesenswert?

Auf die SChnelle:
len wird nirgends initial auf 0 gesetzt

von Karl H. (kbuchegg)


Lesenswert?

Allerdings frage ich mich, wozu du dir die ganze Mühe machst, den String 
erst mal mmühselig im Speicher zusammenzusetzen, anstelle von ganz 
einfach mehreren Aufrufen von write.

Dann gäbs nänmlich auch kein Speicherleck. Du gibst den allokierten 
Speicher nie wieder frei.


Was verbirgt sich hinter  cnf->logfile_fd  bzw. wie wird das File 
geöffnet?

Edit: Offenbar ein File Handle. Gibt es irgendeinen Grund warum das kein 
FILE* sein kann? Dann wäre deine Funktion
1
int log_error_write(config *cnf, const char *filename, uint line, uint errno, const char *error)
2
{
3
  if( cnf->logfile_fd == NULL )
4
    return 0;
5
6
  fprintf( cnf->logfile_fd,
7
           "Error: [%u] on line %u in file %s\r\n",
8
                 errno,
9
                 line,
10
                 filename );
11
}

von Schorsch (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> anstelle von ganz
> einfach mehreren Aufrufen von write.

Das kann daneben gehen, wenn der Server mit threads oder ge-fork()-ten 
tasks arbeitet, die sich das Log-Filehandle teilen.

Damit sich die Ausgaben nicht innerhalb einer Zeile "vermischen", macht 
es schon sinn, zuerst die Zeile im Ram vorzubereiten, und dann mit nur 
einem write rauszuschreiben.

Ich würd das allerdings mit nur einem snprintf erschlagen. Kein 
Speicherleck, und der Rückgabe-Wert geht gleich als Längenangabe fürs 
Write, d.H. die ganzen O(n)-strlen-Aufrufe entfallen.
1
char buffer[1024];
2
int len=snprintf(buffer,sizeof(buffer),"Error [%d] on line %d in file %s ...\n",ierrno,iline,filename);
3
if (len>0) write(logfile_handle,buffer,len);

von trustno1 (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Allerdings frage ich mich, wozu du dir die ganze Mühe machst, den String
> erst mal mmühselig im Speicher zusammenzusetzen, anstelle von ganz
> einfach mehreren Aufrufen von write.

->

Schorsch schrieb:
> Das kann daneben gehen, wenn der Server mit threads oder ge-fork()-ten
> tasks arbeitet, die sich das Log-Filehandle teilen.

Ja, danke Schorsch, so funktioniert es wunderbar. Ich frage mich gerade 
warum ich es mir so kompliziert gemacht habe. Aber super, nun läuft es 
ja problemlos, danke, hätte ich selbst drauf kommen sollen.

Aber merkwürdig fand ich das Problem schon.

Schönen Abend
James

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.