SOLVED: Brauche einen Rat beim Debuggen...



  • Gast3 schrieb:

    dass der Wert an diesem Knoten im statischen Speicher an dieser Stelle verändert wird.

    an welcher Stelle - bei den printfs? da wird doch gar nichts veraendert?
    ausser F_Thread durch das realloc

    Das ist es ja. Der Knotenwert wird nicht mal an die Funktion übergeben. Ich mache das hier nur, um den Wert überwachen zu können.

    Gast3 schrieb:

    Fragen/Tips:
    1. könnte es ein Threading-Problem sein - also konkurrierende Zugriffe oder sowas?

    Nein. Ich Nutze zwar Threading, hab das dann aber zu Testzwecken deaktiviert und führe die Funktion direkt im Code aus.

    Gast3 schrieb:

    2. auf welchem Kompiler/OS läuft dein C/C++ Backend? falls Linux(nur x64) mit gcc/clang geht könntest du mal den Address- und Thread-Sanitizer drauf los lassen - und damit schnell eine riesen Horde Fehler ausschliessen (die beiden Tools sind absolut Gold wert, Danke google)

    Beides Visual Studio 2015 - Windows 7 64 Bit. Hab als platform x64 gewählt.

    Gast3 schrieb:

    3. du solltest zur besseren Fehlereingrenzung von deinem C#-GUI wegkommen und direkt den C/C++ Code Debuggen - also einfach die DllMain durch eine echte/hartkodierte main mit deinem Test ersetzen- und die Dll als Executable kompilieren - dann hast du garantiert keine Debugging-Probleme mehr - ausserdem ist C# für die Fehlereingrenzung nicht relevant und stört nur - oder ist der Auslöser (aber das merkst du dann sehr schnell)

    Langfristig, gerne. Aber ich habe mich mit QT noch nicht auseinandergesetzt und das Programm ist schon sehr weit fortgeschritten:
    https://www.youtube.com/watch?v=iCjezalOBP4

    Muss das jetzt so erstmal fertig bringen...
    Außerdem wurde mir hier im Forum gesagt: "Nutze nie C/C++ um GUIs zu
    programmieren!!" 😋

    Gast3 schrieb:

    4. den Test in Release wie auch in Debug laufen lassen - gibts Unterschiede?

    Kein Unterschied...

    Gast3 schrieb:

    5. Aufräumen und solche ausgeschriebenen Vorkommen von "FB->FBox[i]..." durch lokale Referenz/Pointer ersetzen - schon zu oft ein falsches Einstechen bei so [x][y][z] Einstech-Orgien gesehen

    for (i = 0; i < 8/*Magic Value*/; i++)
    { 
      /*auto&*/ curr_fbox = FB->FBox[i];
      /*auto&*/ n_359_gamma3 = N[359].Gamma[3]; // falls wirklich wie eine Art Konstante genutzt
    
      printf("n_359_gamma3 = %2.4e\n", n_359_gamma3); /*Liefert 0.2500e000*/ 
      curr_fbox.F_Thread = (TFace**)realloc(curr_fbox.F_Thread, curr_fbox.npFace * sizeof(TFace*)); /*Hier wird der Wert überschrieben*/ 
      printf("n_359_gamma3 = %2.4e\n", n_359_gamma3); /*Liefert 9.12e-008*/ 
      if (curr_fbox.F_Thread == NULL){ printf("ERROR - Unable to allocate memory!\n"); getchar(); return 1; } 
      curr_fbox.npFace = 0;
      ...
    }
    

    Schwierig, denn genau darin liegt die Systematik, wenn ich eine Menge in genau acht Untermengen räumlich unterteilen möchte. Außerdem funktioniert die Routine so. Ich habe sie häufig eingesetzt und sie hat stets das richtige geliefert.



  • Gast3 schrieb:

    ist es gewollt das in case 0: das break fehlt?

    case 0: /*Box 1*/ 
                    fbox.XMin = FB->XAve; 
                    fbox.XMax = FB->XMax; 
                    fbox.XAve = .5 * (fbox.XMax + fbox.XMin); 
      
                    fbox.YMin = FB->YAve; 
                    fbox.YMax = FB->YMax; 
                    fbox.YAve = .5 * (fbox.YMax + fbox.YMin); 
      
                    fbox.ZMin = FB->ZAve; 
                    fbox.ZMax = FB->ZMax; 
                    fbox.ZAve = .5 * (fbox.ZMax + fbox.ZMin); 
                case 1: /*Box 2*/ 
                    fbox.XMin = FB->XAve; 
                    fbox.XMax = FB->XMax; 
                    fbox.XAve = .5 * (fbox.XMax + fbox.XMin); 
      
                    fbox.YMin = FB->YAve; 
                    fbox.YMax = FB->YMax; 
                    fbox.YAve = .5 * (fbox.YMax + fbox.YMin); 
      
                    fbox.ZMin = FB->ZMin; 
                    fbox.ZMax = FB->ZAve; 
                    fbox.ZAve = .5 * (fbox.ZMax + fbox.ZMin); 
                    break;
    

    Danke für den Hinweis. Wieso hat das nichts ausgelöst? Hab es korrigiert, der Fehler besteht aber weiterhin.



  • Lass dir nicht alles einzeln aus der Nase ziehen,
    gib die Definition von N und aller beteiligten Typen konkret an (ohne Abschreib-Fehler).



  • Wutz schrieb:

    Lass dir nicht alles einzeln aus der Nase ziehen,
    gib die Definition von N und aller beteiligten Typen konkret an (ohne Abschreib-Fehler).

    Hab den Code ergänzt.



  • Hast du bei malloc/realloc auch immer das richtige sizeof benutzt?

    Nutze den dereferenzierten Zeiger für sizeof

    int *p;
    
    p = malloc(1000*sizeof(int))   // schlecht, da du wissen muss, was p ist.
    p = malloc(1000*sizeof(*p))    // besser 
    p = malloc(1000*sizeof(p[0]))  // geht auch
    

    Gerade bei deinen vielen structs besteht leicht die Möglichkeit, dass du das bei copy&paste mal vergessen hast.

    Dein N oder M kann ja schon von der Größe falsch sein.
    Hat sich evtl. schon M oder pNode oder Gamma verändert (irgendein Zeger auf dem Weg zu Gamma[3]?
    Hat Gamma überhaupt min. 4 Elemente?

    Benutzt du VLA oder Rekursion (reicht dein Stack)?



  • int SubdivideOneFBox(FBBox* FB, TMesh* M){
    

    - Definition von TMesh fehlt

    M zeigt ja wohl irgendwie auf FB, wenn du also durch realloc den FB-Speicherbereich verschiebst (und die Größe änderst), wie stellst du dann sicher, dass M davon was mitbekommt?
    Ich sehe auch kein free zu deinem realloc.



  • Gast3 schrieb:

    3. du solltest zur besseren Fehlereingrenzung von deinem C#-GUI wegkommen und direkt den C/C++ Code Debuggen - also einfach die DllMain durch eine echte/hartkodierte main mit deinem Test ersetzen- und die Dll als Executable kompilieren - dann hast du garantiert keine Debugging-Probleme mehr - ausserdem ist C# für die Fehlereingrenzung nicht relevant und stört nur - oder ist der Auslöser (aber das merkst du dann sehr schnell)

    Langfristig, gerne. Aber ich habe mich mit QT noch nicht auseinandergesetzt und das Programm ist schon sehr weit fortgeschritten:
    https://www.youtube.com/watch?v=iCjezalOBP4

    Muss das jetzt so erstmal fertig bringen...
    Außerdem wurde mir hier im Forum gesagt: "Nutze nie C/C++ um GUIs zu
    programmieren!!" 😋

    das meinte ich nicht - du sollst nur für die Fehlereingrenzung das GUI Verlassen und die Dll (kurz mal) in eine Applikation umwandeln und dort deinen Test machen - dann wäre klar ob es an C# oder C/C++ liegt (es ist für niemanden hier klar wie C# die Schnittstelle nutzt), und dein Debugger funktioniert anständig



  • Gast3 schrieb:

    5. Aufräumen und solche ausgeschriebenen Vorkommen von "FB->FBox[i]..." durch lokale Referenz/Pointer ersetzen - schon zu oft ein falsches Einstechen bei so
    [x][y][z] Einstech-Orgien gesehen

    for (i = 0; i < 8/*Magic Value*/; i++)
    { 
      /*auto&*/ curr_fbox = FB->FBox[i];
      /*auto&*/ n_359_gamma3 = N[359].Gamma[3]; // falls wirklich wie eine Art Konstante genutzt
     
      printf("n_359_gamma3 = %2.4e\n", n_359_gamma3); /*Liefert 0.2500e000*/ 
      curr_fbox.F_Thread = (TFace**)realloc(curr_fbox.F_Thread, curr_fbox.npFace * sizeof(TFace*)); /*Hier wird der Wert überschrieben*/ 
      printf("n_359_gamma3 = %2.4e\n", n_359_gamma3); /*Liefert 9.12e-008*/ 
      if (curr_fbox.F_Thread == NULL){ printf("ERROR - Unable to allocate memory!\n"); getchar(); return 1; } 
      curr_fbox.npFace = 0;
      ...
    }
    

    Schwierig, denn genau darin liegt die Systematik, wenn ich eine Menge in genau acht Untermengen räumlich unterteilen möchte. Außerdem funktioniert die Routine so. Ich habe sie häufig eingesetzt und sie hat stets das richtige geliefert.

    du sollst ja auch nur aufräumen - nicht die Semantik verändern

    1. hättest du dann eher das fehlende break gesehen und 2. passieren dann Indizierungsfehler viel seltener



  • noch ein Tip:

    das Fehler-Szenario so schnell wie möglich reduzieren

    -bleib in C/C++ mit deinen Tests - lass C# erstmal raus

    -mind 2. Testszenarien hart im Code - ein funktionierendes 1 falsches
    z.B. nur in der Dll eine Textdatei oder sonstige Datengrundlage laden und durchjagen - Fehler reproduzieren

    ich würde mir z.B. einfach eine init oder sonstige Routine in der Dll suchen und dort hart eine test_fehler() routinen einbauen die mir die Daten laed und die SubdivideOneFBox aufruft, wenn der dort nicht auftritt liegt der Fehler einfach irgendwo anders

    schnell und einfach



  • Wutz schrieb:

    int SubdivideOneFBox(FBBox* FB, TMesh* M){
    

    - Definition von TMesh fehlt

    M zeigt ja wohl irgendwie auf FB, wenn du also durch realloc den FB-Speicherbereich verschiebst (und die Größe änderst), wie stellst du dann sicher, dass M davon was mitbekommt?
    Ich sehe auch kein free zu deinem realloc.

    Nein, M zeigt nicht auf FB. M beinhaltet alle Knoten, Flächen und Zelle. Ich übergebe es nur um den Wert von N[359].Gamma[3] überwachen zu können.
    Die Funktion an sich würde ohne das Argument TMesh* M funktionieren.

    Ein free gibt es erst, wenn das Programm beendet wird, oder das Gitter aus dem Speicher gelöscht wird. Die Daten sollen im Speicher bleiben. Das ist der Sinn, dass die Daten am Anfang einmal berechnet werden und dann im Laufe weiterer Berechnungen zur Verfügung stehen.

    typedef struct TMesh{
    	char* Name;
    	char* FileName;
    	char* FullFileName;
    	char* PathName;
    
    	unsigned int Index;
    	unsigned int Dimension;
    
    	struct TNode* pNode;
    	struct TEdge* pEdge;
    	struct TFace* pFace;
    	struct TCell* pCell;
    	struct TFamily** ppFamily;
    
    	unsigned long nNode, MinNodeIndex;
    	unsigned long nEdge, MinEdgeIndex;
    	unsigned long nFace, MinFaceIndex;
    	unsigned long nCell, MinCellIndex;
    	unsigned int npFamily;
    
    	struct TNode** ppExternalNode;
    	unsigned long nExternalNode;
    
    	struct TCell** ppExternalCell;
    	unsigned long nExternalCell;
    
    	double MinEdgeLength;
    	double MaxEdgeLength;
    
    	struct TVariable* pVariable;
    	unsigned int nVarialbe;
    
    	struct NBBox NBox;
    }TMesh;
    
    extern __declspec(dllexport) void ChangeMeshName(char* Name, TMesh* M){
    	if (Name != NULL){
    		M->Name = (char*)realloc(M->Name, (strlen(Name) + 1) * sizeof(char));
    		strcpy(M->Name, Name);
    	}
    }
    


  • Gast3 schrieb:

    Gast3 schrieb:

    3. du solltest zur besseren Fehlereingrenzung von deinem C#-GUI wegkommen und direkt den C/C++ Code Debuggen - also einfach die DllMain durch eine echte/hartkodierte main mit deinem Test ersetzen- und die Dll als Executable kompilieren - dann hast du garantiert keine Debugging-Probleme mehr - ausserdem ist C# für die Fehlereingrenzung nicht relevant und stört nur - oder ist der Auslöser (aber das merkst du dann sehr schnell)

    Langfristig, gerne. Aber ich habe mich mit QT noch nicht auseinandergesetzt und das Programm ist schon sehr weit fortgeschritten:
    https://www.youtube.com/watch?v=iCjezalOBP4

    Muss das jetzt so erstmal fertig bringen...
    Außerdem wurde mir hier im Forum gesagt: "Nutze nie C/C++ um GUIs zu
    programmieren!!" 😋

    das meinte ich nicht - du sollst nur für die Fehlereingrenzung das GUI Verlassen und die Dll (kurz mal) in eine Applikation umwandeln und dort deinen Test machen - dann wäre klar ob es an C# oder C/C++ liegt (es ist für niemanden hier klar wie C# die Schnittstelle nutzt), und dein Debugger funktioniert anständig

    Achso. Ich habe bei der Ausführung der DLL eine Konsolenausgabe definiert. Aber ich kann das auch mal versuchen. Dauert nur ein wenig, denn so einfach ist das nicht, alle Usereingaben fest zu schreiben.



  • Gast3 schrieb:

    noch ein Tip:

    das Fehler-Szenario so schnell wie möglich reduzieren

    -bleib in C/C++ mit deinen Tests - lass C# erstmal raus

    -mind 2. Testszenarien hart im Code - ein funktionierendes 1 falsches
    z.B. nur in der Dll eine Textdatei oder sonstige Datengrundlage laden und durchjagen - Fehler reproduzieren

    ich würde mir z.B. einfach eine init oder sonstige Routine in der Dll suchen und dort hart eine test_fehler() routinen einbauen die mir die Daten laed und die SubdivideOneFBox aufruft, wenn der dort nicht auftritt liegt der Fehler einfach irgendwo anders

    schnell und einfach

    Also, ich werde das tun. Aber während die DLL arbeitet, ruht ja der Code in C#. Und in der DLL wird der korrekte Wert berechnet und später überschrieben. Das geschieht ja alles, während C# ruht. Aber ich werde das mal versuchen umzuschreiben - ist auch zum Teil schon im Code vorgesehen, einfach auch, dass ich es evtl. online stellen kann.



  • @Gast3: Ich habe die DLL jetzt als Executable kompiliert und lade die gleiche Datei ein. Der Fehler tritt aber unabhängig davon auf - wieder bei einem realloc-Befehl.

    Was kann dazu führen, dass realloc diesen Speicher überschreibt?

    Kann es helfen, wenn ich das komplette Projekt inkl. der Datei, die gelesen wir, mal online stelle?



  • CJens schrieb:

    Was kann dazu führen, dass realloc diesen Speicher überschreibt?

    Das
    - der Speicher vorher nicht für dich reserviert war.
    - dein Zeiger auf nicht mehr gültigen Speicher zeigt, weil du nicht alle Kopien des Zeigers (nach einem realloc) ersetzt hast.



  • DirkB schrieb:

    CJens schrieb:

    Was kann dazu führen, dass realloc diesen Speicher überschreibt?

    Das
    - der Speicher vorher nicht für dich reserviert war.
    - dein Zeiger auf nicht mehr gültigen Speicher zeigt, weil du nicht alle Kopien des Zeigers (nach einem realloc) ersetzt hast.

    Das kann ich eigentlich ausschließen, da ich den Speicher erst wenige Zeilen vorher reserviere und überprüfe. Außerdem dürfte die Funktion dann nicht den korrekten Wert liefern. Kann es daran liegen, dass ich weit vorher irgendwo über einen Index hinaus gelaufen bin?



  • Also, jetzt wirds etwas ekelhaft, aber vielleicht hilft das. Ich habe ja den Code der DLL so abgeändert, dass ich ihn auch als Executable ausführen kann.

    Wenn ich das Projekt in VS 2015 kompiliere, tritt der Fehler auf.
    Kompiliere ich es in VS2013, tritt der Fehler NICHT auf.



  • Wenn ich das Projekt in VS 2015 kompiliere, tritt der Fehler auf.
    Kompiliere ich es in VS2013, tritt der Fehler NICHT auf.

    ich denke nicht das du einen Fehler in VStudio entdeckt hast sondern eher irgendein undefined-behavior oder sonstiges anstoesst - sowas merkt man oft bei Kompilerwechsel

    Kann es helfen, wenn ich das komplette Projekt inkl. der Datei, die gelesen wir, mal online stelle?

    wenn du es kannst/darfst - hilft es bestimmt mehr als es nicht zu tun



  • Gast3 schrieb:

    Wenn ich das Projekt in VS 2015 kompiliere, tritt der Fehler auf.
    Kompiliere ich es in VS2013, tritt der Fehler NICHT auf.

    ich denke nicht das du einen Fehler in VStudio entdeckt hast sondern eher irgendein undefined-behavior oder sonstiges anstoesst - sowas merkt man oft bei Kompilerwechsel

    Kann es helfen, wenn ich das komplette Projekt inkl. der Datei, die gelesen wir, mal online stelle?

    wenn du es kannst/darfst - hilft es bestimmt mehr als es nicht zu tun

    Also, weil hier andere User (nicht Du) gerne mal empfindlich reagieren: Mir ist klar, dass ich keinen Compilerfehler entdeckt habe. VS2013 wird genau so korrekt arbeiten wie VS2015 - aber ich muss das ja hier posten, wenn ich es entdecke. Kann es an Einstellungen liegen? Kann ich den Compiler vielleicht noch etwas kleinlicher einstellen, dass er bei geringeren Fehler schon anspricht oder so? Optimierung ist in beiden Fällen deaktiviert - aber das wird ja glaube ich im Projekt gespeichert.

    Ich habe hier nur sehr langsames Handy Internet, aber ich werde in etwa einer Stunde mal das Projekt hochladen UND ein Video auf Youtube stellen, welches den Fehler zeigt.

    realloc überschreibt übrigens keinen verwendeten Speicher. N[359].Gamma[3] ist im aktuellen Fall in Adresse 3 987 192 gespeichert.
    Der Speicher, welcher reserviert wird (bei npFace = 1) ist 3 987 248 - ist nur ein Feld, variiert natürlich bei jedem Ausführen.



  • Gibt es Fehlermeldungen beim Kompilieren?

    Könnten (fehlerhafte) Fließkommaberechnungen den Fehler mitverursachen?

    Gibt es schon eine Fehlertheorie(n) (verfehltes Speichermanagement, verdächtige Zeiger o.ä) ?

    Wie sieht das Testszenario aus?

    Was sagt die Fehlerdatenbank?

    Breakpoints kann man zur Not auch von Hand setzen. Besser sind aber Fehlersuchtools für bestimmte Aufgaben.

    Wie zeigt sich der Bug, bzw. wie hast du den Fehler überhaupt selbst entdeckt?
    Eventuell gibt es keinen Fehler, alles nur ein Irrtum?

    Gibt es irgendwo (verdächtige) Zeitverzögerungen (Profiler o.ä.) ?

    Eine stärkere Modulstruktur ist generell debuggingfreundlicher.

    Guidelines kennen hilft ebenfalls z.B.:
    http://www.informit.com/articles/article.aspx?p=1823696&seqNum=2
    http://stackoverflow.com/questions/21006707/proper-usage-of-realloc
    Außerdem lassen sich solche Guidelines/Guides gut automatisieren bzw. automatisiert testen.



  • nachtfeuer schrieb:

    Gibt es Fehlermeldungen beim Kompilieren?

    Nein, gibt keine.

    nachtfeuer schrieb:

    Könnten (fehlerhafte) Fließkommaberechnungen den Fehler mitverursachen?

    Das glaube ich nicht. Ich lese mehrere tausend Zahlen ein - und ich gebe mir das Ergebnis anschließend aus. Die Koordinaten sind alle korrekt, sonst würde die 3D Darstellung des Gitters das zeigen.

    nachtfeuer schrieb:

    Gibt es schon eine Fehlertheorie(n) (verfehltes Speichermanagement, verdächtige Zeiger o.ä) ?

    Ich denke, dass ich irgendwann beim Einlesen mit einem Zeigerindex über ein Feld hinaus fahre und dabei irgend etwas überschreibe, was mir später diesen Fehler verursacht. Ich habe eben mal alle Koordinaten die gelesen werden in MS Excel geladen, das Zahlenformat auf acht Nachkommastellen gesetzt, die Daten in der Datei ersetzt, dann trat exakt der gleiche Fehler etwas später in genau der gleichen Routine auf.

    nachtfeuer schrieb:

    Wie sieht das Testszenario aus?

    Ich kann die Funktion, welche N[359].Gamma[3] erneut berechnet nach dem Einlesen nochmals manuell ausführen, dann Berechnungen starten. Ich kann die Poissongleichung auf dem Rechengitter lösen, das heißt, dass alles funktionieren muss. Es darf kein Wert falsch sein, sonst würde das Gleichungssystem nicht lösbar sein. Aber der Code stürzt manchmal unvorhergesehen ab.
    Ich arbeite seit acht Monaten täglich an dem Code - ich fühle mich einfach nicht wohl, wenn ich weiß, dass das auftritt. Bei anderen Gitterdateien tritt das scheinbar nicht auf.

    nachtfeuer schrieb:

    Breakpoints kann man zur Not auch von Hand setzen. Besser sind aber Fehlersuchtools für bestimmte Aufgaben.

    Jetzt wo ich die DLL als Executabel ausführe, kann ich auch Breakpoints setzen und tue das auch. Aber die zeigen mir nichts anderes. Vor dem Realloc ist der Wert korrekt, danach nicht mehr.

    nachtfeuer schrieb:

    Wie zeigt sich der Bug, bzw. wie hast du den Fehler überhaupt selbst entdeckt?
    Eventuell gibt es keinen Fehler, alles nur ein Irrtum?

    Ich habe den Fehler entdeckt, weil die Berechnungsergebnisse um diesen Punkt nicht korrekt dargestellt wurden.

    Gibt es irgendwo (verdächtige) Zeitverzögerungen (Profiler o.ä.) ?

    Eine stärkere Modulstruktur ist generell debuggingfreundlicher.

    Aber es ist wirklich auffällig, dass das gleiche Projekt mit VS2013 den Fehler nicht zeigt.


Anmelden zum Antworten