Hallo,
ich hab hier ein Programm/Problem was mir zur Weißglut bringt!
OS: XP SP3
IDE: Code::Blocks 8.02
Compiler: MinGW, "gcc.exe -v" sagt "version 3.4.5 (mingw-vista
special)"
Debugger: GNU gdb 6.7.50.20071127
Ich versuch mal das Ganze möglichst kurz und komplett zu erklären: Ich
hab hier ein halbfertiges Programm welches Datensätze von einem Format
in ein anderes konvertieren soll. Ein-/Ausgabe soll über Textdateien
laufen, Eingabe funktioniert auch prima, der Lesepuffer ist mit 1500
Bytes etwas überdimensioniert, Ausgabe fehlt noch. Da die Datensätze
unterschiedliche Längen haben und es mal mehr mal weniger sind wird
massiv Gebrauch von malloc(), realloc() und memcpy() gemacht,
Datenmengen jeweils einige zehn bis hundert Bytes(!). Den Code darf ich
leider nicht veröffentlichen, außerdem ist er ziemlich lang und ein
"funktionierendes" (d.h. den selben Fehler produzierendes)
Minimalbeispiel krieg ich nicht hin. Das ganze compiliert mit "-Wall"
ohne eine einzige Warnung.
Problem: Das Programm konvertiert ein paar Datensätze, hängt sich dann
für ein paar Sekunden oder Minuten auf und beendet sich mit irgendeinem
Rückgabewert ungleich Null (welcher im Programm nirgendswo verwendet
wird). Das ganze ist halb reproduzierbar, d.h. es tritt immer an der
gleichen Stelle im Programmablauf, zu 99,9% ein malloc-Aufruf(!), und
mit dem gleichen Rückgabewert auf, bis das Programm leicht verändert
wird. Über Code::Blocks (Taste F9) gestartet konvertiert es aktuell 7
Datensätze und gibt dann augenblicklich -1073741819 (0xC0000005) zurück,
direkt im Explorer gestartet konvertiert es 126 Sätze und beendet sich
dann ohne jegliche Fehlermeldung. Gestern, bevor ich einen Fehler
entfernt und weitere Debugausgaben eingebaut hatte gab es jedesmal ~30
Sekunden Wartezeit bis zum Programmabsturz.
Ich habe ein paar Testvariablen eingebaut, malloc und memcpy werden fast
1000 mal aufgerufen, realloc ungefähr 150 mal. Die Rückgabewerte der
drei Funktionen werden geprüft und entsprechend reagiert. Der ganze Code
macht massiven Gebrauch von Strukturen und Pointern (und Pointern in
Strukturen).
Ich tippe auf irgendein Pointerproblem, finde die Stelle aber zum
verrecken nicht. Wenn irgendwo ein Pointer Amok läuft kommt meistens
eine Meldung das Programm hätte "ein Problem festgestellt" usw., hier
kommt keine solche Meldung. Außerdem würde sich das Programm dann wohl
eher bei memcpy erhängen, nicht beim Aufruf von malloc.
Wenn ich das Programm im Debugger laufen lasse gibt es nach aktuell 29
Datensätzen das da:
1
Program received signal SIGTRAP, Trace/breakpoint trap.
2
In ntdll!DbgUiConnectToDbg () (C:\WINDOWS\system32\ntdll.dll)
Laut Google ist also ein Ereignis eingetreten über welches GDB
informiert werden will. Schön, aber WELCHES Ereignis? Und in welcher
Zeile vom Programm? Breakpoints gibts keine, wenn ich Pointer und Memory
manuell beobachte kann ich keinen Fehler finden (bzw. habe einen
falschen Index gefunden und korrigiert, aber das Problem bleibt). Leider
kann man nur 256 Bytes Speicher auf einen Schlag anzeigen, das macht die
Sache nicht einfacher.
Ich hab einen bestimmten memcpy-Aufruf im Verdacht, wenn ich diesen
entferne funktionert alles (natürlich mit falschen Ergebnissen). Ich hab
den Aufruf jetzt zig mal geprüft und genaustens im Debugger observiert,
da passt alles! Ich vermute also das Problem ist woanders.
Den Präprozessor anzuweisen memcpy durch memmove zu ersetzen
(überlappende Speicherbereiche) hat auch nichts gebracht.
rhhhhaaaaa!!! Ich sitz jetzt 2 Tage an dem Mist und hab echt die Nase
voll so kurz vor Weihnachten.
Was ist da los? Ich weiss ohne Code ists schwer, aber vielleicht hat ja
jemand eine Idee. Gibt eine Möglichkeit dem Debugger zu entlocken was
genau sich hinter dem SIGTRAP versteckt? Was mir aufgefallen ist:
realloc weist meistens (immer?) einen neuen Speicherbereich zu, die neue
Adresse ist dabei stehts höher als die alte. Kann es sein dass dem
Programm schlicht der Speicher ausgeht? (Bei ein paar hundert
angeforderten Bytes???). Wo wird überhaupt die Info gespeichert wieviel
Bytes jetzt an Adresse 0xabc reserviert worden sind?
Weihnachtliche Grüße!
genervter Programmierer schrieb:> malloc(), realloc() und memcpy()
Wenn du niemals free() benutzt, dann wird dir wohl irgendwann der
Speicher ausgehen. Überprüfst du den Rückgabewert von malloc()? Wenn
kein Speicher mehr da ist, dann gibt malloc() 0 zurück. Wenn du das
nicht abfängst, dann kennst du jetzt dein Problem.
Außerdem könntest du einen statischen Buffer nutzen. Er sollte dann so
lang sein, wie dein längster Datensatz, der vorkommen kann.
Die wahrscheinlichste Variante ist es, dass irgendwo der allokierte
Speicher massiv überlaufen wird, also beispielsweise 100 Bytes allokiert
wurden und dann ab Beginn dieses Pointer 140 Bytes reingeschrieben
werden. Dadurch sind die Chancen recht groß, dass man die Steuerinfo,
die sich malloc zwischen die Datenblöcke legt, niederbügelt und dadurch
die ganze Speicherverwaltung zerschossen wird.
Alles was dann danach passiert ist nur noch Formsache.
Da
> Ausgabe fehlt noch. Da die Datensätze> unterschiedliche Längen haben und es mal mehr mal weniger sind wird> massiv Gebrauch von malloc(), realloc() und memcpy() gemacht,> Datenmengen jeweils einige zehn bis hundert Bytes(!).
hat sich wer massenhaft Arbeit für nichts gemacht.
100 Bytes sind doch auf einem PC kein Thema.
Einfach alle möglichen Datensätze beschreiben. Jeder mit seiner eigenen
Struktur, alle mittels einer Union überinanderlegen, noch ein Typflag
dazu und schon ist das alles kein Thema mehr.
Und schneller gehts auch
Und weniger Speicher wirds wahrscheinlich auch brauchen.
Schon mal Danke für die schnellen Reaktionen!
900ss D. schrieb:> genervter Programmierer schrieb:>> malloc(), realloc() und memcpy()>> Wenn du niemals free() benutzt, dann wird dir wohl irgendwann der> Speicher ausgehen.
Insgesamt dürften da wohl keine 2MB verwendet werden, würde mich
wundern...
> Überprüfst du den Rückgabewert von malloc()? Wenn> kein Speicher mehr da ist, dann gibt malloc() 0 zurück. Wenn du das> nicht abfängst, dann kennst du jetzt dein Problem.
Rückgabewerte von malloc, memcpy und realloc werden überprüft, bei einem
Fehler gibts eine Meldung und exit(EXIT_FAILURE). :-)
Karl heinz Buchegger schrieb:> Dadurch sind die Chancen recht groß, dass man die Steuerinfo,> die sich malloc zwischen die Datenblöcke legt, niederbügelt und dadurch> die ganze Speicherverwaltung zerschossen wird.
Das ist eine gute Info! Die Speicherverwaltung liegt zwischen den
Datenblöcken, das ist allerdings sehr fehleranfällig.
Gibt es nicht eine Methode den Debugger anzuweisen die Speicherbereiche
auf "Grenzüberschreitungen" zu überwachen oder einfach die ganzen
Speicheroperationen zu protokollieren und/oder irgendwie sinnvoll
(d.h. brauchbar) darzustellen? Mit max. 256 Bytes die ich mir anzeigen
lassen kann komme ich hier nicht weit!
R. Freitag schrieb:> Dein Problem scheint mir der Speicher zu sein. Wenn du keinen Code> posten kannst, poste doch mal <eine Speicherbelegung.
Was genau verstehst du unter "Speicherbelegung"? In welcher Form bzw.
mit welchem Tool/... erzeugt?
Ich werd in der Zwischenzeit mal die memcpy()-Aufrufe genau unter die
Lupe nehmen und testweise immer etwas mehr Speicher reservieren.
Karl heinz Buchegger schrieb:> Da>>> Ausgabe fehlt noch. Da die Datensätze>> unterschiedliche Längen haben und es mal mehr mal weniger sind wird>> massiv Gebrauch von malloc(), realloc() und memcpy() gemacht,>> Datenmengen jeweils einige zehn bis hundert Bytes(!).>> hat sich wer massenhaft Arbeit für nichts gemacht.
Das ist gut möglich... Die Daten sind aktuell in Textform und sollen in
ein "Binärformat" (nicht vernünftig im Editor darstellbar) konvertiert
werden. Strings die mehrfach vorkommen werden dabei über Indexes
angesprochen usw., sehr fehleranfällig. Ich werd mal gucken ob bzw. in
wie weit ich die Sache vereinfachen kann, union ist ein gutes Stichwort.
<Was genau verstehst du unter "Speicherbelegung"? In welcher Form bzw.
<mit welchem Tool/... erzeugt?
Unter Speicherbelegung verstehe ich die Belegung des Arbeitsspeichers.
:-)
( vortreffliches Amusement, hier...)
Wer per malloc Speicher alloziiiert, bekommt einen Zeiger zurück, zB so:
int *ptr = malloc(10 * sizeof (int));
Vom Zeiger ausgehend bis zum Ende von 10 * sizeof(int) ist der Speicher
belegt.
Was ich vermute, ist, dass sich das Malloc in Zusammenarbeit mit den OS
verheddert, und mit einer Speicherbelegung findest du heraus, wo.
Das bedeutet abewr nicht, dass du dann eine Lösung hast.
Gruss
Robert
R. Freitag schrieb:> <Was genau verstehst du unter "Speicherbelegung"? In welcher Form bzw.> <mit welchem Tool/... erzeugt?>> Unter Speicherbelegung verstehe ich die Belegung des Arbeitsspeichers.> :-)
Soooo doof bin ich auch wieder nicht. ;-)
Mal ernsthaft: Soll ich alle Pointer notieren oder was genau? Wenn man
dir die Aufgabe "Speicherbelegung erzeugen/zeigen" stellt, wie würdest
du das machen bzw was würdest du machen? Ich meine ich kann alle
Adressen (bzw. "Pointerwerte") notieren, aber das bringt mir ja nicht
wirklich viel (ist bei ~1000 malloc-Aufrufen aber eine Menge Arbeit).
Irgendwie bin ich wohl schwer von Begriff heute.
Wirklich interessant sind wohl die "Grenzüberschreitungen", aber die
muss man erstmal finden! Es muss doch eine Möglichkeit geben das den
Debugger oder irgendein anderes Tool machen zu lassen.
(Zitat von oben)
Gibt es nicht eine Methode den Debugger anzuweisen die Speicherbereiche
auf "Grenzüberschreitungen" zu überwachen oder einfach die ganzen
Speicheroperationen zu protokollieren und/oder irgendwie sinnvoll
(d.h. brauchbar) darzustellen? Mit max. 256 Bytes die ich mir anzeigen
lassen kann komme ich hier nicht weit!
genervter Programmierer schrieb:> Schon mal Danke für die schnellen Reaktionen!>> 900ss D. schrieb:>> genervter Programmierer schrieb:>>> malloc(), realloc() und memcpy()>>>> Wenn du niemals free() benutzt, dann wird dir wohl irgendwann der>> Speicher ausgehen.> Insgesamt dürften da wohl keine 2MB verwendet werden, würde mich> wundern...
Wird jetzt ge-freed() oder nicht?
Wenn nicht, dann such dir einen Fetzen (ein schweres Stück Tuch), mach
es nass und drisch es dem Original-Programmierer solange um die Ohren,
bis du nur noch gaaaanz kleine Stoffstückchen in der Hand hältst. Dazu
murmelst du die Worte: Du sollst allokierten Speicher auch wieder
freigeben, du sollst allokierten Speicher wieder freigeben.
Alternativ kannst du auch ein Badetuch nehmen.
Im Ernst: Wenn free() drinnen wären, hätte man eine kleine
Speicherüberwachung mit Guard-Bytes machen können. In vielen Fällen
kommt man so den Übeltätern schnell auf die Schliche.
Aber wer eben schlampig programmiert, muss mit den Konsequenzen leben
können. Man räumt Speicher hinter sich IMMER auf! Alles andere ist
Murks.
Gips!!
Electric Fence helps you detect two common programming bugs: software
that overruns the boundaries of a malloc() memory allocation, and
software that touches a memory allocation that has been released by
free(). Unlike other malloc() debuggers, Electric Fence will detect read
accesses as well as writes, and it will pinpoint the exact instruction
that causes an error. It has been in use at Pixar since 1987, and at
many other sites for years.
Electric Fence uses the virtual memory hardware of your computer to
place an inaccessible memory page immediately after (or before, at the
user's option) each memory allocation. When software reads or writes
this inaccessible page, the hardware issues a segmentation fault,
stopping the program at the offending instruction. It is then trivial to
find the erroneous statement using your favorite debugger. In a similar
manner, memory that has been released by free() is made inaccessible,
and any code that touches it will get a segmentation fault.
Simply linking your application with libefence.a will allow you to
detect most, but not all, malloc buffer overruns and accesses of free
memory. If you want to be reasonably sure that you've found all bugs of
this type, you'll have to read and understand the rest of this man page.
aus: http://linux.die.net/man/3/efence kopiert.
Karl heinz Buchegger schrieb:> genervter Programmierer schrieb:>> Schon mal Danke für die schnellen Reaktionen!>>>> 900ss D. schrieb:>>> genervter Programmierer schrieb:>>>> malloc(), realloc() und memcpy()>>>>>> Wenn du niemals free() benutzt, dann wird dir wohl irgendwann der>>> Speicher ausgehen.>> Insgesamt dürften da wohl keine 2MB verwendet werden, würde mich>> wundern...>>> Wird jetzt ge-freed() oder nicht?
Ich kann keinen free-Aufruf finden... Allerdings ist das Programm wie
gesagt halbfertig (eher "viertelfertig") und der bisher reservierte
Speicher wird auch bis zum (aktuellen) Programmende gebraucht. Wenn das
Programm beendet wird dürfte der Speicher doch automatisch freigegeben
werden oder?
(Falls nicht: Das Problem dürfte trotzdem woanders liegen, der Fehler
tritt auch beim ersten Aufrufen des Programmes nach dem Start des
Computers auf.)
Ich hasse es fremden Code debuggen zu müssen...
R. Freitag schrieb:> Gips!!
Wie bitte?
> Electric Fence helps you detect two common programming bugs: [...]
Das klingt prima, guck ich mir morgen an! Aber... ist das nicht
(ausschließlich) für Linux?
Würdest Du einen halbwegs aktuellen Microsoft-Compiler (wie z.b. das
kostenfreie Visual C++ Express) verwenden, könntest Du die erweiterten
C-Runtime-Checks der damit gelieferten Debugruntime-Library nutzen - und
den integrierten Debugger, der GDB hier wohl ein bisschen überlegen ist.
Mir ist klar, daß das kein wirklich hilfreicher Hinweis ist, aber
andererseits könntest Du mit noch vertretbarem Aufwand das einfach mal
ausprobieren.
Rufus Τ. Firefly schrieb:> Würdest Du einen halbwegs aktuellen Microsoft-Compiler (wie z.b. das> kostenfreie Visual C++ Express) verwenden, könntest Du die erweiterten> C-Runtime-Checks der damit gelieferten Debugruntime-Library nutzen - und> den integrierten Debugger, der GDB hier wohl ein bisschen überlegen ist.
Darf ich diesem Post entnehmen dass es in GDB keine Möglichkeit gibt die
Bereichsgrenzen der mit malloc() angeforderten Speicherblöcke zu
überwachen?
Ist es nicht zumindestens möglich größere Speicherblöcke auszulesen und
anzuzeigen? 256 Bytes sind etwas wenig, wenn ich ein paar kB auf einmal
betrachten könnte würde das schon helfen.
Ich meine mich zu erinnern dass dieses Visual-Gewusel sehr langwierig zu
installieren ist und viel Platz braucht, naja... Wenn es keine andere
Möglichkeit gibt werd ich es wohl probieren (müssen). Wobei man sich in
die Programme ja auch erstmal einarbeiten muss...
Nico S. schrieb:> Valgrind kann das auch.
Das läuft laut Wiki auch nicht unter Windows. :-(
Mal sehen ob ich morgen weitermache oder erst nach Weihnachten.
genervter Programmierer schrieb:> Ich werd in der Zwischenzeit mal die memcpy()-Aufrufe genau unter die> Lupe nehmen und testweise immer etwas mehr Speicher reservieren.
Der Präprozessor ist schon eine verdammt praktische Erfindung: Eine
Zeile an den Anfang
1
#define malloc(a) malloc(2*(a))
und das Programm läuft ohne Absturz durch. :-) Das bestätigt die
wahrscheinlichste Theorie (Bereichsüberschreitung), jetzt muss ich "nur"
noch den Fehler finden...
genervter Programmierer schrieb:> Darf ich diesem Post entnehmen dass es in GDB keine Möglichkeit gibt die> Bereichsgrenzen der mit malloc() angeforderten Speicherblöcke zu> überwachen?
Das weiß ich nicht -- ich nutze GDB nicht, und erst recht nicht für das
Debuggen von Windows-Anwendungen. Nur weiß ich, daß die Debug-CRT des VC
etliche aktivierbare "runtime checks" bietet, die auch einen
zerschriebenen Heap erkennen können.
Auch vermag der VC-Debugger von Haus aus sinnvoller mit so einer
Situation umzugehen:
> Program received signal SIGTRAP, Trace/breakpoint trap.> In ntdll!DbgUiConnectToDbg () (C:\WINDOWS\system32\ntdll.dll)
Ich will nicht ausschließen, daß man GDB auch beibringen kann, in so
einem Fall an die die Exception auslösende Codestelle zu springen, der
MS-Debugger macht das jedoch von vorn herein richtig. Übrigens auch,
wenn man den Debug-Build außerhalb des Debuggers startet, dann kann der
auch nachträglich bei Programmabsturz aktiviert werden.
Kurze Frage zum Visual Studio Express:
Bei MS steht für die Version 2010
1
we do require that you register your product within 30 days of
2
installation for continued use.
und für die Version 2008
1
Register your product within 30 days from installation.
Ich interpretiere dass als "2010 muss registriert werden, 2008 kann."
Ist das richtig? Gibt es eine Möglichkeit die Registrierung nicht
direkt per Internet durchzuführen (und dabei jede Menge Daten
preiszugeben)?
Rufus Τ. Firefly schrieb "halbwegs aktuell", trifft das auf die
2008-Version zu?
Ich lade momentan beide ISOs runter.
Nochmals Danke für die Hilfe!
Guard Bytes in der Debug Version macht der MS Compiler seit Anbeginn der
Windows Welt.
Allerdings weiß ich nicht, ob die dir hier was bringen werden, wenn
nichts gefreed wird. Denn beim Freigeben von Speicher, wird nachgesehen,
ob die Guard Bytes noch intakt sind. Wird nichts freigegeben gibts auch
keine Überprüfung.
Aber man kann den Memory Check irgendwie auch manuell anwerfen. Mal
danach googeln.
Edit:
Während du den Download machst, google mal ein bischen.
Mit "VC++ guard bytes"
findet sich vieles.
Das geht ja gut los! ISO geladen, DVD(-RW) gebrannt, Setup gestartet,
erste von acht Komponenten wird installiert, BUMM. Vielleicht sollte MS
mal seinen eigenen Installer debuggen...
Und jetzt?
Ich merk schon das wird wieder lustig. :-(
Luk4s K. schrieb:> genervter Programmierer schrieb:>> Und jetzt?>> Prüfsummen der ISOs überprüfen.
Die kann ich bei MS nicht finden... Ich werd die ISO nochmal laden,
leider liefert der MS-Server die Dateien zur Zeit nur häppchenweise.
Aktuell 80kB/s, meine Verbindung schafft locker das 8-fache. grrr
Peter schrieb:> kann es sein das du kein .net auf den PC hast? So in der Art sieht es> auch aus wenn man ein .NET programm ohne Runtime startet.
Ich habe .NET 2 SP2 , .NET 3 SP2 und .NET 3.5 SP1 installiert, dazu
"VC++ irgendwas Redistributables". Letzere hab ich entfernt, ging
problemlos. .NET 3.5 wollte ich versuchsweise auch mal deinstallieren
-->BUMM. Also von MS ein Tool gezogen um den Kram "manuell" zu
entfernen, geht auch nicht, MS Installer spinnt. Letzteren nach
Anleitung [1] "repariert", Version 4.5 installiert, .NET 3.5 mittels
MS-Tool erfolgreich entfernt, Installation vom Express Studio nochmal
gestartet, Punkt 1 von 9(!) = Installation irgendwelcher
Redistributables --> BUMM.
Sch***! Jetzt sitz ich schon wieder 1,5h und hab nicht mal Visual Studio
installiert. seufz
Hat jemand eine Ahnung was da los ist?
[1]
http://www.ehow.com/how_4842153_repair-windows-xp-installer-free.html
genervter Programmierer schrieb:> Hat jemand eine Ahnung wo genau der Unterschied zu der Datei von liegt?
nein, aber nicht nicht die Deutsche Version. Sie haben sie haben dort
auch die Compiler meldungen übersetzt.
Danach hast du es mit
schlechten Zeigern
und änlichen dinge zu tun. Wo man jedes mal erst übersetzen muss um mit
dem Fehler etwas anzufangen.
Ist ja alles sehr merkwürdig. Es gibt eine englische Version mit 749MB,
eine deutsche mit ~800MB und eine deutsche mit ~3GB. Aber es gibt keine
englische Version mit 3GB.
???
Ich bastel dann mal weiter. :-(
Mal zurück zum ursprünglichen Problem.
Es kracht bei Malloc. Die Ursache ist wahrscheinlich ein zu großes
Memcopy. Dein Problem ist, dass du viele Aufrufe von memcpy hast und
nicht nachverfolgen kannst, welcher der böse ist. Richtig?
Dabei ist die Aufgabe doch eigentlich einfach: Textdatei lesen, Daten
interpretieren und irgendwas damit anfangen. Wie kann da ein derart
kompliziertes und unwartbares Programm herauskommen?
Meine Meinung: Da ist irgendwo ein gewaltiger Wurm drin. Schmeiß den
Code weg und fang neu an, und strukturier es so, dass du den Überblick
behältst:
Datensatz einlesen
Erkennen, um welche Art Datensatz es sich handelt
Datensatz auswerten - hier wird unter Umständen gemalloct und gememcpyt.
Auswertung zur weiteren Verarbeitung irgendwo hinschieben (erst mal nur
printf'en)
Wichtig: Aufräumen, nicht mehr gebrauchten Speicher zurückgeben!
Von oben für den nächsten Datensatz.
genervter Programmierer schrieb:> Kurze Frage zum Visual Studio Express:>> (...)>> Ich interpretiere dass als "2010 muss registriert werden, 2008 kann."> Ist das richtig?
Vermag ich nicht zu beurteilen, ich nutze die mit meinem Firmen-MSDN-Abo
kommende nicht-Express-Version, da ich ein größeres Gemenge an
MFC-Anwendungen pflegen muss.
> Rufus Τ. Firefly schrieb "halbwegs aktuell", trifft das auf die> 2008-Version zu?
Ja. VC++ 6 war diesbezüglich noch etwas dürftig, alles neuere (am besten
ab 2005) reicht hierfür.
> Nochmals Danke für die Hilfe!
Naja, nach dem, was ich hier so von den Download- und
Installationsproblemen lesen, hätte ich Verständnis dafür, wenn der
etwas abgeklungen sein könnte ...
Ärgerlich ist, daß es diesen Compiler nicht ohne all das .Net-Geraffel
gibt, und vermutlich macht das auch die meisten Probleme. Der C- und
C++-Compiler für "nativen" Code (also nicht das .Net-Geraffel) ist
hingegen wie auch der Debugger vorzüglich.
Rufus Τ. Firefly schrieb:> Ärgerlich ist, daß es diesen Compiler nicht ohne all das .Net-Geraffel> gibt, und vermutlich macht das auch die meisten Probleme.
mann muss nur richtig suchen, das Platform SDK enthält den compiler der
sogar 64bit code erzeugen kann.
Aber dort ist das Studio nicht dabei, um das geht es ja hier.
Um das Studio selbst auch nicht, sondern primär um den integrierten
Debugger. Mit dem Windbeutel* will man aus gutem Grund nicht arbeiten,
der ist ... fast bäh.
*) Windbg
Jetzt bin ich definitiv reif fürs Irrenhaus.
Aber mal langsam.
besucher schrieb:> Es kracht bei Malloc. Die Ursache ist wahrscheinlich ein zu großes> Memcopy. Dein Problem ist, dass du viele Aufrufe von memcpy hast und> nicht nachverfolgen kannst, welcher der böse ist. Richtig?
Ja.
> Dabei ist die Aufgabe doch eigentlich einfach: Textdatei lesen, Daten> interpretieren und irgendwas damit anfangen. Wie kann da ein derart> kompliziertes und unwartbares Programm herauskommen?
42. (keine Ahnung)
> Meine Meinung: Da ist irgendwo ein gewaltiger Wurm drin. Schmeiß den> Code weg und fang neu an, und strukturier es so, dass du den Überblick> behältst:
Zeitlich gesehen natürlich das einzig Sinnvolle, aber irgendwann packt
es einen und mal will den Fehler unbedingt finden...
Weiter im Text:
Visual Studio Express Dingsda wollte nicht, also Wikipedia nach "Guard
Byte" [1] gefragt (wie von Karl heinz Buchegger am 22.12.2010 um 20:18
Uhr erwähnt), mittels Präprozessor die malloc-, realloc- und
memcpy-Aufrufe umgebogen und versucht ein paar "Wächterbytes"
einzubauen. Hat auch mehr oder weniger funktioniert, allerdings waren
die gemeldeten Fehler im Debugger nicht nachzuvollziehen bzw. vorhanden.
Also den nächsten Anlauf gestartet den MS-Krempel zu installieren.
Nachdem ich zig Einstellungen geändert habe (v.a. Dienste), ein paar mal
".NET Cleanup Tool" ausgeführt und bestimmt 3 mal den Windows Installer
neu installiert habe ist die Installation der englischen Version von
2008 ohne Probleme durchgelaufen, interessanterweise wurden nur 5 statt
9 Komponenten installiert. So weit so gut, ich darf nur nicht daran
denken was ich alles verändert habe ohne mir Notizen zu machen und wie
viele potentielle neue Probleme ich dabei erzeugt habe.
Nachdem ich stdint.h und inttypes.h nachträglich eingebaut habe (sind
nicht im Lieferumfang der 2008er-Version, s. engl. Wikipedia), die
Sprache auf "C" umgestellt und einige __attribute ((_packed_)) aus
einem Headerfile entfernt habe hat das ganze mit ein paar Warnungen
(geprüft, harmlos) tatsächlich kompiliert. Und ob ihr es glaubt oder
nicht, die mit V-Studio erzeugte Version läuft komplett ohne Fehler
durch.
Das hat mich etwas misstrauisch gemacht und ich habe mal das Headerfile
genau unter die Lupe genommen.
Aktueller Stand:
So
1
typedefstruct
2
{
3
uint8_txxx;
4
union
5
{
6
uint16_tyyy;
7
uint16_tzzz;
8
};
9
}xyz_t;
läuft das Programm (mit GCC kompiliert) komplett durch, so
1
typedefstruct__attribute__((__packed__))
2
{
3
uint8_txxx;
4
union
5
{
6
uint16_tyyy;
7
uint16_tzzz;
8
};
9
}xyz_t;
,so
1
typedefstruct
2
{
3
uint8_txxx;
4
union__attribute__((__packed__))
5
{
6
uint16_tyyy;
7
uint16_tzzz;
8
};
9
}xyz_t;
oder so
1
typedefstruct__attribute__((__packed__))
2
{
3
uint8_txxx;
4
union__attribute__((__packed__))
5
{
6
uint16_tyyy;
7
uint16_tzzz;
8
};
9
}xyz_t;
läuft es NICHT.
WHAAAAAAA!!! Kann mir mal jemand erklären was da los ist? Ich suche mir
3 Tage einen Wolf und dann ist so ein dämliches Compilerattribut schuld?
Das kann doch nur ein Zufall sein oder wie oder was?, das muss kann soll
darf geht doch gar nicht... **durchdreh**
[1] http://en.wikipedia.org/wiki/Guard_byte
Im alten Rom entstand ein Streit über den Umgang mit Karthago. Ein
Senator, Cato d.Ä, hat zur Zerstörung Karthagos aufgerufen, in dem er
jeder seiner Reden den Satz ' Ceterum Censeo Karthago esse delendam'
angefügt hat (Ü: Im Übrigem bin ich der Meinung, daß Karthago zwerstört
werden sollte.)
Nach einigen Jahren ist er dem Senat so sehr auf die Nerven gegangen,
dass die Römer Karthago tatsächlich zerstörten.
Redmondium ist deer latinierte Name für Redmond, HQ of µSoft.
Gruss
Robert
Du bist zweifellos erregt und erschöpft. Das ist verständlich.
So ist auch erklärlich, das Du das pragma packed für ein "dämliches"
hälst.
Das ist es aber nicht. Es hat, wie andere Spracheigenschaften auch
seinen Sinn. So hat sich (hoffentlich) der Autor auch etwas dabei
gedacht, wenn er es einsetzt.
Das es ohne packed läuft ist allein, keine hinreichende Erklärung. Das
pragma hat ja wiegesagt einen Sinn und es muss erstmal geklärt werden
auf welche Weise genau seine An- oder Abwesenheit die Funktion des
Programmes beeinflusst.
Ich würde Dir ernsthaft empfehlen eine längere Pause zu machen. Eine
wesentliche Information hast Du jetzt ermittelt. Jetzt mal ein bischen
Abstand. Die Verurteilung des bösen pragmas wird Dir nicht wirklich
weiterhelfen.
Viel Erfolg.
Huch schrieb:> So ist auch erklärlich, das Du das pragma packed für ein "dämliches"> hälst.
Naja, ich weiss schon was das bewirkt (verhindert dass der Compiler
Nullbytes zwischen die einzelnden Elemente "stopft") und dass das
durchaus nützlich sein kann.
> So hat sich (hoffentlich) der Autor auch etwas dabei> gedacht, wenn er es einsetzt.
Vermutlich um die genaue Anordnung der Bytes in der erzeugten Datei zu
kennen / zu beeinflussen.
> Das es ohne packed läuft ist allein, keine hinreichende Erklärung.
Dem stimme ich durchaus zu.
> Das> pragma hat ja wiegesagt einen Sinn und es muss erstmal geklärt werden> auf welche Weise genau seine An- oder Abwesenheit die Funktion des> Programmes beeinflusst.
Dürfte mit den erzeugten Dateien zu tun haben, s.o.
> Ich würde Dir ernsthaft empfehlen eine längere Pause zu machen.
Werd ich wohl machen, morgen ist Weihnachten...
> Die Verurteilung des bösen pragmas wird Dir nicht wirklich> weiterhelfen.
Ich verurteile nichts und niemanden, aber es ist wohl verständlich dass
man sich bei solchen Sachen irgendwann aufregt oder?
> Viel Erfolg.
Danke.
Peter schrieb:> setze mal das alignment auf 1byte, das sollte den gleichen Effeckt wie> das ((_packed_)) haben.
Da muss ich erstmal in die Doku gucken.
R. Freitag schrieb:> Im alten Rom entstand ein Streit über den Umgang mit Karthago.> ...> Redmondium ist deer latinierte Name für Redmond, HQ of µSoft.
Du hast Ideen... ;-)
Mit der IDE von MS komme ich überhaupt nicht klar, bevor man da das
Programm zum Compilieren gebracht hat hat man schon die Schnauze voll...
Der GDB hat auch nicht wirklich geholfen, über Code::Blocks ist das Ding
eine bessere printf-Funktion und über die Kommandozeile... die Doku ist
sehr sehr lang...
Schlussendlich hab ich den Ansatz von oben weiter verfolgt: Diverse
Funktionsaufrufe (malloc usw.) per Präprozessor auf eigene Funktionen
umgebogen welche den Aufruf zur eigentlichen Funktion weiterleiten,
dabei jeweils etwas mehr Speicher reservieren, Guardbytes schreiben,
Guardbytes prüfen, Debuginfo anlegen, ...
Nachdem das zwar einen Fehler bei einem memcpy() meldete aber ich im
Code an dieser Stelle kein Problem fand einfach alle paar Zeilen
memorycheck() (Eigenbau) aufgerufen und Bingo, eine Fehlermeldung mit
Zeilennummer, ein scharfer Blick, ein zweiter Blick und der Fehler war
gefunden.
Was für ein Aufwand für einen dämlichen Index!!!
genervter Programmierer schrieb:> Data[i].Felder[NbFelder].Index=j;
post fence error
im Übrigen, so eine Aufgabe schreit doch eher nach einer Skriptsprache
import random
random.choice(["Python","Ruby","Perl"])
Rufus Τ. Firefly schrieb:> Um das Studio selbst auch nicht, sondern primär um den integrierten> Debugger. Mit dem Windbeutel* will man aus gutem Grund nicht arbeiten,> der ist ... fast bäh.>> *) Windbg
Was hast du gegen Windbg?
Abgesehen davon, daß gelegentlich das alte sdb-Feeling aufkommt, ist
er doch gar nicht verkehrt.
Zumindest für Leute wie mich, die das VisualStudio sonst nur wegen
des Debuggers nehmen würden, ist es eine Alternative.
Klaus Wachtler schrieb:> Zumindest für Leute wie mich, die das VisualStudio sonst nur wegen> des Debuggers nehmen würden, ist es eine Alternative.
Äh, nein. Genau das ist er nicht, der VisualStudio-Debugger ist gefühlte
15 Jahre jünger.
Jünger ja, aber das Studio ist eine IDE mit allem Schnickschnack.
Um nur ein Programm zu debuggen, nervt es irgendwie, wenn man gar
kein Projekt in seinem Sinne hat.
Windbg kümmert sich darum nicht.
Nicht daß er besser oder moderner wäre, er ist einfach schlank
dagegen und funktioniert auch.
Wobei ich zugegebenermaßen zur Zeit recht selten debugge unter
Windows (mangels Fehlern natürlich :-)
Klaus Wachtler schrieb:> Wobei ich zugegebenermaßen zur Zeit recht selten debugge unter> Windows (mangels Fehlern natürlich :-)
Dann programmierst du nicht unter Windows :)
So, das Programm scheint zu funktionieren, weitere Fehler habe ich nicht
gefunden.
Danke für die Unterstützung, besonders an Karl heinz Buchegger für das
Stichwort "Guard-Byte" (simpel aber wirksam)!
Daniel schrieb:> genervter Programmierer schrieb:>> Data[i].Felder[NbFelder].Index=j;>> post fence error
schlichte Unaufmerksamkeit, wahrscheinlich hat genau in dieser Zeile das
Telefon geklingelt. ;-)
> im Übrigen, so eine Aufgabe schreit doch eher nach einer Skriptsprache>> import random> random.choice(["Python","Ruby","Perl"])
Mag sein, aber dazu muss man diese Sprachen auch erstmal beherrschen...