Hi
ich habe ein kleines Problem mit malloc
und zwar geht es um einen IP stack auf einem cortex M3 mit coocox IDE +
GCC 4.8
Dieser legt für tcp und udp verbindungen in ein struct die werte ab(
port time usw ... )
nun soll das ganze dynamisch mit malloc erfolgen da ja nicht immer die
verbindungen offen sind.
vorher war es so aufgebaut:
1
udp_stuctudp_table[10];// max 10 udp verbindungen
2
3
voidfoo(void){
4
udp_table[i].port=...
5
udp_table[i].time=...
6
}
ich hatte mir gedacht das mal ein malloc auch auf arrayelemente machen
kann.
also so:
1
udp_stuct*udp_table[10];// max 10 udp verbindungen
gemacht
aber es scheint manchmal zu laufen ... und manchmal stürzt er genau beim
malloc ab
liegt es an der evtl falschen denkweise von mir ? oder sollte DAS
grundlegend erstmal laufen ?
kann es evtl auch daher kommen das ich verschachtelte malloc hab ?
es tritt oft auf wenn 2 bis 3 malloc hintereinander kommen.
zB
erst DHCP ( über udp es sind 2 pointer die hier genutzt werden )
die werden wieder freigegeben
danach folgt gleich ein NBNS register
erst payload allocieren ( 100byte )
dann udp öffnen ( 40byte ) <------ hier kracht es !!
er stoppt bei _malloc_r()
Hat jemand eine Idee?
Vielen Dank
Grüße
husten schrieb:> udp_table[i] = (udp_stuct*)malloc( sizeof(udp_stuct) );
Die Adresse, die du von malloc bekommst, NICHT casten!
DAs kann einen unangenehmen Fehler unterdrücken.
malloc liefert einen void* und der ist in C ohne weiteren Cast an jeden
anderen Pointer Type zusweisbar.
Wenn du casten musst, dann benutzt du keinen C COmpiler, sondern einen
C++ Compiler. Und dann solltest du nicht malloc benutzen, sondern new.
> liegt es an der evtl falschen denkweise von mir ? oder sollte DAS> grundlegend erstmal laufen ?
Das sollte erst mal grundlegend laufen, auch wenn es meistens recht
sinnfrei ist, ein statisch allokiertes Array von Strukturen durch ein
Array von Pointern zu ersetzen und dann durch die Allokierungen zu
laufen. Im Endeffekt braucht das Array von Pointern ja auch
Speicherplatz. D.h. hier greift die Abwägung: wie gross ist ein
derartiges udp_stuct, wie groß ist in Relation dazu ein Pointer und
wieviele udp_stuct sind im Schnitt erwartungsgemäss zu jedem Zeitpunkt
allokiert.
> kann es evtl auch daher kommen das ich verschachtelte malloc hab ?> es tritt oft auf wenn 2 bis 3 malloc hintereinander kommen.
Ich geh mal davon aus, dass du genug Speicher im System hast, dass die
Speicherfragmentierung keinen Sreich spielen wird.
Von daher kann man eigentlich nur sagen: Das Problem liegt nicht im
gezeigten Code.
hi
Karl Heinz schrieb:> Die Adresse, die du von malloc bekommst, NICHT casten!> DAs kann einen unangenehmen Fehler unterdrücken.> malloc liefert einen void* und der ist in C ohne weiteren Cast an jeden> anderen Pointer Type zusweisbar.> Wenn du casten musst, dann benutzt du keinen C COmpiler, sondern einen> C++ Compiler. Und dann solltest du nicht malloc benutzen, sondern new.
ok ich MUSS nicht casten ...
hatte das aber mal versucht um evtl den Fehler zu finden.
Karl Heinz schrieb:> Das sollte erst mal grundlegend laufen, auch wenn es recht sinnfrei ist,> ein statisch allokiertes Array von Strukturen durch ein Array von> Pointern zu ersetzen und dann durch die Allokierungen zu laufen. Im> Endeffekt braucht das Array von Pointern ja auch Speicherplatz.
Ja aber das ist 1 word .. eine struct hat 40bytes
bei tcp sind das 60 bytes insgesammt sind das 1k RAM die ich spare
Zeitlich ist das alles kein thema ...
das zieht sich nun noch durch andere quellen das ich insgesammt 4k
weniger RAM brauch
Karl Heinz schrieb:> Ich geh mal davon aus, dass du genug Speicher im System hast, dass die> Speicherfragmentierung keinen Sreich spielen wird.>> Von daher kann man eigentlich nur sagen: Das Problem liegt nicht im> gezeigten Code.
ich habe 32k Ram ... heap sagt nach einer weile( wnn es mal läuft.. )
22k free
habe dazu in der _sbrk funktion eine Variable eingefügt
nagut ... das war grundlegend erstmal die frage ob es so gehen kann ...
Ich kanne s bisher auch ganz gut reproduzieren ...
lasse ich die nbns funktion weg funktioniert alles inkl dem webserver
es scheint sich also dort der fehler zu verbergen bzw die reihenfolge
...
vielen Dank für die Antwort
Hi,
die Speicherverwaltung der C-Runtime merkt sich eine Liste freier
Speicherbereiche, möglicherweise über Pointer und Größenangabe am Anfang
eines freien Blocks.
Hast Du einen Bug in Deinem Code, der über den von malloc()
angeforderten Speicherbereich hinausschreibt, überschreibst Du
möglicherweise einen solchen Pointer und die Größenangabe. Der nächste
malloc()-Aufruf greift dann ins Klo, da er die freien Blöcke nach einer
geeigneten Größe durchsucht und dabei auf den Straypointer und die
Murksgröße stößt.
Grüße, Markus
Hi,
husten schrieb:> char* payload;> payload = malloc( xyz );
sicher, daß xyz gereicht hat? Oder hätte es eher xyz+1 heißen müssen?
Das wäre in solcher Bug. Die Umwandlung in einen statischen Array
verhindert das Hintenrausschreiben in einen freien Speicherbereich.
Grüße, Markus
Markus schrieb:> Die Umwandlung in einen statischen Array> verhindert das Hintenrausschreiben in einen freien Speicherbereich.
Nö, tut es nicht. Und der überschriebene Speicher ist auch nicht
notwendigerweise frei (bei malloc aber auch nicht).
husten schrieb:> nachtrag...>> wenn ich in der NBNS funktion nun statt>
1
>char*payload;
2
>payload=malloc(xyz);
> ein
1
>charpaylaod[xyz]
> nutze> funktioniert das ganze ohne probleme
Arrays sind keine Zeiger.
Wenn du also z.B. die Adresse von payload nimmst dann macht es einen
großen Unterschied, ob es sich um ein Array oder einen Zeiger handelt!
Hi,
fbi schrieb:> Nö, tut es nicht. Und der überschriebene Speicher ist auch nicht> notwendigerweise frei (bei malloc aber auch nicht).
völlig sinnfreier Kommentar.
Oben drüber steht "möglicherweise".
Gruß, Markus
husten schrieb:> aber es scheint manchmal zu laufen ... und manchmal stürzt er genau beim> malloc ab
Hast du eine Datei mit dem Start Up Code?
Ich hatte mal einen Fehler, wo das ganze beim Anlegen eines Arrays
abgeschmiert ist... hat ne weile gedauert bis ich rausgefunden habe,
dass der Stack/Heap in dem Start Up Code von Atmel für meinen Controller
standardmäßig auf 1k eingestellt ist.
husten schrieb:> ich habe 32k Ram
Und meiner hat 96k... ist aber egal wenn die Stack-/Heapgröße nicht zu
deinen Anforderungen passt.
husten schrieb:> und manchmal stürzt er genau beim> malloc ab
Was genau meinst du mit abstürzen? Und wie stellst du das fest?
Wenn der Controller deiner Meinung nach "nichts" mehr macht, kann es
sein das er im Dummy-Handler ( while(1); ) für nicht behandelte
Interrupts hängt. Das kann passieren (so wie bei mir z.B.) wenn du was
auf dem Stack/Heap anlegen willst, was da aber nicht mehr rauf passt.
Just my 2 cent...
Markus schrieb:> völlig sinnfreier Kommentar.
Ändert aber nichts an der Tatsache das Dein Kommentar,
Zitat:
"Die Umwandlung in einen statischen Array
verhindert das Hintenrausschreiben in einen freien Speicherbereich."
genauso schwachsinnig und dazu auch noch falsch ist.
husten schrieb:> Im Endeffekt braucht das Array von Pointern ja auch Speicherplatz.>> Ja aber das ist 1 word .. eine struct hat 40bytes> bei tcp sind das 60 bytes insgesammt sind das 1k RAM die ich spare> Zeitlich ist das alles kein thema ...
Dafür fibst du halt die Sicherheit über die Anzhal der Verbindungen auf.
Ein statisches Array mit 10 Einträgen kann garantiert immer 10
Verbindungen aufnehmen. Bei dynamischer Allokation machst du zwar
Speicher frei. Wenn du den aber tatsächlich dann für was anderes nutzt,
bedeutet das, daß die Anzahl möglicher Verbindungen sich dadurch
reduziert. Sie kann natürlich auch höher sein, wenn wo anders gerade der
Speicher nicht gebraucht wird, aber die Zahl hängt dann von der
aktuellen Situation ab.
Und es ergibt sich auch ein gewisses Risiko: Wenn du viele Verbindungen
offen hast und nun den Speicher für was anderes bräuchtest, ist dieser
nicht mehr frei.
Rolf Magnus schrieb:> Wenn du den aber tatsächlich dann für was anderes nutzt, bedeutet das,> daß die Anzahl möglicher Verbindungen sich dadurch reduziert.
Meistens erhöht sie sich aber (im statistischen Mittel), denn die
statische Allozierung musst du „sicherheitshalber“ so groß ansetzen
wie die maximal „unter normalen Umständen“ zu erwartende Anzahl.
Dass man, wenn man ein dynamisches Problem hat (Gesamtspeicherbedarf
ist nicht vorab exakt ermittelbar) mit der Situation umgehen können
muss, dass die Ressourcen irgendwann zu Ende sind, ist bei statischer
Allozierung genauso gesetzt wie bei dynamischer, in dieser Hinsicht
hilft das also auch nicht.
Jörg Wunsch schrieb:> Du hast den Fehler also erfolgreich kaschiert, statt ihn zu finden.> Glückwunsch!
das stimmt allerdings ...
grenzt für mich aber schonmal ein wo man weiter suchen kann ...
Markus schrieb:> Hast Du einen Bug in Deinem Code, der über den von malloc()> angeforderten Speicherbereich hinausschreibt, überschreibst Du> möglicherweise einen solchen Pointer und die Größenangabe. Der nächste> malloc()-Aufruf greift dann ins Klo, da er die freien Blöcke nach einer> geeigneten Größe durchsucht und dabei auf den Straypointer und die> Murksgröße stößt.
das KANN sein . ich werde das mal prüfen und ggf ein +1 hinzufügen
Markus schrieb:> sicher, daß xyz gereicht hat? Oder hätte es eher xyz+1 heißen müssen?> Das wäre in solcher Bug. Die Umwandlung in einen statischen Array> verhindert das Hintenrausschreiben in einen freien Speicherbereich.
siehe weiter oben ..
ich werde das mal nachsehen und jedes malloc in der länge prüfen
aber auch ein array[10] kann ich grundlegend erstmal mit 20 werten
beschreiben
spätestens nach dem pop krachts dann
Johann L. schrieb:> Arrays sind keine Zeiger.>> Wenn du also z.B. die Adresse von payload nimmst dann macht es einen> großen Unterschied, ob es sich um ein Array oder einen Zeiger handelt!
richtig ...
ich benötige jedoch für payload einen speicherbereich.
also entweder
1
chararray[10];
2
//oder
3
char*buf;
4
buf=malloc(10);
zB:
1
unsignedchar*payload;
2
payload=malloc(ARP_REQUESTLEN);
3
if(payload==NULL)
4
return;
5
memset(payload,0,ARP_REQUESTLEN);
6
make_arp_header(payload,0,0,ip,ARP_REQUEST);
7
EMAC_SendPacket(payload,ARP_REQUESTLEN);
8
memset(payload,0,ARP_REQUESTLEN);
9
free(payload);
10
payload=NULL;
}
Kaj schrieb:> Hast du eine Datei mit dem Start Up Code?> Ich hatte mal einen Fehler, wo das ganze beim Anlegen eines Arrays> abgeschmiert ist... hat ne weile gedauert bis ich rausgefunden habe,> dass der Stack/Heap in dem Start Up Code von Atmel für meinen Controller> standardmäßig auf 1k eingestellt ist.
habe den stack auf 2048byte gesetzt und den fix für den LPC1768 mit den
ersten 32byte die man nicht nutzen sollte
in der_sbrk funktion wird auch nochmal geprüft ob der heap nicht dem
stackend zu nahe kommt
Kaj schrieb:> Was genau meinst du mit abstürzen? Und wie stellst du das fest?> Wenn der Controller deiner Meinung nach "nichts" mehr macht, kann es> sein das er im Dummy-Handler ( while(1); ) für nicht behandelte> Interrupts hängt. Das kann passieren (so wie bei mir z.B.) wenn du was> auf dem Stack/Heap anlegen willst, was da aber nicht mehr rauf passt.
er hängt sich dann auf im
1
staticvoidDefault_Handler(void)
2
{
3
/* Go into an infinite loop. */
4
while(1)
5
{
6
_NOP;
7
}
8
}
Rolf Magnus schrieb:> Dafür fibst du halt die Sicherheit über die Anzhal der Verbindungen auf.> Ein statisches Array mit 10 Einträgen kann garantiert immer 10> Verbindungen aufnehmen. Bei dynamischer Allokation machst du zwar> Speicher frei. Wenn du den aber tatsächlich dann für was anderes nutzt,> bedeutet das, daß die Anzahl möglicher Verbindungen sich dadurch> reduziert.
ich weiß .. aber der webserver wird nur bei konfiguration benötigt ...
danach nicht mehr.
in normalen betrieb wird zyklisch man diese und jene funktion aufgerufen
die mal speicher braucht
sicher geht das auch mit fixen arrays...
nur dachte ich ist es so etwas flexibler und brauch nicht array doppelt
und dreifach nutzen
die funktionen werden eh nacheinander ausgeführt
somit stünde immer genug speicher bereit
das ganze läuft in einem RTOS wo später auch mal funktionen hinzukommen
ich danke nochmal für die hilfe
werde mal schauen ob ich nicht doch irgendwo "pber das ziel hinnaus
schieße"
bzw die allocierte größe überschreibe
das ist zumindest ein guter hinweiß .. danke nochmal dafür
husten schrieb:> er hängt sich dann auf im> static void Default_Handler(void)> {> /* Go into an infinite loop. */> while (1)> {> _NOP;> }> }
Mach den Stack doch einfach mal aus spass 4k oder 8k gross und schau ob
er sich dann immer noch aufhaengt, du hast doch 32k. Wenn's dann immer
noch kracht, kannst du immerhin (nahezu) sicher sein, das es nicht daran
liegt.
Es gibt mit sicherheit ca. 1 Million Gruende warum der Controller in den
Default_Handler springt. Ich habe aber erstmal weiter hin die
Stack-/Heapgrenze im verdacht, einfach weil's mir auch passiert ist.
Kaj schrieb:> Mach den Stack doch einfach mal aus spass 4k oder 8k gross
Ein typisches Setup beim GCC benutzt keinen festen Stack, sondern
gibt dem Stack das Maximum an RAM, das er bekommen kann.
Ich danke erstmal allen für die Kommentare :-)
der Fehler lag wie immer am Programmierer :-P
ich hatte an vielen stellen schon die Größe angepasst
1
ptr=malloc(sizeof(struct));
außer an 3 stellen ... dort hatte ich die #defines genutzt
problem lag daran das
1
#define XYZ 50
nicht mit dem struct übereinstimmte ...
ein
1
malloc(sizeof(struct));
hilft hier ungemein
#defines sind gut .. aber gerade hierbei nicht hilfreich ...
ergebniss ist :
das #define sagte 50 bytes
sizeof sagt 68 bytes
damit zerschießt er den folgenden malloc aufruf qweil der ptr schon
gestorben ist
Markus schrieb:> Hast Du einen Bug in Deinem Code, der über den von malloc()> angeforderten Speicherbereich hinausschreibt, überschreibst Du> möglicherweise einen solchen Pointer und die Größenangabe. Der nächste> malloc()-Aufruf greift dann ins Klo, da er die freien Blöcke nach einer> geeigneten Größe durchsucht und dabei auf den Straypointer und die> Murksgröße stößt.
ist des rätsels lösung
Vielen Dank für den hinweiß
grüße
Jörg Wunsch schrieb:> Kaj schrieb:>> Mach den Stack doch einfach mal aus spass 4k oder 8k gross>> Ein typisches Setup beim GCC benutzt keinen festen Stack, sondern> gibt dem Stack das Maximum an RAM, das er bekommen kann.
Mag sein, aber nicht beim verwenden von Atmel Studio.
Auszug aus den Dateien sam3x8e_flash.ld/sam3x8e_sram:.ld
1
/* The stack size used by the application. NOTE: you need to adjust according to your application. */
Bei AVRs wird das nicht gemacht, aber bei den Cortex-Controllern.
Ich weiß halt nicht wie andere IDEs/Controller-Hersteller das so
handhaben und vorgefertigte LinkerScripte nutzen oder nicht, deswegen
hab ich einfach darauf hingewiesen, da ich selbst vor ca. 3 Wochen
darüber gestolpert bin.
Wenn man nicht weiß das sowas gemacht wird, kann einem das schon mal den
ein oder anderen Tag fehlersuche bescheren :)
Was auch immer sie da verbockt haben. Keine Ahnung, warum man eine
Stackgröße im Linkerscript festzurren will. Es genügt doch vollauf,
die Variablen vom Anfang des RAMs nach oben zählen zu lassen und den
Stack vom Ende nach unten.
Ist ja am Ende aber die Frage, wofür dieses STACK_SIZE benutzt wird.
Jörg Wunsch schrieb:> Ist ja am Ende aber die Frage, wofür dieses STACK_SIZE benutzt wird.
das kann man in der SW nutzen
so habe ich die _sbrk funktion modufiziert das ein reinwachsen von heap
in stack normalerweise geblockt wird.
das linkerscript bietet es zumindest an die stackgröße zu überwachen ...
aber innerhalb der SW wird das nirgends getan ( außer man baut dies ein
)
man kann nun den STACK eine fixe größe geben ..
und warten bis heap irgendwann reinwächst
-> einfach weil man nur 2 variablen abfragen muss
oder man holt sich immer den aktuellen stackpointer und schaut dann nach
-> die schönere Lösung
damit stellt man auch sicher fals der erdachte STACK zu klein ist es
trotzdem nicht kracht
husten schrieb:> damit stellt man auch sicher fals der erdachte STACK zu klein ist es> trotzdem nicht kracht
Die Frage ist: was machst du dann?
Auf einem Desktoprechner mit Betriebssystem ist das leicht. Das laufende
Programm wird abgewürgt, mit "letzter Kraft" wird noch eine
Fehlermeldung ausgegeben und das Betriebssystem kriegt die Kontrolle
zurück, die dann das Programm entsorgt.
Aber was soll auf einem kleinen µC sinnvolles geschehen?
Ich hab da nicht wirklich Freude daran, wenn die Waschmaschine mitten im
Schleudern abschmiert, nur weil der Stack in den Heap gewachsen ist. Da
hilft es mir dann auch nichts, wenn irgendwo verschämt eine LED auf
diesen Fehler hinweist.
husten schrieb:> das kann man in der SW nutzen so habe ich die _sbrk funktion modufiziert> das ein reinwachsen von heap in stack normalerweise geblockt wird.
Ah OK. In der avr-libc erfolgt der entsprechende Test gegen den
aktuellen Stackpointer plus einer konfigurierbaren Sicherheitsreserve.
Karl Heinz schrieb:> Ich hab da nicht wirklich Freude daran, wenn die Waschmaschine mitten im> Schleudern abschmiert, nur weil der Stack in den Heap gewachsen ist.
Allerdings ist die Waschmaschine ja nun auch nicht gerade das
Musterbeispiel für eine Applikation mit stark dynamischem Datenanfall.
Bei einer solchen Applikation wiederum brauchst du immer eine
„Exit-Strategie“, wie du verfährst, wenn der Datenanfall die Kapazität
übersteigt. Dabei ist es völlig egal, ob die statisch vorkonfigurierte
Kapazität überschritten wird oder ob malloc() keinen Speicher mehr hat.
nunja
frage ist was der rogrammierer draus macht wenn ein
malloc( ... );
ein NULL zurück gibt!!
wenn _sbrk alarm gibt kommt aus dem malloc ein NULL ..
so ist das zumindest auf dem Cortex M
Wenn man diese sicherheit nicht abfängt schepperts eben
im Falle des IP Stacks ... er überspringt das Protokoll oder sendet mal
nicht
fängt er sich nicht wieder .. sollte man eine sicherheit einbauen
Jörg Wunsch schrieb:> Kaj schrieb:>> Mach den Stack doch einfach mal aus spass 4k oder 8k gross>> Ein typisches Setup beim GCC benutzt keinen festen Stack, sondern> gibt dem Stack das Maximum an RAM, das er bekommen kann.
Ausserdem alloziert malloc() nicht auf dem stack sondern im Heap.
Stack vergrößern bei einem malloc()-problem wird also wenig bringen...
Karl Heinz schrieb:> husten schrieb:>>> damit stellt man auch sicher fals der erdachte STACK zu klein ist es>> trotzdem nicht kracht>> Die Frage ist: was machst du dann?>> ... was soll auf einem kleinen µC sinnvolles geschehen?
Eintrag im Fehlerspeicher schreiben, was dann später über eine On-Board
Diagnose (OBD) ausgelesen werden kann, und dann ein reset und hoffen
dass alles dann gut geht.
Noch später darf dann ein armer Entwickler auf Fehlersuche, ohne dass er
ausreichende Logs/Traces oder sonstige Infos hat. Das alles unter
Riesendruck und direktes Management-beobachten , weil der Fehler vom
Kunden und nicht in der hauseigenen Testabteilung gefunden wurde.
Die letztendliche Ursache liegt dann aber natürlich doch wieder beim
Management, weil die ja einen zu kleinen uC für das Projekt ausgewählt
hatte.
Aber darüber darf man nicht sprechen...