(mir) unerklärliche Abstürze



  • Hallo miteinander!
    Ich habe hier eine Routine zur Gerätekommunikation über RS232, die meinen Computer zum Totalabsturz bringt (Neustart). Das Ding wird so alle 5 Sekunden ausgeführt, und wenn ich morgens wieder komme, hat sich die Kiste meistens neu gestartet.
    Ich hab nicht viel Ahnung von sauberer 😃 Programmierung, deshalb kann's sein, dass es ein ganz plumper Fehler ist, der einem Experten sofort auffällt. Folgender Code unter MS Visual C++ 6.0, die GetTempOf ist die, die so alle paar Sekunden aufgerufen wird:

    float COfenController::GetTempOf(unsigned char OfenNummer){
    unsigned char funktion = 0x89;  //0x89 : Lesen 
    unsigned char index = 0xE7;	//0xE7 : aktueller Istwert, siehe Schnittstellenbeschr. S. 36
    	CHARVECTOR datenblock; //leer
    	LangsatzSenden(OfenNummer,funktion,index,datenblock);
    	Sleep(200);
    	CHARVECTOR antwort = DatenblockAuslesen();
    	float temperatur = Hex2Float(antwort);
    	return temperatur;
    }
    
    void COfenController::LangsatzSenden(unsigned char ofennummer, unsigned char funktion, unsigned char index, CHARVECTOR datenblock){
    unsigned char carray_daten[100] = {0};        //wird benötigt, da SerialCom::Write(unsigned Nr,void *Buffer,int Count) ein array benötigt
        CHARVECTOR cvector_daten = DatenZusammenstellen(ofennummer, funktion, index, datenblock , carray_daten);		//Die Zeichenkette ist nun sowohl in cvector_daten als auch in carray_daten gespeichert
        Write(COMPort,carray_daten,cvector_daten.size());      //Senden der Daten; cvector_daten.size() entspricht der Länge der Daten
    }
    
    CHARVECTOR COfenController::DatenZusammenstellen(unsigned char ofennummer, unsigned char funktion, unsigned char index,   CHARVECTOR daten_rein, unsigned char* daten_raus){
    		CHARVECTOR anwenderdaten;							//Zusammenstellen des Anwenderdatenblocks
    		//******Anwenderdaten*******
    		anwenderdaten.push_back(ofennummer);				//Adresse
    		anwenderdaten.push_back(funktion);					//Funktion
    		anwenderdaten.push_back(index);						//Index
    		for (int i = 0 ; i < daten_rein.size(); ++i) {		//in daten_rein musst der Datenblock gespeichert sein,
    				anwenderdaten.push_back(daten_rein[i]);		//dieser kann aber auch leer sein (z.B. beim Lesen).
    		}
    
    		CHARVECTOR zusammenstellung;						//Langsatz zusammensetzen:	
    
    		//********Kopf********
    		zusammenstellung.push_back(0x68);						//Startzeichen
    		zusammenstellung.push_back(anwenderdaten.size());		//Länge des Anwenderdatenblocks
    		zusammenstellung.push_back(anwenderdaten.size());		//Länge des Anwenderdatenblocks
    		zusammenstellung.push_back(0x68);						//Startzeichen
    		//********\Kopf********
    
    		//******Anwenderdaten*******
    		{for (int i = 0 ; i < anwenderdaten.size(); ++i) {
    				zusammenstellung.push_back(anwenderdaten[i]);
    		}}
    		//******\Anwenderdaten*******
    
    		//*****Fuß*****
    		zusammenstellung.push_back(Pruefsumme(anwenderdaten));		//Prüfsumme des Anwenderdaten
    		zusammenstellung.push_back(0x16);							//Stopzeichen
    		//*****\Fuß*****
    
    		{for (int i = 0 ; i < zusammenstellung.size() ; ++i) {		//Für die Serielle Kommunikation wird der Lansatz
    				daten_raus[i] = zusammenstellung[i];				//als Array von (unsigned) chars benötigt, dieser
    		}}											//wird hier zusammengesetzt.
        return zusammenstellung;
    }
    
    CHARVECTOR COfenController::DatenblockAuslesen(){
    	const int zaehler = GetReadCount(COMPort);  //Wieviele Zeichen liegen im Lesepuffer?
    	unsigned char carray_antwort[100] = {0};		//wird benötigt, da SerialCom::Read(unsigned Nr,void *Buffer,int Count) ein array benötigt
    	Read(COMPort,carray_antwort,zaehler);  //Gesamten Lesepuffer auslesen
    	CHARVECTOR antwort;
    	// Datenblock im CHARVECTOR speichern; carray_antwort[1] enthält die Länge der Anwenderdaten inklusive dem 
    	// Zeichen "Funktion" (Siehe Schnittstellenbeschreibung S. 5). Der Datenblock (ohne "Funktion" und "Index") beginnt
    	// bei carray_antwort[6]. 
    	for (int i = 6; i < 6 + (carray_antwort[1] - 2); ++i ) antwort.push_back(carray_antwort[i]); 	
    	return antwort;
    }
    
    float COfenController::Hex2Float(CHARVECTOR hexzahlen){
    union{
    	unsigned char array[4];
    	float fliesspunkt;
    } konvertierung;
    	for (int i = 0; i < 4; i++) konvertierung.array[i] = hexzahlen[i];
    	return konvertierung.fliesspunkt;
    }
    

    Ich erwarte nicht, dass jetzt jemand sofort sieht, woran's hakt, aber vielleicht hat ja auch einer ne Idee, wie ich den Fehler ein bisschen einkreisen kann.

    Besten Dank!
    rufusD



  • Erstmal sieht das ganze tatsächlich sehr unübersichtlich aus.

    Zweitens: Wie groß sind denn die Nutzdaten, die du der Funktion übergibst? Reichen da wirklich die reservierten 100 Byte aus?

    Drittens: Es ist nicht unbedingt norwendig, die Daten zu kopieren, wenn du nur Lesezugriff darauf benötigst - mit "&data[0]" bekommst du einen Zeiger auf den Anfang des Vector-Inhalts (ist zwar nicht allgemein bekannt, aber afaik vom Standard gefordert).
    (falls du auf der sicheren Seite sein willst, kannst du auch std::string anstelle von vector<char> verwenden)

    PS: Ist es eigentlich Absicht, daß du zweimal die Größe der Nutzdaten speicherst - und dann beide Ausführungen auf 1 Byte gestutzt?



  • Hi!
    Erstens: Tja, da sagst Du was...
    Das blöde ist, dass ich die Routine geerbt habe, nicht selber geschrieben. Ich versuche noch, die Schnittstellendokumentation aufzutreiben, dann kann ich da mal weiter sehen.

    Zweitens: ich denke, die 100 Byte reichen gut (sag ich genauer, wenn ich die Doku hab)

    Drittens: OK, mach ich mich mal ran - war mir gar nicht aufgefallen.

    Was mich generell wundert ist, dass die Routine ja oft problemlos durchläuft. Das sollte mir sicher was sagen, aber ich weiß nicht was. Vielleicht überlade ich irgendeinen Adressraum, weil ich jedesmal (vgl. drittens) eine neue Variable aufmache? Woran kann denn so unregelmäßiges Verhalten generell noch liegen? Ich erinner mich, vor Jahrzehnten mal Pointervariablen definiert, aber keinen Speicher für sie reserviert, zu haben; damit konnte man auch Russisches Roulette spielen, aber ob hier so was in der Art passiert, seh ich überhaupt nicht.



  • Zu zweitens: frag doch einfach in der Senden-Funktion ab, wie groß der übergebene vector<> ist 😉 Das ist schneller als sich durch die Dokumentationen zu wühlen (bei so einem Code würde ich nicht erwarten, eine besonders ausführliche Doku zu erhalten).
    Du brauchst 6 Byte für Kopf- und Fußdaten in der Funktion - d.h. wenn du mehr als 94 Byte an Nutzdaten eintragen willst, überschreibt die Funktion den Bereich, der hinter deinem Array auf dem Stack liegt - möglicherweise der CHARVECTOR.



  • , die meinen Computer zum Totalabsturz bringt (Neustart).

    Dann hast du ein grösseres Problem als nur einen Programmierfehler in deinem Programm.
    Deinen Computer zum Absturz bringen darf ein Programm welches im Usermode läuft niemals können. Wenn es doch möglich ist dann ist irgendwo ein Treiber fehlerhaft o.ä.
    Ein Fehler in Windows ist natürlich auch nie ganz auszuschliessen, allerdings unwahrscheinlich.



  • OK, danke allen für die Ideen.
    Was mich dann doch stutzig machte ist, dass der Code auf einem anderen Rechner problemlos tagelang durchläuft. Ich hab jetzt zwei unnötige (btw sündhaft teure namhafte) Hintergrundprozesse gefunden, nach deren Beenden auch *mein* Rechner ohne Weiteres durchläuft 🙄.
    Klar, schöner wird mein Code dadurch auch nicht, aber wenigstens kann ich jetzt damit arbeiten 🤡


Anmelden zum Antworten