Forum: Mikrocontroller und Digitale Elektronik Fehler bei strlen() in mspgcc ?


von debugger (Gast)


Lesenswert?

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 ?

von Peter II (Gast)


Lesenswert?

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.

von debugger (Gast)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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.

von debugger (Gast)


Lesenswert?

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)

von Peter II (Gast)


Lesenswert?

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.

von debugger (Gast)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

mach doch mal ein test ein deine strlen funktion rein.
1
unsigned int strlen_self(unsigned char *str, unsigned int li)
2
  {
3
    if ( str[li-1] != 0 ) {
4
       senduart("schwerer fehler");
5
       while( true ) {};
6
    }
7
    unsigned int si=0;
8
    while ((str[si] != 0) && (si<li)) si++;
9
    return si;
10
  }

von debugger (Gast)


Lesenswert?

Danke, gute idee, werde ich testen !

von 2ter Gast (Gast)


Lesenswert?

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...

von Rolf Magnus (Gast)


Lesenswert?

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.

von 2ter Gast (Gast)


Lesenswert?

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

von Rolf Magnus (Gast)


Lesenswert?

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.

von 2ter Gast (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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

von 2ter Gast (Gast)


Lesenswert?

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.

von 2ter Gast (Gast)


Lesenswert?

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".

von Guru (Gast)


Lesenswert?

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?

von Guru (Gast)


Lesenswert?

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.

von 2ter Gast (Gast)


Lesenswert?

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.

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.