lese ich erst User und dann Passwort aus, erhalte ich für das Passwort
einen falschen Wert, lese ich jedoch erst das Passwort und dann den User
aus, erhalte ich für beides die richtigen Werte...
woran liegt das, an der dynamischen Speicherreservierung? ist diese
verkehrt? das Programm läuft auf einem uC, deswegen kann ich z.b.
getenv() nicht benutzen...
gruß
Hi Francesco,
hab den Ansatz mit strcat(newKeyword,"=") mal ausprobiert. Es ändert
sich nichts am Verhalten, ist mir ein Rätsel. Lass ich erst nach
Passwort suchen und dann nach User, gibt es keine Probleme. Suche ich
erst nach User und dann nach Passwort, bekomme ich für das PW einen
falschen Wert.
gruß
> den ersten Fehler den ich sehe:> newkeyword ist ein Byte zu kurz
Ist er nicht.
Das
strcat(newKeyword,"=\0");
ist zwar ungewöhnlich, verlängert den String aber
trotzdem nur um 1 Zeichen.
> lese ich erst User und dann Passwort aus, erhalte ich für das> Passwort einen falschen Wert, lese ich jedoch erst das Passwort> und dann den User aus, erhalte ich für beides die richtigen> Werte...
Lass mich raten:
In deinem BUFFER kommt zuerst der User und dann das Passwort.
*(value + pos) = '\0';
Das würde ich nicht tun. Das verändert den Originalstring.
Wenn du zuerst nach dem User suchst, und User im String tatsächlich
zuerst kommt, führt das dazu, dass das weiter hinten liegende
Passwort hier:
char* value = strstr(Key,newKeyword);
nicht mehr gefunden werden kann, weil dir das '\0' den
String nach dem User terminiert.
Dadurch, dass du den Returnwert auch nicht auf NULL
überprüfst, passieren dann halt seltsame Dinge, wenn
strstr nicht fündig wird.
strcat(newKeyword,"=\0");
ergänzt den String mit 2 Bytes und fügt ein terminierendes \0 hinzu.
Insgesamt 3 Bytes, weniger das terminierende Null-Byte das vom 1en Byte
überschrieben wird, also 2 Bytes mehr.
> strcat(newKeyword,"=\0");> ergänzt den String mit 2 Bytes
red keinen Unsinn.
strcat holt sich vom 2. String solange Character
bis es auf ein '\0' Zeichen trifft.
auch bei
strcat( newKeyword, "=\0abcdefghijkl" );
wird nur das erste '=' berücksichtigt, weil
das nächste Zeichen ein '\0' ist. Alles dahinter
interessiert strcat nicht mehr. Sobald es auf
ein '\0' trifft, ist für strcat() und alle
anderen str... Funktionen der String zu Ende.
Nein, bis es auf ein richtiges NULL trifft.
Probier es aus,statt strcpy cansst du auch strcat benutzen.
char buff[20]="";char*p;
strcpy(buff,"eins\0zwei\0drei\0");
for(p=buff;*p;p+=strlen(p)+1) puts(p);
Francesco.
Wenn du mir nicht glaubst, dann glaub wenigstens dem
Mann der deine C-Library geschrieben hat.
> Nein, bis es auf ein richtiges NULL trifft.
Und wie bitte soll strcat das unterscheiden können?
Im String ist ein '\0' Zeichen drinnen. Und das
ist für strcat das Zeichen, dass hier der String
zuende ist.
Das hier, mein Freund:
> char buff[20]="";char*p;> strcpy(buff,"eins\0zwei\0drei\0");> for(p=buff;*p;p+=strlen(p)+1) puts(p);
funktioniert im übrigen nicht. Wenn du Glück hast
wird grade noch "eins" ausgegeben. Wenn du
Pech hast, dann produziert dir das Ganze einen
Speicherdump des halben Hauptspeichers.
Hast du das ausprobiert bevor du das gepostet hast?
Solltest du!
Hallo Karl Heinz,
danke für deine Ausführungen. So richtig funktioniert die ganze Sache
aber leider immer noch nicht. Hab gerad keine Zeit mich mit dem Problem
weiter zu beschäftigen. Habe noch einen anderen Lösungsansatz, welcher
wunderbar funktioniert, aber nicht so elegant ist. Deswegen läuft die
Sache insgesamt. Es interessiert mich aber trotzdem, warum ich mit
diesem Weg solche Probleme habe, deswegen werde ich mich im Laufe der
Woche nocheinmal melden.
Gruß ed.
OK. Ist im Grunde ganz einfach.
Wenn dein ursprünglicher String in Buffer so ausgesehen hat
....User=abcd&\rPassword=xyz&\r.....
000000000011111 11111222222222 2333333
012345678901234 56789012345678 9012345
Jetzt suchst du nach Password zuerst:
Der Text "Password=" wird auch tatsächlich
gefunden. Er startet an Position 15. Daraus
leitest du ab, dass die Daten an Position 24
beginnen und durch die Suche nach "&\r" weist
du dass sie an Position 26 enden.
Soweit so gut. Aber jetzt kommts. Jetzt setzt
du nach den Daten einen '\0' rein
....User=abcd&\rPassword=xyz\0
000000000011111 1111122222222 2 2333333
012345678901234 5678901234567 8 9012345
Das Problem, das du jetzt erzeugt hast, besteht
darin, dass du alles was rechts vom '\0' steht
vom String abgetrennt hast. Wenn deine strlen()
von dem String vorher beispielsweise 35 war, dann
ist sie jetzt nur noch 26. Keine str... Funktion
schaut dir den Teil rechts vom '\0' nochmal an.
Jetzt suchst du weiter nach dem "User=" und findest
den auch. etc.
Jetzt drehen wir die Abfragen mal um.
Wieder zurück zur Ausgangsposition:
....User=abcd&\rPassword=xyz&\r.....
000000000011111 11111222222222 2333333
012345678901234 56789012345678 9012345
gesucht wird nach "User=". Wird auch gefunden an
Position 4. Restlicher Klimbin bringt raus, dass die
Nutzdaten an 9 anfangen und an 12 enden. Soweit so
gut. Aber dann wieder. Du ersetzt das Zeichen nach
den Daten durch einen '\0'.
Damit kriegst du
....User=abcd\0\rPassword=xyz&\r.....
00000000001111 1 11111222222222 2333333
01234567890123 4 56789012345678 9012345
Und jetzt hast du ein Problem: Der String ist wieder
verkürzt worden. Ab sofort geht der String für alle
str... Funktionen nur noch bis Position 12. An Position
13 steht der '\0' und der ist für alle str... Funktionen
das Kennzeichen dafür, dass hier der String zuende ist.
Ein strlen() würde hier zb. nur noch 12 zurückliefern.
Dadurch ist aber klar, dass bei der nächsten Suche, nämlich
nach "Password=" dieser String einfach nicht mehr gefunden
wird. Der String in dem gesucht wird ist simpel gesprochen
früher zuende, als der Suchstring da drin enthalten ist.
Für strstr ist der String an Position 12 bereits aus,
dein Suchmuster fängt aber erst bei 15 an.
Das ist das ganze Problem das du hast. Und mit der jetzigen
Vorgehensweise ist das auch nicht schön zu lösen.
Hallo Karl Heinz,
ich hätte vll. erwähnen sollen, das ich das mit dem Einfügen von '\0'
schon rausgenommen habe. Ich habe aber irgendwo noch ein Problem mit der
dynamischen Speicherallokierung. Im Buffer befindet sich ein
HTML-Formular, die relevanten Daten in dieser Form
"....User=abcd&Password=xyz\r\n". In der Funktion getKeyVal() werden
meinen Daten jetzt schon richtig extrahiert, nach Rückgabe der Zeiger
stimmen Sie dann wieder nicht (manchmal). Wenn ich Zeit hab setzte ich
den Code nochmal rein.
Gruß und Danke ed.
Hallo Karl Heinz,
hab mich nochmal rangesetzt, jetzt scheint es zu laufen. Das
Unterprogramm wird jetzt folgendermaßen aufgerufen, und die Daten
ordentlich extrahiert.
Bis jetzt läuft alles korrekt, und ich konnte noch kein Fehlverhalten
feststellen. Falls du noch Anmerkungen hast, oder der Meinung bist, man
könnte manche Sachen noch besser machen, bin ich für jede Anregung
dankbar.
Gruß ed.
> Bis jetzt läuft alles korrekt
zufällig.
Du kannst das so nicht machen:
char* rvalue = (char*)calloc(len + 1, sizeof(char));
strncpy(rvalue, value, len);
value = rvalue;
free(newKeyword);
free(rvalue);
return value;
Auch wenn du den Pointer, den du vom calloc kriegst,
beim return value nennst. Es ist immer noch derselbe
Pointer, den du vom calloc erhalten hast. Und den
Speicher auf den value (aka: rvalue) zeigt, hast du
vor dem return freigegeben.
Wenn ich mal deine Compiler-Täuschungsversuche rückgängig
mache, dann steht da:
char* rvalue = (char*)calloc(len + 1, sizeof(char));
strncpy(rvalue, value, len);
free(newKeyword);
free(rvalue);
return rvalue;
Jetzt sieht mans besser, dass du da was illegales machst.
Dein Glück ist momentan nur, dass du mit dem Pointer
ausserhalb der Funktion sofort neuen Speicher allokierst
und umkopierst. Da braucht es schon sehr viel Pech,
wenn zwischen dem free() in der Funktion und dem strcpy()
ausserhalb der Funktion sich das Betriebssystem einklinkt
und den mitlerweile freigegebenen Speicher für andere
Zwecke benutzt, sodass beim strcpy was völlig falches
gelesen wird (oder das BS eine Speicherschutzverletzung
feststellt). Nur: 'sehr viel Pech' bedeutet nicht, dass es
nie passieren wird. Laut Murphy passiert dir das genau
dann, wenn du es zum ersten Mal deinem Kunden vorführst :-)
In C gibt es keine wirklich schöne Lösung um einen String
aus einer Funktion herauszubekommen. Du hast folgende
Möglichkeiten
* Ein char Array in die Funktion hineinübergeben, dass gross
genug ist, um den String aufnehmen zu können. Zusätzlich
zum Array sollte so eine Schnittstelle auch die Grosse dieses
Arrays beinhalten, damit die Funktion ein Überlaufen des
Arrays verhindern kann. Sehr oft wird das mit einer zweiten
Funktion kombiniert, die ausrechnet wie gross denn dieses
Array sein muss.
Nachteil: Wenn der Aufrufer faul ist, dann gibt er einfach ein
konstantes Array mit einer bestimmten Größe an und hofft, dass
das immer reichen wird.
In diese Kategorie fällt auch eine berühmte 'Functiona non grata':
Was ist falsch an der C Standard-Funktion gets()?
Antwort: gets() hat keine Möglichkeit sich gegen Bufferoverflow
zu schützen. Immer fgets benutzen!
* Die Funktion allokiert genügend Speicher für den String und
gibt einen pointer darauf zurück.
Nachteil: Der Aufrufer darf nicht vergessen, auf diesen Pointer
free() aufzurufen, wenn er den String nicht mehr braucht.
* Die Funktion verwendet einen funktionslokalen Buffer, den sie
selbst verwaltet und gibt einen Pointer darauf zurück.
Nachteil: Der Aufrufer kriegt Schwierigkeiten, wenn er mehrere
Aufrufe hintereinander tätigt und nicht sofort nach Erhalt
des Pointers eine Kopie der Daten anlegt. Für ihn sieht es
dann so aus, als ob bereits erhaltene Daten, plötzlich
den Wert ändern würden.
Und bevor du fragst: Es gibt keine 'beste Möglichkeit'. Alle
3 sind Krücken, mit denen man leben muss. Hier zeigt sich
eine der grossen Schwachstellen in C.