Segfault wird durch printf() unterbunden?

Gast #1985265
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
Gast #1985326
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.
#1985352
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
}
Gast #1985364
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);
Gast #1985384
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

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 15 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.