Ich habe eine Funktion, nach dem diese x Mal problemlos aufgerufen wird,
springt das Programm nach einem x+n Aufruf zum HardFault Handler. Und
zwar beim Verlassen der der Funktion. Gibt es eine Möglichkeit raus zu
finden, woran das liegt? Kann man irgendwie die Rücksprungabdresse vom
Stack überwachen, um zu sehen, wohin nach dem Funktionsaufruf gesprungen
wird?
send_response funktionier allein für sich wunderbar, ohne die Zeile:
notify_data = strrpl(notify_data, "UUID", device_id);
Sobald die Zeile drin ist und die Fkt x Mal aufgerufen wird, kommt der
Hardfault Handler. Habe jetzt auf die Schnelle die Ausgabe der Register
nach dem Handler Einsprung gemacht:
CFSR = 0x400
HFSR = 0x40000000
Bit 10 IMPRECISERR: Imprecise data bus error
When the processor sets this bit to 1, it does not write a fault address
to the BFAR.
This is an asynchronous fault. Therefore, if it is detected when the
priority of the current
process is higher than the bus fault priority, the bus fault becomes
pending and becomes
active only when the processor returns from all higher priority
processes. If a precise fault
occurs before the processor enters the handler for the imprecise bus
fault, the handler detects
both IMPRECISERR set to 1 and one of the precise fault status bits set
to 1.
0: No imprecise data bus error
1: A data bus error has occurred, but the return address in the stack
frame is not related to
the instruction that caused the error.
Aha interessant. Was kann ich damit anfangen?
Wenn strrpl (wegen OOM) NULL zurück gibt, machst Du einen strlen(NULL).
Das könnte Deinen Bus Error verursachen.
Außerdem sehe ich das Du sowas machst:
1
notify_data=malloc(...);
2
[...]
3
notify_data=strrpl(...);
Da fehlt ein free() für das malloc(), denn strrpl() allokiert ja selbst
Speicher. Du überschreibst einfach den Pointer ohne den Block
freizugeben.
>Da fehlt ein free() für das malloc(), denn strrpl() allokiert ja selbst>Speicher. Du überschreibst einfach den Pointer ohne den Block>freizugeben.
Was soll da free() bewirken? Dann würden ja die Daten verloren gehen,
bevor strrpl ausgeführt wird.
Der Aufruf von free() für den zuerst allokierten Block muss natürlich
nach dem Aufruf von strrepl() erfolgen. Im Moment wird der Zeiger auf
den zuerst allokierten Block schlicht "weggeworfen" und der Block nie
freigegeben (memory leak).
1
char*notify_data;
2
char*to_free;
3
notify_data=malloc(...);
4
[...]
5
to_free=notify_data;/* Pointer für free() aufheben */
6
notify_data=strrpl(...);
7
free(to_free);/* Jetzt ist der erste Block auf wieder im Pool */
Guast schrieb:> Gibt es eine Möglichkeit raus zu> finden, woran das liegt?
Du musst weitere faults zulassen, dann kannst du in den Statusregistern
besser die Ursache finden. Das hier steht in einem alten Beispielcode
drin, auf dem ich mal für einen SAM3S debuggt habe:
1
/*
2
* Enable additional exceptions, so they don't escalate to
3
* HardFault immediately.
4
*/
5
SCB->SHCSR|=SCB_SHCSR_USGFAULTENA_Msk|
6
SCB_SHCSR_BUSFAULTENA_Msk|
7
SCB_SHCSR_MEMFAULTENA_Msk;
Diese faults sind initial nach einem Reset alle verboten, was dazu
führt, dass sie letztlich in einen hardfault münden.
Hmm, bewirkt irgendwie nichts. Kann man sich irgendwie anzeigen lassen,
wieviel Platz noch im Heap frei ist? So könnte ich einfach
kontrollieren, ob es sich tatsächlich um memory leaks handelt.
Läßt sich die Funktion ohne Probleme aufrufen. Wenn ich den Block
reinnehme aber die Funktionen mit strrpl auslasse, läßt sich die
Funktion ebenfalls problemlos aufrufen. Sobald ich aber strrpl und die
Sendefuntionen benutze, kracht es.
malloc/free auf einem µC ist eher ungewöhnlich. Unabhängig davon ist die
"wer macht wann den free()?" fehleranfällig. Erschwerend kommt hinzu,
dass in diesem Fall das Alloziieren und die Freigabe nicht in einem
Block/Funktion, sondern über zwei Funktionen verteilt geschieht.
Mir erscheint das unnötig kompliziert:
Versuche komplett ohne strrpl() und ohne malloc/free auszukommen, auch
die vielen String-Funktionsaufrufe sind vermutlich nicht nötig. Das
memcpy() sieht auch verdächtig aus.
Nach dem Motto:
wobei SSDP_M_SEARCH_RESPONSE die nötigen Platzhalter %s etc. enthält.
Ich würde die Konstante direkt einfügen, damit die Anzahl der
Platzhalter und der Parameter "zusammen" sind.
Wenn es unbedingt mit malloc() sein soll, dann würde ich versuchen, die
Zuweisung so umzuschreiben, dass der Compiler eine erneute Zuweisung des
Zeigers verhindert (habe das im Zusammenhang mit malloc() noch nie
probiert).
1
char * const notify_data = malloc(...);
Wenn es unbedingt mit strrpl() erfolgen soll, dann würde ich den Puffer
für die Rückgabe als Parameter mitgeben, so wie bei snprintf(). Das
verhindert die verteilte Zuständigkeit für malloc() und free().
Wenn strrpl() noch einen längeren Namen hätte, könnten auch andere den
Zweck der Funktion schneller erkennen ;-) Das sechs-Zeichen-Limit stammt
aus der C-Steinzeit.
Irgendwie werden hier Puffer mehrfach angelegt. Warum wird nicht nur der
pkt_buf alloziiert, dann dann die Antwort direkt hineingeschrieben? D.
h. es braucht kein notify_data. Das spart auch das memcpy(). Aber auch
hier sehe ich keinen Grund, den Speicher für pkt_buf dynamisch
anzufordern.
Hier wird ordentlich geprüft:
Das ist nicht konsequent, weil im zweiten Fall nicht auf "out of memory"
geprüft wird. Dann gäbe es auch keinen "hard fault". Da der aufrufende
Programmteil sicherlich ordentlich programmiert ist, würde im Falle
eines "out of memory"-Fehlers dies protokolliert ;-)
Das
Mich persönlich verwirrt dies ohnehin - memcpy() weist eher auf ein
"byte array" hin, ansonsten würde ich hier strcpy() einsetzen. Ist es
ein "byte array", dann finde ich die Anwendung von strlen() auf das
"byte array" etwas unglücklich.
Wobei das ein guter Grund wäre, eine C++-Klasse einzusetzen, die das
intern regelt. Zusätzlich würde C++ vermutlich auch die Verwendung von
"casts" erzwingen, welche die Lesbarkeit enorm verbessern würden.
Das hier
1
if (!upnp_pcb) return 0;
ist ganz großer Murks. Denn dies verhindert die Freigabe mittels free()
am Ende.
> Kann man sich irgendwie anzeigen lassen,> wieviel Platz noch im Heap frei ist? So könnte ich einfach> kontrollieren, ob es sich tatsächlich um memory leaks handelt.
Lass es einfach mit dem Heap.
Roland H. schrieb:> malloc/free auf einem µC ist eher ungewöhnlich.
Auf einem ARM keineswegs. Insbesondere übliche Implementierungen
von stdio brauchen es, dafür bekommt man halt eine gut erprobte
Implementierung.
> Lass es einfach mit dem Heap.
Meine Empfehlung: debugge es. Früher oder später musst du das sowieso
lernen, wie man das macht.
@ Roland H.
>if (!upnp_pcb) return 0;>ist ganz großer Murks. Denn dies verhindert die Freigabe mittels free()>am Ende
Hier hast du natürlich recht, upnp_pcb ist aber jedes Mal initialisiert
und tut nichts zur Sache, wenn alles top läuft, kann man aufräumen :)
Mit einem dem Char array habe ich es auch bereits probiert. Sogar die
strrpl Funktion anders gelöst, leider mit dem gleichen Resultat. Nach
12x Senden kommt ein Absturz. Ich bin ratlos :/
Guast schrieb:> Ich bin ratlos :/
Nimm doch endlich den Debugger und sieh' dir an, wo der Fault
auftaucht. Du hast anschließend Register, in denen du die fault
address lesen kannst, du hast den PC, was brauchst du noch?
Siehe Beitrag "Re: STM32 Grund für Hardfault herausfinden",
nicht vergessen, die memory protection faults freizuschalten.
Is zwar ne weile her aber vielleicht ist es ein Stackproblem. Stack zu
klein oder überlappt mit dem Heap. Stack wächst normalerweise runter und
Heap hoch. Wenn die zusammenwachsen weil der code zum beispiel leakt
könnte sowas passieren.
Gruss
Michael
Hi,
hab das gleiche Problem. Wenn meine Funktion nur kurz was berechnet, ist
es ok, wenn es aber dann mal länger was macht, gibts den Hardfault
(siehe Screenshot).
Kann es sein, das ich zuwenig RAM habe?
STM32F103RET7 ist mein µC
MfG
Ersan
Hallo ersan,
kannst du noch ein paar details geben?
Allokiert dein Code dynamisch Speicher? (benutzt also malloc und free)?
Sind deine Stacktiefen immer gleich oder hast du rekursive Funktionen?
Bist du dir sicher das im gut Fall alle funktionen bis in die tiefste
ebene aufgerufen wurden?
Manchmal ist es so das der Stack im gerade aus Pfad reicht, aber wenn
eine Fehlerbehandlung angesprungen wird nicht mehr weil hier mehr
variablen auf den Stack gelegt werden. Hier kann ich dir emfehlen alle
variablen gleich am Funktionsanfang zu definieren und nicht wie auf dem
PC üblich immer erst in dem Block wo sie gebraucht werden.
Auch ob der code in Debug oder Release gebaut wird spielt eine Rolle in
der benötigten Stacktiefe.
Benutzt du ein OS?
Gruss
Michael
Hallo Michael,
ich benutze kein OS. Könnte ich dir den Code mal zu per PN zuschicken
(gerne jeden, der interesse an der Lösung meines Problems hat)?
Im prinzip komme ich bis in die letzte tiefe der Funktion. Mir scheint
es halt Gefühlsmäßig bei einer Dauer von 4-5Sek. einen Überlauf zu
geben.
Leider hab ich nicht das Wissen um zu schauen ob ich irgendwo eine
Variable oder eine Datenstruktur habe, welche sich aufbläht. -> kann ich
das im Compiler/Debugger nachverfolgen?
Ich ging immer davon aus, das die Variablen und Konstanten im
Ram/Speicher vom Compiler auf die größtmögliche Speichernutzung
vor-reserviert werden.
MfG
Ersan
Um solche Hard-Faults zu lokalisieren habe ich mir ein Array mit 30
Positionen erstellt, bei jedem Aufruf einer Routine wird der PC in eine
neue Array-Position gespeichert.
Dazu kann ich noch andere Zahlen noch mit speichern.
Kommt jetzt ein HardFault so schaue ich mir die Zahlen in diesem Array
an. Die PC Adressen stimmen dann immer ungefähr mit der Adresse der
Routine überein und ich kann so sehen in welcher Routine das auftrat.
Bei zu viel Stack-Verbrauch hast Du vermutlich eine Routine, die sich
selbst rekursiv nonstop aufruft.
Ansonsten einzelne Programmteile deaktivieren bis es geht.
Ersan G. schrieb:> Hallo Michael,> Leider hab ich nicht das Wissen um zu schauen ob ich irgendwo eine> Variable oder eine Datenstruktur habe, welche sich aufbläht. -> kann ich> das im Compiler/Debugger nachverfolgen?>
Selbstverständlich. Schau' einfach, wo der/die Stackpointer (PSP
und/oder MSP) im Crashfall steht/stehen.
Die Fault-Adressregister sollten darüber Auskunft geben,
an welcher Codestelle der Crash passiert.
> Ich ging immer davon aus, das die Variablen und Konstanten im> Ram/Speicher vom Compiler auf die größtmögliche Speichernutzung> vor-reserviert werden.
Nicht bei Embedded-Systemen.
Woher sollten der Linker und Compiler auch wissen,
was zur Laufzeit passiert.
Die "größtmögliche Speichernutzung" kann auch unbegrenzt sein.
>> MfG> Ersan
Hallo Ersan,
schau mal noch in deine .lst Datei die der Linker anlegt. Da sind alle
Funktionen mit offset abgelegt.
Im LR steht die rücksprung Adresse, diese zeigt zumindest in die Nähe
des Fehlers. Je nach art des Fehlers genau dort hin oder ein bischen
vorher.
Der Inhalt der Datei sieht ungefähr so aus:
uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
80002cc: f04f 0000 mov.w r0, #0
80002d0: f002 fa02 bl 80026d8 <uxTaskGetStackHighWaterMark>
80002d4: 4603 mov r3, r0
80002d6: 60fb str r3, [r7, #12]
MSG1("Main Task tick...Stack HWM 0x%x",uxHighWaterMark);
80002d8: f003 fdbc bl 8003e54 <trace_reserve>
80002dc: f003 fdde bl 8003e9c <timestamp>
80002e0: f64a 607c movw r0, #44668 ; 0xae7c
80002e4: f6c0 0000 movt r0, #2048 ; 0x800
80002e8: 68f9 ldr r1, [r7, #12]
80002ea: f003 fac7 bl 800387c <termf>
80002ee: f003 fdc3 bl 8003e78 <trace_release>
remainingHeap=xPortGetFreeHeapSize();
80002f2: f002 fb3d bl 8002970 <xPortGetFreeHeapSize>
Der Teil der mit 8 anfängt ist die Flashadresse. Also einfach die
Adresse suchen die am nähesten an der LR adresse ist. Die Funktion nach
oben ist die Stelle in der aufrufenden Funktion die noch geklappt hat.
Gruss
Michael