crash mit nicht nachvollziehbarem Stack



  • Bei mir läuft ein Programm ca 30 Minuten bevor es crasht. Dabei wird folgendes aufgerufen

    1. fillPlot(int plotnumber=3, double * ArrayX=0x0114ae98, double * ArrayY=0x0115af98, int N=2048)
    2. setData(const unsigned int number=1, const double * xData=0x0114ae98, const double * yData=0x0115af98, int size=2048)
    

    Soweit ist alles richtig. fillplot ruft setData auf, übergibt dabei die Array Pointer und hat als number immer 1 (das ist im Quellcode fest eingebaut) und als Size immer 2048 (wird mit programmstart als größe der Arrays festgelegt).

    Das funktioniert auch ein paar 10.000 mal. Und dann plötzlich wird nach setData das nochmal aufgerufen mit vollkommen unsinnigen Werten:

    setData(const unsigned int number=16740072, const double * xData=0x0114ae98, const double * yData=0x00004000, int size=1235108)
    

    hier der vollständige Stack:

    msvcr80d.dll!fastcopy_I(void * dst=0x0114aea0, void * src=0x00003f80, int len=0)  + 0x50 Bytes	C
     	msvcr80d.dll!_VEC_memcpy(void * dst=0x0114aea0, void * src=0x00003ff8, int len=8)  + 0x52 Bytes	C
     	msvcr80d.dll!_VEC_memcpy(void * dst=0x0114ae98, void * src=0x00004000, int len=1235108)  + 0xb4 Bytes	C
     	ModelockingSimulationd.exe!QCurvePlot::setData(const unsigned int number=16740080, const double * xData=0x0114aea0, const double * yData=0x00003f80, int size=0)  Zeile 87 + 0x22 Bytes	C++
     	msvcr80d.dll!_VEC_memcpy(void * dst=0x0114aea0, void * src=0x00003ff8, int len=8)  + 0x52 Bytes	C
     	msvcr80d.dll!_VEC_memcpy(void * dst=0x0114ae98, void * src=0x00004000, int len=1235108)  + 0xb4 Bytes	C
    >	ModelockingSimulationd.exe!QCurvePlot::setData(const unsigned int number=16740080, const double * xData=0x0114aea0, const double * yData=0x00003ff8, int size=8)  Zeile 87 + 0x22 Bytes	C++
     	msvcr80d.dll!_VEC_memcpy(void * dst=0x0114ae98, void * src=0x00004000, int len=1235108)  + 0xb4 Bytes	C
     	ModelockingSimulationd.exe!QCurvePlot::setData(const unsigned int number=16740072, const double * xData=0x0114ae98, const double * yData=0x00004000, int size=1235108)  Zeile 87 + 0x22 Bytes	C++
     	ModelockingSimulationd.exe!QCurvePlot::setData(const unsigned int number=1, const double * xData=0x0114ae98, const double * yData=0x0115af98, int size=2048)  Zeile 87 + 0x22 Bytes	C++
     	ModelockingSimulationd.exe!MainWindow::fillPlot(int plotnumber=3, double * ArrayX=0x0114ae98, double * ArrayY=0x0115af98, int N=2048)  Zeile 236	C++
    

    Der Code dazu ist folgender:

    void MainWindow::fillPlot(int plotnumber, double * ArrayX, double * ArrayY, int N)
    {
    	QCurvePlot * plot;
    	switch(plotnumber)
    	{
    		case 1: plot = CurvePlot1; break;
    		case 2: plot = CurvePlot2; break;
    		case 3: plot = CurvePlot3; break;
    		case 4: plot = CurvePlot4; break;
    		default:
    			return;
    	}
    
    	plot->setData(1, ArrayX, ArrayY, N);
    	plot->qwtPlot->replot();	
    }
    
    void QCurvePlot::setData(const unsigned int number, const double * xData, const double * yData, int size)
    {
    	if (number <= m_data.size())
    	{
    		int arraynumber = number - 1;
    		if (m_data[arraynumber].x != NULL )
    			delete [] m_data[arraynumber].x;
    		if (m_data[arraynumber].y != NULL )
    			delete [] m_data[arraynumber].y;
    		m_data[arraynumber].x = new double [size];
    		m_data[arraynumber].y = new double [size];
    		memcpy(m_data[arraynumber].x, xData, size * sizeof(double));
    		memcpy(m_data[arraynumber].y, yData, size * sizeof(double));
    		Curve[number].setData(m_data[arraynumber].x, m_data[arraynumber].y, size);
    		zoomer->initScale();
    	}
    }
    

    irgenteine Idee wie ich das debuggen sollte?



  • Das Problem scheint im rekursiven Aufruf zu liegen. fillPlot() ruft setData() noch richtig auf, aber setData() macht dann wahrscheinlich in der folgenden Zeile einen Fehler:

    Curve[number].setData(m_data[arraynumber].x, m_data[arraynumber].y, size);
    

    Benutze doch Container, dann kannst du dir auch das Gefrickel mit der Speicherverwaltung sparen. Oder wenigstens std::copy() statt memcpy() .

    Ausserdem musst du Zeiger nicht auf Null prüfen, bevor du delete oder delete[] auf sie anwendest.



  • Nexus schrieb:

    Das Problem scheint im rekursiven Aufruf zu liegen. fillPlot() ruft setData() noch richtig auf, aber setData() macht dann wahrscheinlich in der folgenden Zeile einen Fehler:

    Curve[number].setData(m_data[arraynumber].x, m_data[arraynumber].y, size);
    

    Das 'Curve[number].setData' ist eine Funktion aus einer Bibliothek, und die erwartet eine C-Array. Rekursive Aufrufe gibt es dabei nicht. Ich leite die Daten eher weiter.

    Nexus schrieb:

    Benutze doch Container, dann kannst du dir auch das Gefrickel mit der Speicherverwaltung sparen. Oder wenigstens std::copy() statt memcpy() .

    Da ich sowohl in der Rechnung als auch in der Ausgabe mit externen Bibliotheken arbeiten, die keine Container benutzen bin ich auf C-Arrays angewiesen. Ansonsten würde ich gerne mit std::copy arbeiten.

    Nexus schrieb:

    Ausserdem musst du Zeiger nicht auf Null prüfen, bevor du delete oder delete[] auf sie anwendest.

    Ich weiß, ich habe es nur noch nicht überall entfernt.



  • Du kannst std::copy() auch mit C-Arrays verwenden.

    Sogar Container können kompatibel sein. Der std::vector hat intern den gleichen Aufbau wie ein dynamisches Array - es ist garantiert, dass die Elemente linear hintereinander im Speicher liegen.

    Du brauchst nur einen Zeiger auf das erste Element zu übergeben, und schon hast du die Schnittstelle zu C.

    std::vector<double> Vec(5, 6.324);
    C_API_Funktion(&Vec[0]);
    


  • Das habe ich noch nie so gehört, und demnach nie benutzt. Jetzt das Programm deshalb komplett umzuschreiben würde allerdings sehr aufwendig sein.

    Für das ursprüngliche Problem habe ich damit aber noch immer keine schlüssige Erklärung.



  • pospiech schrieb:

    Für das ursprüngliche Problem habe ich damit aber noch immer keine schlüssige Erklärung.

    Überprüf doch mal mit dem Debugger die Variablen in der setData() -Funktion, schau, ab wo sie fehlerhaft sind.

    pospiech schrieb:

    Das habe ich noch nie so gehört, und demnach nie benutzt. Jetzt das Programm deshalb komplett umzuschreiben würde allerdings sehr aufwendig sein.

    Du musst selbst wissen, ob sich das Umschreiben lohnt. Ich halte es allerdings für wahrscheinlich, dass dieser Fehler mit Containern nicht passieren würde (oder man würde wenigstens eine vernünftige Assertion, z.B. bei Array-Überlauf, erhalten). Du musst auch dran denken, dass der Code damit wartbarer wird und dir auch in Zukunft das Debuggen erleichtert.



  • Ich würde mal darauf tippen, dass du irgnedwo einen Überlauf hast, und/oder Speicher nicht richtig freigegeben wird und sich so ein grosses Leck ansammelt..



  • drakon schrieb:

    [...] und/oder Speicher nicht richtig freigegeben wird und sich so ein grosses Leck ansammelt..

    Hm, wobei ein Memory Leak nicht unbedingt zu falschen Variablenwerten führt...

    Aber Memory Leaks sind natürlich ein weiterer Grund dafür, warum sich Container auszahlen. 😉



  • Nexus schrieb:

    pospiech schrieb:

    Für das ursprüngliche Problem habe ich damit aber noch immer keine schlüssige Erklärung.

    Überprüf doch mal mit dem Debugger die Variablen in der setData() -Funktion, schau, ab wo sie fehlerhaft sind.

    Da der Fehler nicht determinsitisch auftritt (allerdings unabhängig vom Rechner), und ich das Programm zwischendurch neugestartet habe, kann ich das nicht mher nachvollziehen.

    Was ich aber sehen konnte, war das sowohl size, als auch number total unsinnige sehr hohe Werte hatten, und das

    int arraynumber = number - 1;
    

    den Wert von number nicht um 1 verringerte, sondern eine beliebige genauso unsinnige Zahl im Millionenbereich hatte.


Log in to reply