Halo,
ein mspgcc-Programm von mir für den MSP430F149 hatte das Problem, dass
nach einer gewissen Laufzeit (> 1 Stunde) der Inhalt von Stringvariablen
ungewollt überschrieben wurde.
Das passierte in der Nähe der strlen()-Funtion (die aber nicht die dann
überschriebenen String-Variablen verwendete).
Nachdem ich die strlen()-Funktion jetzt durch eine selbst geschriebene
Funktion ersetzt habe, tritt der Fehler nicht mehr auf.
Hat jemand ähnliche Erfahrungen gemacht ?
Hier der Code meiner eigenen Funktion :
unsigned int strlen_self(unsigned char *str, unsigned int li)
{
unsigned int si=0;
while ((str[si] != 0) && (si<li)) si++;
return si;
}
wobei die Funktion so aufgerufen wird :
len_str = strlen_self(dummystr, sizeof(dummystr)) /*char dummystr[50*/
BTW: Gibt es eine Möglichkeit, die maximale Länge eines per "char *str"
übergebenen Strings auch innerhalb der Funktion mit sizeof()
festzustellen ?
dann ist doch das Problem klar. du übeschreibst dir das letze 0 byte
deines Strings umd damit liefert strlen zu viel zurück.
Du musst also den überschreiber finden und nicht eine neue strlen
funktion programmieren.
Danke für den Tipp, das werde ich nochmals genauer überprüfen.
Allerdings logge ich die mit strlen() ermittelte Stringlänge über eine
UART-Ausgabe mit und da wurden eigentlich immer plausible Werte
angezeigt, die nicht über den maximalen Stringlängen lagen.
debugger schrieb:> Allerdings logge ich die mit strlen() ermittelte Stringlänge über eine> UART-Ausgabe mit und da wurden eigentlich immer plausible Werte> angezeigt
wenn du dir den speicher überschreibst, kommt vermutlich überhaupt keine
ausgabe mehr, weil das Programm einfach was anders machst als du
erwartest.
Prüfe doch erstmal alle stellen wo du etwas in den string schreibst.
Peter II schrieb:> wenn du dir den speicher überschreibst, kommt vermutlich überhaupt keine> ausgabe mehr, weil das Programm einfach was anders machst als du> erwartest.
Nein, das ist ja das kuriose : das Programm läuft ganz normal weiter. Es
werden nur drei Strings überschrieben (mit Leerzeichen), in den
Telefonnummern gespeichert sind, die über AT-Befehle für das Versenden
von SMS verwendet werden.
Damit ist natürlich die SMS-Kommunikation unterbrochen, aber das
Programm selbst läuft auf dem MSP430F149 trotzdem weiter (in einer
Endlos-while-Schleife)
strlen macht genau das gleich wie du gemachst hat, nur das es nicht auf
die maximale länge prüft.
Damit bleibt nur die Möglichkeit übrig das es kein 0 byte mehr gibt.
Zeigt doch mal den code wenn er nicht geheim ist.
Der Code besteht aus elf (11) separaten C-Files mit zusammen etlichen
tausend Zeilen, den kan ich leider nicht einfach so herzeigen.
Aber trotzdem erst mal danke für den Hinweis, damit weiss ich jetzt
genauer, nach was ich suchen muss.
Wenn ich das Problem gefunden habe, werde ich es hier posten.
strlen_self() kennt man auch unter dem Namen strnlen() :). Aber im
Allgemeinen sind strlen, strcpy & co. geächtete Funktionen, da diese die
max. Länge des Strings nicht berücksichtigen daher unsicher sind. Also
lieber strnlen, strncpy & co benutzen...
2ter Gast schrieb:> strlen_self() kennt man auch unter dem Namen strnlen() :). Aber im> Allgemeinen sind strlen, strcpy & co. geächtete Funktionen, da diese die> max. Länge des Strings nicht berücksichtigen daher unsicher sind.
Bei strcpy gebe ich dir recht, weil es stillschweigend davon ausgeht,
daß für den Zielstring genug Platz ist, aber strlen? Die Funktion gibt
entweder den richtigen Wert zurück, oder der String ist kaputt, weil ihm
die Nullterminierung fehlt. strnlen läuft dann zwar immerhin nicht über
das Ende des für den String vorgesehenen Speicherplatzes hinaus, aber es
wird trotzdem Mist zurückgeben.
Rolf Magnus schrieb:> Bei strcpy gebe ich dir recht, weil es stillschweigend davon ausgeht,> daß für den Zielstring genug Platz ist, aber strlen? Die Funktion gibt> entweder den richtigen Wert zurück, oder der String ist kaputt, weil ihm> die Nullterminierung fehlt. strnlen läuft dann zwar immerhin nicht über> das Ende des für den String vorgesehenen Speicherplatzes hinaus, aber es> wird trotzdem Mist zurückgeben.
IHMO nicht schön sowas so zu handhaben.
Auf dem Mikrocontroller kannst du den RAM bzw. Flash Adressbereich des
Mikrocontrollers verlassen und landest bei den SFR. Wäre schon, blöd
wenn diese Lese-sensitiv wären. Mag auf diesem uC nicht sein, aber gibt
soft core uc auf FPGAs auf denen z.B. FIFOs memory mapped eingebunden
sind. Diese können gelesen werden, in dem ein Lesezugriff ein memory
mapped input register erfolgt....
Auf dem PC erntet man eine Zugriffsverletzung, wenn man "Pech" hat,
passiert aber auch nichts
2ter Gast schrieb:> IHMO nicht schön sowas so zu handhaben.>> Auf dem Mikrocontroller kannst du den RAM bzw. Flash Adressbereich des> Mikrocontrollers verlassen und landest bei den SFR. Wäre schon, blöd> wenn diese Lese-sensitiv wären. Mag auf diesem uC nicht sein, aber gibt> soft core uc auf FPGAs auf denen z.B. FIFOs memory mapped eingebunden> sind. Diese können gelesen werden, in dem ein Lesezugriff ein memory> mapped input register erfolgt....
Naja, durch die Anwendung von strnlen() hat man den Fehler allerdings
nicht behoben, sondern nur seine Auswirkungen verringert.
> Auf dem PC erntet man eine Zugriffsverletzung, wenn man "Pech" hat,> passiert aber auch nichts
Mit strnlen() hat man immer das Pech, daß nichts passiert. Einen
Fehler hat das Programm aber trotzdem, wenn der String nicht
nullterminiert ist. Davon abgesehen müßte man dann durchs ganze Programm
die Mögliichkeit durchziehen, eine maximale Stringlänge anzugeben, damit
man überhaupt was hat, was man an strnlen() übergeben kann.
Ist es nicht besser, mögliche Fehlerquellen zu vermeiden?
Also mir ist es lieber einen Fehler abzufangen, als darauf zu blind zu
vertrauen, dass alles gut geht ( egal, ob ich für den PC oder für den uC
einen Programm schreibe).
Sicher hast Du recht, dass das Programm ein Fehler hat, wenn sich der
String mit bekannter Länge im Flash steht und plötzlich nicht mehr ins
Array passt. Was machst du aber, wenn Du die Länge nicht kennst?
Einfach annehmen, dass der String schon eine gewisse Maximallänge hat?
Um fehlerfreiere Programme zu schreiben ist auch ein Stück Fleißarbeit.
Wie weit man geht oder es braucht, muss aber jeder für sich entscheiden.
2ter Gast schrieb:> Ist es nicht besser, mögliche Fehlerquellen zu vermeiden?
Natürlich.
Aber du läufst gerade in ein 2-scheidiges Schwert hinein.
Wenn der Rest des Programmes stimmt, dann KANN strlen keinen Fehler
produzieren. Und jetzt kommt die 2-te Schneide des Schwertes ins Spiel.
Machst du zu viele Korrektur-Hacks in dein Programm hinein, so läufst du
in das Problem hinein, dass du keine Programmfehler mehr bemerkst und
sie korrigierst. Statt dessen sammeln sich die Fehler an bis es dann
irgendwann einmal trotz aller Autokorrekturen ganz gewaltig kracht.
Been there - done that
Karl Heinz Buchegger schrieb:> Machst du zu viele Korrektur-Hacks in dein Programm hinein, so läufst du> in das Problem hinein, dass du keine Programmfehler mehr bemerkst und> sie korrigierst. Statt dessen sammeln sich die Fehler an bis es dann> irgendwann einmal trotz aller Autokorrekturen ganz gewaltig kracht.
Damit macht man keine Korrektur-Hacks! Das habe ich auch nicht
geschrieben. Damit entdeckt man man Fehler und versucht diese zu
beheben. Man gibt zum Beispiel den Zustand des Programms aus und
analysiert, was passiert ist.
Da war ich zu fix...
Und es geht ja beim debugging um das FINDEN und BEHEBEN beim Debbugging.
So kann ich wenigstens etwas feststellen und verhindere das "gewaltig
krachen".
Was mich stutzig macht, ist, das er schreibt, das mit seiner eigenen
Version von strnlen der "Fehler" nicht mehr auftritt.
Wenn durch die neue Fassung von strlen "der Fehler" nicht mehr auftritt
dann ist die naheliegendste Hypothese die (wer hat gesagt Hypthosis non
figo?), dass in der ursprünglichen Version der Ergebniswert dieses
strlen in einem folgenden Schritt als Argument verwendet wurde, so das
ein String ungewollt überschrieben wurde.
Wenn das aber stimmt, dann muss schon in einem früheren Schritt das
Argument dieses Aufrufs von strlen ungewollt und unzulässig verändert
worden sein so das strln etwas falsche zurückgibt, denn sonst würde die
neue Version von strlen ja nicht den nachfolgenden Fehler verhindern.
D.h. die eigentliche Ursache ist schon vor Aufruf der strlen-Funktion
gesetzt worden.
Die ursprüngliche Fragestellung war also irgendwie zu kurz gegriffen,
vor allem wenn man beachtet das so eine Standard-Funktion wie strlen
wahrscheinlich schon Millionenmal "getestet" worden ist.
Mir scheint der Beitrag von Karl Heinz irgendwie in die selbe Richtung
zu gehen, aber die kleine Subdiskussion zwischen 2ter Gast und ihm
verwirrt mich gerade ein wenig.
Klar was ich meine und hilft das weiter?
Das hier
>Wenn das aber stimmt, dann muss schon in einem früheren Schritt das>Argument dieses Aufrufs von strlen ungewollt und unzulässig verändert>worden sein so das strln etwas falsche zurückgibt, denn sonst würde die>neue Version von strlen ja nicht den nachfolgenden Fehler verhindern.
ist nicht ganz vollständig.
Es kann ja auch sein, das der erste String nicht verändert sondern auch
falsch eingelesen oder initialisiert worden ist. Man kennt ja den
Quellcode nicht.
Ok, die Diskussion artet wohl etwas aus.
1) Sowohl mit strlen() als auch mit strnlen() kannst du den Fehler
detektieren.
2) Das Problem bei strlen() ist, dass dieser über die Grenzen deines
buffers hinausgehen kann, wenn er das Terminierungszeichen nicht findet.
Bsp.: Also dein Stringbuffer ist 80 Zeichen lang, aber auf Grund eines
Fehlers liest strlen() über die Grenzen des Buffers hinaus; er findet
ein vermeintliches Terminierungszeichen erst nachdem 1027ten Zeichen
(das macht strnlen(), richtig angewendet, eben nicht).
3) Über die "Grenzen lesen" sollte man nicht. Wie Du den gefundenen
Fehler nun behandelst, liegt bei Dir.