Forum: Mikrocontroller und Digitale Elektronik Compiler überschreibt Speicherbereich von Malloc


von Holger K. (holgerkraehe)


Lesenswert?

Hallo zusammen

Ich reserviere mit malloc einen kleinen Speicherbereich für einen Text.
malloc gibt mir eine Adresse zurück, und ich schreibe an diese meinen 
Text.

Dies funktioniert soweit so gut.

Nun wird etwas später im Code eine neue uint16_t Variable in einer 
Funktion gelöst.
Bevor diese Variable gelöst wird, sehe ich im Memory Browser meinen 
zuvor kopierten Text an der Adresse, welche mir malloc zurückgegeben 
hat.

Nach dem Initialisieren der Variable innerhalb meiner Funktion, steht 
jedoch an dieser Stelle der Inhalt meiner neuen Variable.
Mein Text ist nun verloren.

Hat jemand eine Idee, wie es zu solch einem Verhalten kommen kann?
Muss ich malloc eine art "Startadresse" übergeben, ab welcher Speicher 
reserviert werden kann?

Danke schonmal
Eure Krähe!

von Martin (Gast)


Lesenswert?

Es ist richtig, dass malloc die Adresse des allocierten Speichers 
zurückliefert.
Wie ist die Größe des Speicherbereichs, welcher malloc reservieren soll?
Der Quelltext (Ausschnitt) wäre hilfreich zur Beurteilung.

von Holger K. (holgerkraehe)


Lesenswert?

Hallo

An dieser Stelle im Code wird der Speicherplatz alloziert
1
class->object_text = malloc((( strlen(Text) + 1) * sizeof(char)));
2
3
if(class->object_text == 0)
4
{
5
    uGUI_releaseGlobalID(objectID);
6
    return 0;
7
}
8
9
strcpy(class->object_text, Text);

Mit dem Debugger sieht man im Memory Bereich, dass der richtige Text an 
der richtigen Speicheradresse steht.
1
uint16_t offset=(uint16_t)0x0000;
2
uint8_t cnt;
3
uint8_t height= (font_char_height(font_addr)-1)/8;
4
5
for (cnt= font_first_char(font_addr);cnt<chr;cnt++)
6
{
7
  offset+=font_char_width(font_addr,cnt) * (height+1);
8
}
9
10
offset+=font_number_of_chars(font_addr)+6;
11
12
return offset;

An der Stelle, wo die obigen Variabeln initialisiert werden, wird der 
von malloc allozierte Speicher überschrieben.

Verwendet wird btw. ein STM32F105, CooCox, und der ST-Link/V2 debugger

von Georg (Gast)


Lesenswert?

Holger Krähenbühl schrieb:
> Muss ich malloc eine art "Startadresse" übergeben, ab welcher Speicher
> reserviert werden kann?

Nein, wie denn auch. Aber was mir auffällt: malloc reserviert i.d.R. vom 
Heap, lokale Funktionsvariablen stehen oft auf dem Stack, ist aber 
kompilerabhängig - ich würde mal den Stackpointer prüfen.

Ist dein ganzer Text überschrieben oder bloss ein Teil?

Georg

von Steffen R. (steffen_rose)


Lesenswert?

Klingt etwas nach Stack Overflow. Heap und Stack werden wohl gleich 
hintereinander liegen.

von Holger K. (holgerkraehe)


Lesenswert?

Ihr seit ja super! Nun, wie kann ich das herausfinden ob es wirklich ein 
Stack Overflow ist?
Kann ich den Speicherbereich für den Stack vergrössern?
Müsste das nicht eine Warnung ausgeben?

Georg schrieb:
> Ist dein ganzer Text überschrieben oder bloss ein Teil?

Da mein Text sehr kurz ist, hat es den gesamten überschrieben

: Bearbeitet durch User
von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Steffen Rose schrieb:
> Klingt etwas nach Stack Overflow. Heap und Stack werden wohl gleich
> hintereinander liegen.

Vermute ich auch so. Liegt möglicherweise an zu wenig RAM. Oder daran, 
dass die betreffende Funktion über eine Endlosschleife rekursiv 
aufgerufen wird. Dann reicht natürlich kein RAM der Welt. ;-)

von Holger K. (holgerkraehe)


Lesenswert?

Markus Weber schrieb:
> Liegt möglicherweise an zu wenig RAM.

Der verwendete Controller hat 64kB Ram
Die .data Section sagt: 2516 Bytes nach dem Compilieren.

Markus Weber schrieb:
> Oder daran,
> dass die betreffende Funktion über eine Endlosschleife rekursiv
> aufgerufen wird.

Dies ist ebenfalls nicht der Fall.
Ich bin mommentan mit dem Debugger am durchsteppen.

Zudem liefert malloc ja weiterhin eine Adresse zurück und nicht '0'

Program Size:
      text     data      bss      dec      hex  filename
     28868     2516     2176    33560     8318  Calibration.elf

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Holger Krähenbühl schrieb:
> Der verwendete Controller hat 64kB Ram
> Die .data Section sagt: 2516 Bytes nach dem Compilieren.

Das enthält weder den Heap noch den Stack. Beide sind dynamisch und 
wachsen/schrumpfen während der Laufzeit.

Der Heap wächst mit jedem Alloc-Aufruf, der Stack mit jedem 
Funktionsaufruf und jeder automatischen Variablen (d.h. Variablen, die 
in Funktionen definiert werden).

von Martin (Gast)


Lesenswert?

Vielleicht führt die Beantwortung folgender Fragen weiter:
Wurde die Variable "chr" mit einem passendern Wert initialisiert?
Wie oft wird die for-Schleife  durchlaufen?

von Martin (Gast)


Lesenswert?

Meine Vermutung ist, dass in der for Schleife der Speicherbereich, des 
Textes überschrieben wird....

von Holger K. (holgerkraehe)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Das enthält weder den Heap noch den Stack. Beide sind dynamisch und
> wachsen/schrumpfen während der Laufzeit.
>
> Der Heap wächst mit jedem Alloc-Aufruf, der Stack mit jedem
> Funktionsaufruf und jeder automatischen Variablen (d.h. Variablen, die
> in Funktionen definiert werden).

Gibt es eine Möglichkeit, die grösse der beiden während der Laufzeit zu 
messen? Bzw auszulesen?

Martin schrieb:
> Vielleicht führt die Beantwortung folgender Fragen weiter:
> Wurde die Variable "chr" mit einem passendern Wert initialisiert?
> Wie oft wird die for-Schleife  durchlaufen?

Du hast recht, der Text wird während der for-Schleife überschrieben.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Holger Krähenbühl schrieb:
> Gibt es eine Möglichkeit, die grösse der beiden während der Laufzeit zu
> messen? Bzw auszulesen?

Für den Heap wirst Du Dir die Runtime-Library ansehen müssen, die sollte 
entsprechende Funktionen enthalten.

Eine recht gute Einschätzung des momentanen Wert des Stackpointers 
bekommst Du z.B. so:
1
... irgendwo in einer Funktion
2
3
unsigned int spwert;
4
5
{
6
  int i;
7
  
8
  spwert = (unsigned int) &i;
9
}
10
11
... hier kann spwert betrachtet werden

(setzt voraus, daß sizeof (unsigned int) == sizeof (pointer) ist, ist 
auf den meisten Architekturen der Fall)

von Holger K. (holgerkraehe)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Eine recht gute Einschätzung des momentanen Wert des Stackpointers
> bekommst Du z.B. so:.......

Vielen Dank!

Ich habe nun den Stack im Startupfile von 0x000100 auf 0x001000 
vergrössert und das Problem war behoben.

Der Stack wird ja während der Laufzeit nicht wieder kleiner oder?
Also kann man die Änderung als saubere Lösung des Problems betrachten?

Danke!

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

Der Stack wächst typischerweise nach unten. Und der Heap nach oben. Du 
hast dein Problem also vermutlich nur verschoben bis dein Heap wieder 
mit dem Stack kollidiert (dann bei Stack + Heap = 4kiB statt Stack + 
Heap = 256B).

Wie sieht denn dein Linkerscript aus?

Matthias

von Holger K. (holgerkraehe)


Angehängte Dateien:

Lesenswert?

Anbei das linker Script

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Also das Linkerscript sieht eigentlich gut aus. Es müßte noch irgendwo 
eine Funktion sbrk() geben. Wie sieht die denn aus.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Vlt wär der Startup-Code für deinen ARM auch interessant ... der müsste 
den Stackpointer richtig initialisieren und vlt läuft da was schief

von Holger K. (holgerkraehe)


Angehängte Dateien:

Lesenswert?

Anbei noch das Startup File

von Steffen R. (steffen_rose)


Lesenswert?

Es ist prinzipiell richtig, die Stackgröße dem realen Bedarf anzupassen 
und löst damit das Problem eines Stackoverflows.

Meine bisherigen Erfahrungen zu malloc() sind, dass dieser den Heap 
nicht verläßt. Ist der Heap zu klein angegeben, bekommt man einen 
NULL-Pointer.

von Holger K. (holgerkraehe)


Lesenswert?

Ok, vielen Dank für eure Hilfe!

von Micca (Gast)


Lesenswert?

Ich empfehle, möglichst einen Stack-Test in jedes embedded Programm 
einzubauen.

Während der Initialisierung setzt man am unteren/oberen Stack-Ende ein 
paar Bytes mit einer Magic Number. Dann kann man zyklisch im 
Hauptprogramm einfach prüfen, ob es einen Stack Overflow gab.

Erst vor kurzem hat ein Kollege tagelang einen Fehler gesucht, der 
mittels Stack-Test in kürzester Zeit erkannt worden wäre.

von Dr. Sommer (Gast)


Lesenswert?

Holger Krähenbühl schrieb:
> class->object_text = malloc((( strlen(Text) + 1) * sizeof(char)));
Kleiner Tip: sizeof(char) ist immer 1. Daher reicht hier malloc 
(strlen (Text) + 1).

Rufus Τ. Firefly schrieb:
> (setzt voraus, daß sizeof (unsigned int) == sizeof (pointer) ist, ist
> auf den meisten Architekturen der Fall)
Auf x86_64 zum Beispiel nicht... Dafür gibts uintptr_t in der <stdint.h> 
.

von Holger K. (holgerkraehe)


Lesenswert?

Das Problem hat sich nun, wie bereits prognostiziert, verschoben.

Nach dem vergrössern des Stack gings einige Zeit lang gut.
Nun wieder die Selben fehler.

Vermutlich ist es nun der Heap welcher zu klein ist.
Wie kann man denn den Heap vergrössern?


Danke!

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Holger Krähenbühl schrieb:
> Vermutlich ist es nun der Heap welcher zu klein ist.

Wäre der Heap zu klein, würden malloc-Aufrufe fehlschlagen und NULL 
zurückgeben. Da Du das abfangen wirst ... kann es das nicht sein.

von Peter D. (peda)


Lesenswert?

Holger Krähenbühl schrieb:
> Der verwendete Controller hat 64kB Ram

Dann sollte ja massig Platz sein.
Prüfst du auch immer brav, ob das Malloc nicht Null liefert?

Es gibt für manche Compiler Tools, die grasen den Calling-Tree ab und 
ermitteln so die maximal mögliche Stacklast. Oft können die sogar 
Funktionspointer aufdröseln.

von Holger K. (holgerkraehe)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Da Du das abfangen wirst ... kann es das nicht sein.

Ja das prüfe ich, da hast du recht.

Peter Dannegger schrieb:
> Dann sollte ja massig Platz sein.
> Prüfst du auch immer brav, ob das Malloc nicht Null liefert?

Ja das wird immer konsequent geprüft.

von Eric B. (beric)


Lesenswert?

Holger Krähenbühl schrieb:
> Das Problem hat sich nun, wie bereits prognostiziert, verschoben.
>
> Nach dem vergrössern des Stack gings einige Zeit lang gut.
> Nun wieder die Selben fehler.

Zeig mal dein Code -- 4k Stack soll bei 64k RAM eigentlich reichen. 
Entweder legst du "riesige" Datenstrukturen auf dem Stack, oder du hast 
zu viele verschachtelte Funktionsaufrufe, oder irgendwo ist eine 
rekursive Schleife.

von Holger K. (holgerkraehe)


Lesenswert?

Eric B. schrieb:
> Holger Krähenbühl schrieb:
>> Das Problem hat sich nun, wie bereits prognostiziert, verschoben.
>>
>> Nach dem vergrössern des Stack gings einige Zeit lang gut.
>> Nun wieder die Selben fehler.
>
> Zeig mal dein Code -- 4k Stack soll bei 64k RAM eigentlich reichen.
> Entweder legst du "riesige" Datenstrukturen auf dem Stack, oder du hast
> zu viele verschachtelte Funktionsaufrufe, oder irgendwo ist eine
> rekursive Schleife.

Hallo Eric

Ich zeige dir/euch gerne den Code.
Es sind jedoch an die 5000 Zeilen.

Ich kann schlecht nur eine "kritische" Stelle posten, da ich ja 
ebendiese nicht kenne.

von Steffen R. (steffen_rose)


Lesenswert?

Ist es denn noch immer das gleiche Problem - heißt: an der ursprünglich 
geposteten Stelle wird der Text überschrieben, der in einem 
Speicherbereich steht, der mit malloc() angefordert wurde.

Prüfe im Mapping File, ob dein Heap korrekt gesetzt ist. Prüfe auch mal 
die gemachten Aussagen, dass malloc() in deiner Umgebung NULL liefert, 
wenn im heap nichts mehr frei ist.

Beobachte deinen Stackpointer. Eine Rekursion sollte doch zu finden 
sein.

von Eric B. (beric)


Lesenswert?

Holger Krähenbühl schrieb:
> Ich kann schlecht nur eine "kritische" Stelle posten, da ich ja
> ebendiese nicht kenne

Dann nach und nach Teile auskommentieren bis der Fehler nicht mehr 
auftritt. Obwohl das bei einem Stacküberlauf nicht unbedingt zu der 
Fehlerquelle führen muss.
Am bequemsten wäre definitiv mit einem Debugger ein Write Access 
Breakpoint auf den "Stack Top" zu legen.

von Holger K. (holgerkraehe)


Lesenswert?

Steffen Rose schrieb:
> Ist es denn noch immer das gleiche Problem - heißt: an der ursprünglich
> geposteten Stelle wird der Text überschrieben, der in einem
> Speicherbereich steht, der mit malloc() angefordert wurde.

Nein, es sieht effektiv nach einer Rekursion oä. aus. Nach mehrmaligem 
Aufruf und Ablauf einer gewissen Funktion stürzt das Programm ab. Ein 
eindeutiges Muster konnte ich noch nicht erkennen, da das Programm 
manchmal nach dem ersten, manchmahl erst nach dem 10. Aufruf abstürzt. 
Wahrscheinlich abhängig davon was zuvor aufgerufen wurde.
In der Funktion und dazugehörenden Unterfunktionen konnte ich keinen 
Fehler entdecken. Ich hatte aber leider nicht viel Zeit es zu testen und 
kann euch nicht viel mehr dazu sagen.

Eric B. schrieb:
> Am bequemsten wäre definitiv mit einem Debugger ein Write Access
> Breakpoint auf den "Stack Top" zu legen.

Interessante Idee, ich werd mich mal schlau machen ob mein Debugger das 
kann.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Am 22. habe ich einen "Trick" gepostet, den "in etwa" aktuellen Stand 
des Stackpointers zu ermitteln - Du könntest das in Dein Programm an 
strategischen Stellen einbauen und den Wert irgendwohin ausgeben lassen.

Wenn er sich in der gleichen, auf die (vermeintlich) gleiche Art und 
Weise aufgerufenen Funktion ändert, hast Du eine Stelle gefunden, die Du 
Dir genauer ansehen solltest.

von Holger K. (holgerkraehe)


Lesenswert?

@rufus

Habs gesehen, werd ich ausprobieren. Danke für den Tipp!

von Rainer F. (ferdiflachmann)


Lesenswert?

Hi

Da heute ja schon für weiße Ware ein Selbsttest vorgeschrieben ist, gibt 
es soetwas schon von Atmel als Vorlagen.

Such mal bei Atmel nach IEC60730 Class B Test.

Dort findest du eine ganze Menge von Selbsttests der verschiedenen Atmel 
Controllern und deren Hardware im laufenden Programmen.

Ist heute ja schon fast überall vorgeschrieben, auch in Waschmaschienen 
und Backöfen.

Rainer

von Holger K. (holgerkraehe)


Lesenswert?

Ich habe nun folgendes getestet:

1
unsigned int spwert(void)
2
{
3
  int i;
4
  return (unsigned int) &i;
5
}
6
7
8
if (SysTickFlag)
9
{
10
  malloc(10);
11
  int i = 0;
12
  i = spwert();
13
  i = i - 0x20000000;
14
  SysTickFlag = 0;
15
  ItoA(i,pointerBuffer,"");
16
        WriteText(Handle,BLACK,WHITE,pointerBuffer);
17
}

Dies wird alle 100ms aufgerufen.
Doch der Ausgegebene Text ändert sich nie.
Auch mit dem Debugger ändert sich die Adresse von i nie

Nach einiger zeit stürtzt der Controller ab, da malloc keinen Speicher 
mehr alloziieren kann. Das prinzip funktioniert also.

Hat jemand eine idee, warum sich die adresse von i nicht ändert?

von Typ (Gast)


Lesenswert?

Naja wie groß ist den 'int' auf deinem Controller? Bei einigen ist 'int' 
nur 16 bit groß und damit zu klein für deine Rechnung.

von Eric B. (beric)


Lesenswert?

Holger Krähenbühl schrieb:

> Hat jemand eine idee, warum sich die adresse von i nicht ändert?

Wahrscheinlich weil du diese if-Abfrage in deiner Haupschleife machst. 
Da soll der Stackzustand eigentlich immer gleich sein. Bau dieser 
Konstrukt mal an ein paar mehr Stellen in deiner SW ein.

zB so:
1
char buffer[10];
2
3
void showSP()
4
{
5
  unsigned int i;
6
  char * buffer;
7
  i = (unsigned int) &i - 0x20000000;
8
  ItoA(i, buffer, "");
9
  WriteText(Handle, BLACK, WHITE, buffer);
10
}
11
12
13
void foo(void)
14
{
15
  WriteText(Handle, BLACK, WHITE, "foo:");
16
  showSP();
17
  
18
  // foo code
19
}
20
21
int bar(void)
22
{
23
  WriteText(Handle, BLACK, WHITE, "bar:");
24
  showSP();
25
}

EDIT: buffer statisch gemach - spart malloc(), free() und NULL-Abfrage 
in showSP().

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rufus Τ. Firefly schrieb:
> Am 22. habe ich einen "Trick" gepostet, den "in etwa" aktuellen Stand
> des Stackpointers zu ermitteln

Besser:
1
register char *stack_ptr asm ("sp");

von Steffen R. (steffen_rose)


Lesenswert?

Eric B. schrieb:
> Holger Krähenbühl schrieb:
>
>> Hat jemand eine idee, warum sich die adresse von i nicht ändert?
>
> Wahrscheinlich weil du diese if-Abfrage in deiner Haupschleife machst.

Wobei anzumerken ist, dass es im fehlerfreien Zustand korrekt ist, dass 
in der Hauptschleife der Stackpointer immer gleich ist.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Besser:register char *stack_ptr asm ("sp");

Sicher besser, aber abhängig vom verwendeten Prozessor und Compiler. Das 
wird nicht jeder C-Compiler für jeden µC so übersetzen.

von temp (Gast)


Lesenswert?

Hast du manchmal noch irgendein RTOS im Spiel? Das würde die ganze 
Diskussion um den Stack hier völlig verändern...

von temp (Gast)


Lesenswert?

Eventuell ist es auch hilfreich in deinem Stacktestschnipsel den 
minimalen Stack festzuhalten. Ungefähr so:
1
void *pSpMin=0;
2
3
unsigned int sptest(void)
4
{
5
  int i;
6
  if (!pSpMin || (&i<pSpMin))
7
    pSpMin=&i;
8
    
9
10
  return (unsigned int) &i;
11
}

damit kannst dann einfach im Debugger den Wert kontrollieren.

von Little B. (lil-b)


Lesenswert?

Ich würde den Stackverbrauch mit einem "High Water Mark" messen.

Fülle hierzu (vor beginn des Programms) den Stack komplett mit einem 
Byte-Pattern deiner Wahl (z.B. 0x55).
Während der Laufzeit des Programms brauchst du nur schaun (mit debugger 
und MemoryDump), bis wohin dieses Bytepattern überschrieben wurde.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rufus Τ. Firefly schrieb:
> aber abhängig vom verwendeten Prozessor und Compiler.

Hat er aber oben angegeben, letztendlich ARM-GCC (STM32 + CooCox).

von Steffen R. (steffen_rose)


Lesenswert?

Little Basdart schrieb:
> Ich würde den Stackverbrauch mit einem "High Water Mark" messen.

Wenn es um den Stackverbrauch geht, würde ich diese Methode auch 
bevorzugen.

Da der TO jedoch mittlerweile 4k Stack hat und keinen Grund für einen 
derart hohen Verbrauch angibt, gehe ich von einem Fehler im Programm 
(einige Ideen wurden schon genannt) aus.

Was würden dann die ganzen Stacktests liefern?

Höchsten die Bestätigung, dass es eine ungewollte Rekursion gibt.
Wäre ja nicht schlecht. Aber soviel näher am eigentlichen Problem ist 
man trotzdem nicht dran.

Der diskutierte Test des Stackpointers mittels Pointer müßte dann aber 
in einer Funktion innerhalb der Rekursion (die unbekannt und ungewollt 
ist) oder in einem Interrupt (ungenau) untergebracht werden.

von Little B. (lil-b)


Lesenswert?

Ich stimme zu, dass das messen der Stack-Größe an dieser Stelle keinen 
Sinn mehr macht. Man weiß ja bereits, dass der Stack überläuft.

Wichtig wäre zu wissen, wie der Stack aussieht, sobald das geschieht!
(Lass dir den Callstack vom Debugger anzeigen)

Um den Prozessor zu stoppen, wenn der Fehler auftritt ist eine memory 
protection unit hilfreich (aber die hat der STM32F1 nicht xD)

Oder du verwendest die vorgeschlagene Funktion, aber leicht abgewandelt:
1
void StackTest () {
2
   uint8_t i;
3
   extern uint8_t __StackLimit;   // symbol definiert im Linkerfile,
4
                                  // deshalb extern
5
6
   if (&i < &__StackLimit) {
7
      while(1);   // setze hier ein BreakPoint!
8
   }
9
}

von Holger K. (holgerkraehe)


Angehängte Dateien:

Lesenswert?

Wenn das Programm abstürzt endet es im Default Handler des STM
1
static void Default_Handler(void) 
2
{
3
  /* Go into an infinite loop. */
4
  while (1)
5
  {
6
  }
7
}

&__StackLimit = 0x200037fc <pulStack+11228>


@temp: Es ist kein RTOS im Spiel.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Sieh Dir mal den Wert des Stackpointers in Deinem Screenshot an.

Da sehe ich 0x200053e0, was von 0x200037fc doch etwas entfernt ist - 
dazwischen liegen gut 7 k.

von Holger K. (holgerkraehe)


Lesenswert?

Da bin ich ganz deiner Meinung. Jedoch ist der Wert des SP nach dem 
Initialisieren schon auf 0x20005408, Dh es müsste irgendwo eine riesige 
globale Variable erstellt werden..

von Steffen R. (steffen_rose)


Lesenswert?

Holger Krähenbühl schrieb:
> Jedoch ist der Wert des SP nach dem
> Initialisieren schon auf 0x20005408, Dh es müsste irgendwo eine riesige
> globale Variable erstellt werden..

Könntest Du näher darauf eingehen, an welchem Punkt Du bist?
Schaust Du in das richtige Mappingfile?
Welcher Wert steht auf 0x08000000?

Kurz nach der Initialisierung bist Du am Anfang von main(). Die 
Stack-Variablen von main() sind ja noch überschaubar und gut prüfbar.
Globale Variable liegen nicht auf dem Stack.

Anm:
Wenn ich es richtig in Erinnerung habe setzt CooCox den Stackpointer 
nicht explizit neu auf default. Er müßte entsprechend durch den CPU 
Reset auf dem ersten Wert in der Vektortabelle gesetzt worden sein.

Machst Du keinen Reset oder verwendest Du einen Bootloader, der den 
Stackpointer beim Einsprung nicht korrekt vorbelegt?

-------
Der Trap wird einige Zeit nach dem Problem auftreten. Wenn Du den Weg 
über die Trap's weitergehen willst, solltest Du getrennte Handler für 
die verschiedenen Traps machen.

Ansonsten füge die beschriebene Stackprüfung in sehr vielen bzw. 
problemrelevanten Funktionen ein.

Anm: Ich gehe mal davon aus, dass Du keine Routinen verwendest, welche 
den Stackpointer direkt verändern und dich so in die Irre führen.

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

laut dem Linkerscript was du oben mal gezeigt hast sollte dein SP in 
Main irgendwo bei (0x20010000 - (ein paar Byte)) liegen. Schau dir das 
gleich beim Systemstart im Debugger mal an. Wenn das nicht so ist stimmt 
irgendwas überhaupt nicht. Du kannst auch mal die ELF-Datei (oder besser 
noch MAP-Datei) hochladen.

Matthias

von Steffen R. (steffen_rose)


Lesenswert?

@Matthias
4k direkt nach dem Heap

von Holger K. (holgerkraehe)



Lesenswert?

Also, im Anhang ein Screenshot der Register bei Systemstart. Das Gerät 
wurde neu gestartet, der Flash überschrieben und der Debugger steht an 
erster Stelle im Code.
Zusätzlich noch die gewünschten Files.

Ich habe die den Fehler auf die Stelle gleich vor dem Absturz 
eingekreist.
1
struct uGUI_str_t_class *class;
2
class = (struct uGUI_str_t_class *)uGUI_ObjectID[objectID - 1].Addr;
3
.
4
.
5
//Falls eine Funktion definiert sein sollte, rufe diese auf!
6
if(class->onClick)
7
  class->onClick(objectID);

In obigem Coder wird eine Funktion aufgerufen, welche in folgender 
Struktur abgespeichert ist:
1
struct uGUI_str_t_class  // 20bytes
2
{
3
  uint16_t  object_x0;
4
  uint16_t  object_y0;
5
  uint16_t  object_x1;
6
  uint16_t  object_y1;
7
  char    *object_text;    //Pointer immer 4Byte!
8
  void    *object_Ptr;
9
  void    (*onClick)(uint8_t Sender);
10
};

Bei gesundem Ablauf stehen folgende Werte in der Struktur:

class = 0x20000f38

object_x0 = 230
object_y0 = 60
object_x1 = 300
object_y1 = 225
object_text = 0x20000f50
object_Ptr = 0xeec7a91
onClick = 0x08006edd

Gleich vor dem Absturz aber das Folgende:

class = 0x20000ec8

object_x0 = 240
object_y0 = 133
object_x1 = 293
object_y1 = 154
object_text = 0x20000ef0
object_Ptr = 0x20000ee0
onClick = 0xeea02cec

sp = 0x200053f0   lr = 0x08000b5b   pc = 0x0800080a

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Holger Krähenbühl schrieb:
1
> struct uGUI_str_t_class *class;
2
> class = (struct uGUI_str_t_class *)uGUI_ObjectID[objectID - 1].Addr;

Wenn ich so etwas sehe, schrillen bei mir direkt die Alarmglocken.
Hier wird auf uGUI_ObjectID[objectID - 1].Addr unbedingt zugegriffen.

Wie stellst Du sicher, dass objectID tatsächlich > 0 und nicht 
vielleicht == 0 ist?

: Bearbeitet durch Moderator
von Holger K. (holgerkraehe)


Lesenswert?

1
    uGUI_ObjectID[ID_Counter].Type = ObjectType;
2
    uGUI_ObjectID[ID_Counter].ID = ID_Counter+1;
3
    return ID_Counter + 1;

IDs werden hier und nur hier erstellt

von Holger K. (holgerkraehe)


Lesenswert?

Fehler Gefunden Inschallah
1
  if(function) 
2
                class->onClick = function;
3
  else
4
    class->onClick = 0;

Bei der Initialisierung fehlte das else, war also keine Funktion 
übergeben, stand irgendetwas zufälliges in onClick. Das erklärt zwar 
noch nicht warum sp so hoch ist, aber der Absturz scheint behoben.

@Frank Vor dem Zugriff wird geprüft ob objectID 0 ist
1
  if(objectID == 0)
2
    return 0;

: Bearbeitet durch User
von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

Auch wenn das jetzt erstmal ein Fehler war: Der Wert deines SP ist für 
mich jetzt auch nachvollziehbar. Du hast deine STACK_SIZE jetzt 
wahrscheinlich auf 0x1200 stehen. Damit hast du 18432 Bytes an Stack 
reserviert da STACK_SIZE in deinem Beispiel sich auf die Elemente von 
pulStack bezieht und das sind unsigned long. Du kannst das erste Element 
deiner Vektortabelle auch auf __stack setzen und pulStack rauswerfen. 
Dann steht dir der gesamte freie RAM als Stack zur Verfügung.

Außerdem scheint mir die Größe des RAM im Linkerscript falsch. Der 
STM32F105 hat doch 64k RAM oder?

Matthias

von Holger K. (holgerkraehe)


Lesenswert?

Μαtthias W. schrieb:
> wahrscheinlich auf 0x1200 stehen

stimmt.

Μαtthias W. schrieb:
> Außerdem scheint mir die Größe des RAM im Linkerscript falsch. Der
> STM32F105 hat doch 64k RAM oder?

Laut Datenblatt ja.

Ist mir nicht ganz wohl dabei ins Linkerscript zu schreiben. Ich kenn 
mich damit überhaupt nicht aus.

von Steffen R. (steffen_rose)


Lesenswert?

Holger Krähenbühl schrieb:
> Zusätzlich noch die gewünschten Files.

Der heap hat 0 Bytes. Der Heap ist relevant für malloc().

von Holger K. (holgerkraehe)


Lesenswert?

Wo seh ich das? Wie ändere ich das? Was passiert wenn ich es ändere?

von Steffen R. (steffen_rose)


Lesenswert?

Steffen Rose schrieb:
> Der heap hat 0 Bytes.

Holger Krähenbühl schrieb:
> Wo seh ich das? Wie ändere ich das? Was passiert wenn ich es ändere?

Gesehen habe ich es im Mappingfile:
1
.heap           0x20000c1c        0x0
2
                0x20000c1c                __end__ = .
3
                0x20000c1c                _end = __end__
4
                0x20000c1c                end = __end__
5
 *(.heap*)
6
                0x20000c1c                __HeapLimit = .
7
8
.co_stack       0x20000c1c     0x4804 load address 0x0800bb04

Warum es trotzdem soweit zu funktionieren scheint ist mir schleierhaft. 
Welche Adresse liefert das erste malloc()? Vergleiche diese Adressen mit 
dem jeweiligen Mapping File auf Stimmigkeit und auf Kollisionsfreiheit 
mit dem Stack.

Wie man es setzt, keine Ahnung. Nutze kein malloc().
Kommt auch auf deine malloc() Implementierung an (sprich, welche lib).
Hast Du eine sbrk() Funktion?

Lt. altem Forum von CooCox ist es recht complex. Vermutlich wird es aber 
nur für die abgespeckte lib (nano?) zutreffen. Da es bei Dir prinzipiell 
zu funktionieren scheint, sei an dieser Stelle vorsichtig beim 
übernehmen von den angesprochenen Änderungen:

[[http://www1.coocox.org/forum/topic.php?id=917]]

von Steffen R. (steffen_rose)


Lesenswert?

Erinnern möchte ich an obigen Beitrag:
Beitrag "Re: Compiler überschreibt Speicherbereich von Malloc"
1
caddr_t _sbrk ( int incr )
2
{
3
  static unsigned char *heap = NULL;
4
  unsigned char *prev_heap;
5
6
  if (heap == NULL) {
7
    heap = (unsigned char *)&_end;
8
  }
9
  prev_heap = heap;
10
11
  heap += incr;
12
13
  return (caddr_t) prev_heap;
14
}

Dies ist ein _sbrk() aus einem CooCox Beispiel mit newlib.

Diese Implementierung nutzt wie angesprochen den oberen Teil des Stacks 
als Heap. Dann nützen die ganzen Tipps wenig welche den Stackoverflow am 
oberen Ende überwachen. Hier müßtest Du das Zusammenwachsen von Heap und 
Stack überwachen. Daher hat das vergrößern des Stacks auch Luft für den 
Heap geschaffen, falls Du eine ähnliche Routine einsetzt.

von Samir Samsalmar (Gast)


Lesenswert?

Konnte das Problem nun gelöst werden?


Ich denke der TO muss noch mehr informationen liefern

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Samir Samsalmar schrieb:
> Konnte das Problem nun gelöst werden?

Laut

  Beitrag "Re: Compiler überschreibt Speicherbereich von Malloc"

konnte es gelöst werden. Es lag an einer nicht initialisierten 
Variablen.

von Samir Samsalmar (Gast)


Lesenswert?

Dies erklärte jedoch nicht warup sp so hoch war.

Und dies istetwas was mich auch beschäftigt

von Steffen R. (steffen_rose)


Lesenswert?

1
.co_stack       0x20000c1c     0x4804 load address 0x0800bb04

Stackende lt. den letzten Infos:
0x20000c1c + 0x4804 = 0x20005420

SP liegt bei 0x20005408.

Alles gut.

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.