Archiv verlassen und diese Seite im Standarddesign anzeigen : möglicherweise ein bug in der glibc ?
hi :)
ich hab mal eine Frage zu einer kleinen template-Sprache, die ich in C geschrieben habe. Es ist zwar nicht gerade schöner Code, aber es erfüllt halbwegs seinen Zweck ;)
Der Source ist im Anhang :)
Kompilieren mit gcc -o tpltest main.c stringtools.c :)
Usage: ./tpltest [dateiname] [parameterstring]
Der Parameterstring sieht so aus wie in einer URL. Beispielsweise : name=amiga&os=linux&compiler=gcc
Bei dem Beispiel sucht das Programm in der angegebenen Datei nach den Schlüsseln
${name}, ${os} und ${compiler} und ersetzt sie durch die Werte.
Bei der unten im Archiv angehängten Datei input.t gibt es mit der glibc ein Problem (Segmentation Fault), wenn man als Parameterstring zu kurze Werte angibt (z.B. s=1 und s=11, also aufruf mit "./tpltest input.t s=1").
Dann stürzt das Programm bei "free(lOffsets);" in der Funktion strSearchReplaceAll(); mit Segmentation Fault ab, allerdings nur unter Linux. Hab's auch mal unter FreeBSD und unter Windows kompiliert - läuft einwandfrei. Ich hab alles ausprobiert. Ich glaube fast, dass es ein Bug in der glibc ist, aber ich bin mir nicht sicher, vielleicht fällt Euch irgendwas auf ?
Sitze da schon sehr lange dran und kriege langsam Gehirnschnecken *g*
Daher bin ich dankbar für jede Hilfe :)
Eins vorweg: Ich würd' dein Programm aber nicht test nennen, denn das gibts bereits!
Wird zum Auswerten der Bedingungen von ifs und Schleifen in bash scripts verwendet.
man test (http://unixhelp.ed.ac.uk/CGI/man-cgi?test)
ok :)
gcc -o tpltest stringtools.c main.c
sollte auch nichts zum make installen sein, sondern war eher als test-codesnippet gedacht :)
Bananafish
09-04-2004, 09:20
Ein Segfault in free(3) bedeutet meistens, dass die internen Strukturen von malloc(3) kaputt sind, d.h. Du hast vermutlich dadrin herumgeschrieben.
hab malloc oder free nicht angerührt :)
Hmmm, es könnte aber sein dass die Compilerflags, mit dem das Gentoo-System kompiliert wurde, zu aggressiv sind.
in der /etc/make.conf steht bei mir
CFLAGS="-O3 -march=i686 -funroll-loops -pipe"
Im Allgemeinen gibts mit malloc und free aber keine Probleme und das System läuft auch sehr stabil, nur in diesem Fall gibts Probleme.
Vielleicht probiere ich den code mal auf einem -O2, -O1 oder -O0 gebauten System aus :)
edit: ich hab's auch mal mit nem knoppix system ausprobiert (hatte zur Zeit nichts besseres zur Hand, da ich über Ostern nicht zuhause bin). Dort kommt jedenfalls dieselbe Segmentation fault - also gehe ich erstmal davon aus, dass das Problem nicht bei den CFLAGS liegt, mit denen das System gebaut wurde.
edit2:
ich hab das ganze lOffsets Charpointer-Array jetzt mal rausgenommen und lasse den String jetzt 2 mal nach den Patterns durchsuchen, anstatt die strstr()-Offsets in einem Array zwischenzuspeichern.
jetzt stürzt das Ganze beim free(buf1); in der Funktion templateLanguage(); ab .... irgendwas ist da faul, aber ich habe nicht die geringste Ahnung, was es sein könnte.
... ich bin da einfach nur noch ratlos :(
Sieht wohl so aus als müsste ich mein Programm gänzlich ohne malloc / free schreiben, da es irgendwie buggy ist ;) aber das kann's doch nicht sein :) Statische Buffer will ich vermeiden :)
im anhang hab ich mal die veränderte (gzippte) stringtools.c. Hat jemand ne Idee ? :)
Ich würd das alles anders coden.
Ohne viel in den Speicher einzulesen sondern einen Parser der die Datei zeichenweise einliest und 1:1 ausgibt bis das 1. $ auftritt. Dann rufter er ne parsing Funktion auf die wenn ein { folgt alles bis zum nächsten } in einen Puffer einliest. Den Puffer würd ich dynamisch machen und wenn er zu klein ist reallocen. Dann such ich in der Liste meiner Ersetzungsvariablen nach dem SChlüssel und gib den aus. Wenns den net gibt würd ich einfach printf( "${%s}", strkey ); machen.
Um einen Parameterstring zu Parsen haben wir in der Schule sogar mal ein Java Prog. geschrieben. Soll ich das posten? Das kann man mit nen Automaten lösen.
Hab mal kurz den Code für C rekonstruiert. Das ist hier mal alles bis auf den eigentlichen CGI-String Parser (der kommt Morgen oder auch nicht, wie ich lust hab):
/*
Automat für einen CGI-String:
S ist der Startpunkt
E ist der Endpunkt (mit (( und )) gekennzeichnet als solcher)
S->A [a-zA-Z] Variablennamen dürfen nur mit Buchstaben beginnen
A->A [0-9a-zA-Z] danach dürfen sie auch Zahlen enthalten
A->B = trennt Variablennamen von Wert
B->B [0-9a-zA-Z] alphanumerische Zeichen werden 1:1 übernommen
B->C->D->B %hh (wobei `h´ eine hexadezimale Ziffer ist) wird in das entsprechende ASCII-Zeichen übersetzt
B->B + wird in ein space übersetzt
B->S & nach einen & folgt ein weiterer Variablenname
B->E \0 makiert das Ende des Strings
Anmerkung:
%00 wird ignoriert!
((E))<-- \0 <--+------------------------> + ------------------------+
^ |
| v
+-------------- & <------------+--> % -->(C)--> [0-9a-fA-F] -->(D)--> [0-9a-fA-F] --+
| ^ |
v | v
->(S)--> [a-zA-Z] -->(A)--> = -->(B)-----------------> [0-9a-zA-Z] --------------------+
^ | ^ |
| +----+ | |
| | +----------------------------------------------------+
| v
| [0-9a-zA-Z]
| |
+------+
Als Regulärer Ausdruck:
^[a-zA-Z][0-9a-zA-Z]*=\([0-9a-zA-Z+]\|%[0-9a-fA-F]\{2}\)\(&[a-zA-Z][0-9a-zA-Z]*=\([0-9a-zA-Z+]\|%[0-9a-fA-F]\{2}\)\)*$
Tabelle für den Automaten (2-dim. Array):
ALPHA [g-zG-Z] alphabetische Zeichen ohne denen, die auch hexadezimale Ziffern sind
NUM [0-9] dezimale Ziffern
HEXAL [a-fA-F] hexadezimale Ziffern
PLUS + plus Symbol
EQ = gleichheits Ziechen
PERC % prozent Zeichen
NIL \0 terminierende Null (NIL, '\0', 0)
ELSE [:else:] alle anderen Zeichen
*/
#define S 0 /* Start */
#define A 1
#define B 2
#define C 3
#define D 4
#define E 5 /* Ende */
#define ERR 6 /* Fehler */
#define ALPHA 0
#define NUM 1
#define HEXAL 2
#define PLUS 4
#define AND 5
#define EQ 6
#define PERC 7
#define NIL 8
#define ELSE 9
#define IS_END( ROW ) ((ROW) == E)
const int cgi_map[][] =
{ /* 0 1 3 4 5 6 7 8 9 */
/* ALPHA NUM HEXAL PLUS AND EQ PERC NIL ELSE */
/* S: 0 */ { A, ERR, A, ERR, ERR, ERR, ERR, ERR, ERR }, /* Start */
/* A: 1 */ { A, A, A, ERR, ERR, ERR, ERR, ERR, ERR },
/* B: 2 */ { B, B, B, B, S, ERR, C, ERR, E },
/* C: 3 */ { ERR, D, D, ERR, ERR, ERR, ERR, ERR, ERR },
/* D: 4 */ { ERR, B, B, ERR, ERR, ERR, ERR, ERR, ERR },
/* E: 5 */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* Ende */
/* ERR: 6 */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR } /* Fehler */
};
/*
Übersetzen eines Zeichens in den zugehörigen Spaltenindex:
*/
size_t get_column( char sym ) {
if( ( sym >= 'g' && sym <= 'z' ) ||
( sym >= 'G' && sym <= 'Z' ) ) {
return ALPHA;
}
else if( sym >= '0' && <= '9' ) {
return NUM;
}
else if( ( sym >= 'a' && <= 'f' ) ||
( sym >= 'A' && <= 'F' ) ) {
return HEXAL;
}
else if( sym == '+' ) {
return PLUS;
}
else if( sym == '=' ) {
return EQ;
}
else if( sym == '%' ) {
return PERC;
}
else if( sym == '\0' ) {
return NIL;
}
else {
return ELSE;
}
}
Achja, in Java gibts ne Klasse StringBuffer. Hab auch g'wschind etwas vergleichbares für C g'schrieben. Braucht man um die Variablennamen und Werte zusammenzubaun.
/*
Ein Simpler String-Buffer:
*/
#define BLOCKSIZE 64
typedef struct strbuf_s {
size_t size;
size_t curpos;
char * data;
} strbuf_t;
strbuf_t * strbuf_init ( strbuf_t * buf, size_t initsize );
int strbuf_addc ( strbuf_t * buf, char c );
int strbuf_addstr ( strbuf_t * buf, char * str );
const char * strbuf_str ( strbuf_t * buf );
char * strbuf_strdup ( strbuf_t * buf );
int strbuf_resize ( strbuf_t * buf, size_t size );
void strbuf_clear ( strbuf_t * buf );
void strbuf_destroy( strbuf_t * buf );
strbuf_t * strbuf_init( strbuf_t * buf, size_t initsize ) {
buf->data = malloc( initsize );
if( buf->data ) {
buf->size = initsize;
buf->curpos = 0;
return buf;
}
else {
return NULL;
}
}
int strbuf_addc( strbuf_t * buf, char c ) {
if( buf->size == buf->curpos ) {
if( !strbuf_resize( buf, buf->size + BLOCKSIZE ) ) {
return 0;
}
}
buf->data[ buf->curpos ++ ] = c;
return 1;
}
int strbuf_addstr( strbuf_t * buf, char * str ) {
size_t len = strlen( str ) + 1;
if( buf->size < buf->curpos + len ) {
if( !strbuf_resize( buf, len > BUFLEN ? len : BUFLEN ) ) {
return 0;
}
}
buf->data[ buf->curpos ] = '\0';
strcat( buf->data, str );
buf->curpos += len;
return 1;
}
const char * strbuf_str( strbuf_t * buf ) {
if( buf->curpos == 0 || buf->data[ buf->curpos - 1 ] != '\0' ) {
if( !strbuf_addc( buf, '\0' ) ) {
return NULL;
}
}
return buf->str;
}
char * strbuf_strdup( strbuf_t * buf ) {
const char * str = strbuf_str( buf );
if( str ) { return strdup( str ); }
else { return NULL; }
}
int strbuf_resize( strbuf_t * buf, size_t size ) {
char * data = realloc( buf->data, size );
if( !data ) {
return 0;
}
else {
buf->data = data;
buf->size = size;
return 1;
}
}
void strbuf_clear( strbuf_t * buf ) {
buf->curpos = 0;
}
void strbuf_destroy( strbuf_t * buf ) {
free( buf->data );
}
Ein Automat für deine Templ.-Sprache würde ca. so aussehn:
+-- [^$] <--+ +--> [0-9a-zA-Z_] --+
| | | |
| +---------+ +--------+ +--------+
v | | v
-->((S))<------------ } <----------(C)------+
| |
+--> $ --(A)--> { -->(B)--> [a-zA-Z] --+
Bzw. so:
+-- [^$] <--+ +--> [0-9a-zA-Z_] --+
| | | |
| +---------+ +--------+ +--------+
v | | v
-->(S)<------------ } <----------(C)-------+
| |
+--> $ --(A)--> { -->(B)--> [a-zA-Z] --+
|
v
EOF
|
v
((E))
vielen dank, ich werd den code mal etwas umstricken :)
parseParams werde ich erstmal ganz neu schreiben da es noch buggy ist und strtok verwendet, was man lieber vermeiden sollte :)
Die Segmentation Fault in templateLanguage() ist mir nach wie vor ein Rätsel, da es mit der FreeBSD-libc läuft :)
Ich setz mich erstmal dran und bau das um und poste es dann hier
vielen Dank nochmal :)
hab noch ein if in die resize funktion eingebaut:
int strbuf_resize( strbuf_t * buf, size_t size ) {
char * data = realloc( buf->data, size );
if( !data ) {
return 0;
}
else {
buf->data = data;
buf->size = size;
if( buf->curpos > size ) {
/* könnt ja auch verkleinert werden */
buf->curpos = size;
}
return 1;
}
}
Powered by vBulletin® Version 4.2.5 Copyright ©2025 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.