Probleme mit delete (Base64 Coder ...Umfangreich)



  • Hallo Leute,

    ich habe mir vor einigen Wochen einen Base64 Kodierer/Dekodierer aus Codeschnipseln zusammengebaut, der gar nicht schlecht funktioniert.
    Nun habe ich versucht eine Speicherfreigabe zu realisieren, da ich die Kodierung nun in einer Schleife nutzen möchte(ca. 10000 mal).

    Ich habe in letzter Zeit des öfteren Klassenobjekte angelegt, Speicher zugewiesen und wieder frei gegeben. Alles wunderbar! Doch hier krieg ichs einfach nicht hin.... 😡
    Dabei versuche ich es mit einem Kollegen zusammen schon mehr als 3 Tage.

    Der Code ist recht umfangreich, doch hoffe ich, dass sich mal ein Crack diesen anschaut und uns aus der Patsche helfen kann.

    Ich wüsste nicht wie ich das Problem noch genauer beschreiben könnte, um die Suche nach dem Fehler leichter zu machen. Habt also bitte ein wenig Verständnis und macht mich nicht gleich fertig, wegen dem umfangreichen Code 🙂

    Ach noch was: Rufe ich die Methode "Clear()" sofort auf, so Stürzt das Program ab (auf die übliche Art und Weise, wenn es sich um fehlerhafte Deletes handelt)

    VIELEN DANK!!!!!!!!!!
    Günni

    void CBASE64Dlg::OnButtonCStringKodieren() 		//MEIN ALLES AUSLÖSENDER BUTTON
    {
    	Encode64 = new CBASE64Encode(m_eingabe);
    	m_ausgabe = Encode64 ->GetEncoded();
    	//Encode64->Clear();
    	UpdateData(false);
    	delete Encode64;
    }
    
    class CBASE64Encode  		//DIE BASE64 KLASSE
    {
    public:
    	byte* m_source;
    	byte* m_source2;
    	byte* m_buffer;	
    	byte* m_quelle;
    	char* m_result;
    	char* m_lookupTable;
        int length,length2;
        int blockCount;
        int paddingCount;
    
    	CBASE64Encode(CString Inhalt);
    	virtual ~CBASE64Encode();
    
    	char sixbit2char(byte b);
    	CString GetEncoded();
             void Clear();
    };
    
    CBASE64Encode::CBASE64Encode(CString Inhalt)	//KONSTRUKTOR
    {
    	m_quelle = new byte[10000];
    	//Inhalt = Inhalt + '\0';
    	int laenge = Inhalt.GetLength();
    
    	for(int x=0; x<Inhalt.GetLength(); x++)
    	{
    		m_quelle[x] = static_cast<byte>(Inhalt[x]);
    	}
    
    	//m_quelle[3] = '0x00';
    
    	m_source = m_quelle;
    	length=laenge;
    
    	if((length % 3)==0)
    	{
    		paddingCount=0;
    		blockCount=length/3;
    	}
    	else
    	{
    		paddingCount=3-(length % 3);//need to add padding
    		blockCount=(length+paddingCount) / 3;
    	}
    
    	length2=length+paddingCount;//or blockCount *3
    }
    
    CBASE64Encode::~CBASE64Encode()			//DESTRUKTOR
    {
    	Clear();
    }
    
    CString CBASE64Encode::GetEncoded()			//METHODE ZUM KODIEREN
    {
    	m_source2 = new byte[length];
    	//copy data over insert padding
    
    	for (int y=0; y<length2;y++)
    	{
    		if (y<length)
    		{
    			m_source2[y]=m_source[y];
    		}
    		else
    		{
    			m_source2[y]=0;
    		}
    	}
    
    	byte b1, b2, b3;
    	byte temp, temp1, temp2, temp3, temp4;
    	m_buffer = new byte[blockCount*4];
    	m_result = new char[blockCount*4];
    
    	for (int x=0;x<blockCount;x++)
    	{
    		b1=m_source2[x*3];
    		b2=m_source2[x*3+1];
    		b3=m_source2[x*3+2];
    
    		temp1=(byte)((b1 & 252)>>2);//first
    
    		temp=(byte)((b1 & 3)<<4);
    		temp2=(byte)((b2 & 240)>>4);
    		temp2+=temp; //second
    
    		temp=(byte)((b2 & 15)<<2);
    		temp3=(byte)((b3 & 192)>>6);
    		temp3+=temp; //third
    
    		temp4=(byte)(b3 & 63); //fourth
    
    		m_buffer[x*4]=temp1;
    		m_buffer[x*4+1]=temp2;
    		m_buffer[x*4+2]=temp3;
    		m_buffer[x*4+3]=temp4;
    	}
    
    	for (int z=0; z<blockCount*4;z++)
    	{
    		m_result[z]=sixbit2char(m_buffer[z]);
    	}
    
    	//convert last "A"s to "=", based on paddingCount
    	switch (paddingCount)
    	{
    		case 0:break;
    		case 1:m_result[blockCount*4-1]='=';break;
    		case 2:m_result[blockCount*4-1]='=';
    		m_result[blockCount*4-2]='=';
    		break;
    		default:break;
    	}
    
    	CString uebergabe = m_result;
    	return uebergabe;
    }
    
    char CBASE64Encode::sixbit2char(byte b)			//METHODE ZUM WANDELN DER EINZELNEN ZEICHEN
    {
    	m_lookupTable=new char[64];
    	m_lookupTable[0] = 'A';
    	m_lookupTable[1] = 'B';
    	m_lookupTable[2] = 'C';
    	m_lookupTable[3] = 'D';
    	m_lookupTable[4] = 'E';
    	m_lookupTable[5] = 'F';
    	m_lookupTable[6] = 'G';
    	m_lookupTable[7] = 'H';
    	m_lookupTable[8] = 'I';
    	m_lookupTable[9] = 'J';
    	m_lookupTable[10] = 'K';
    	m_lookupTable[11] = 'L';
    	m_lookupTable[12] = 'M';
    	m_lookupTable[13] = 'N';
    	m_lookupTable[14] = 'O';
    	m_lookupTable[15] = 'P';
    	m_lookupTable[16] = 'Q';
    	m_lookupTable[17] = 'R';
    	m_lookupTable[18] = 'S';
    	m_lookupTable[19] = 'T';
    	m_lookupTable[20] = 'U';
    	m_lookupTable[21] = 'V';
    	m_lookupTable[22] = 'W';
    	m_lookupTable[23] = 'X';
    	m_lookupTable[24] = 'Y';
    	m_lookupTable[25] = 'Z';
    	m_lookupTable[26] = 'a';
    	m_lookupTable[27] = 'b';
    	m_lookupTable[28] = 'c';
    	m_lookupTable[29] = 'd';
    	m_lookupTable[30] = 'e';
    	m_lookupTable[31] = 'f';
    	m_lookupTable[32] = 'g';
    	m_lookupTable[33] = 'h';
    	m_lookupTable[34] = 'i';
    	m_lookupTable[35] = 'j';
    	m_lookupTable[36] = 'k';
    	m_lookupTable[37] = 'l';
    	m_lookupTable[38] = 'm';
    	m_lookupTable[39] = 'n';
    	m_lookupTable[40] = 'o';
    	m_lookupTable[41] = 'p';
    	m_lookupTable[42] = 'q';
    	m_lookupTable[43] = 'r';
    	m_lookupTable[44] = 's';
    	m_lookupTable[45] = 't';
    	m_lookupTable[46] = 'u';
    	m_lookupTable[47] = 'v';
    	m_lookupTable[48] = 'w';
    	m_lookupTable[49] = 'x';
    	m_lookupTable[50] = 'y';
    	m_lookupTable[51] = 'z';
    	m_lookupTable[52] = '0';
    	m_lookupTable[53] = '1';
    	m_lookupTable[54] = '2';
    	m_lookupTable[55] = '3';
    	m_lookupTable[56] = '4';
    	m_lookupTable[57] = '5';
    	m_lookupTable[58] = '6';
    	m_lookupTable[59] = '7';
    	m_lookupTable[60] = '8';
    	m_lookupTable[61] = '9';
    	m_lookupTable[62] = '+';
    	m_lookupTable[63] = '/';
    
    	if((b>=0) &&(b<=63))
    	{
    		return m_lookupTable[(int)b];
    	}
    	else
    	{
    		//should not happen;
    		return ' ';
    	}
    }
    
    void CBASE64Encode::Clear()				//SPEICHER FREI GEBEN 
    {
    	if(m_buffer)
    	{
    		delete[]m_buffer;
    		m_buffer = NULL;
    	}
    
    	if(m_quelle)
    	{
    		delete[]m_quelle;
    		m_quelle = NULL;
    	}
    
    	if(m_result)
    	{
    		delete[]m_result;
    		m_result = NULL;
    	}
    
    	if(m_source)
    	{
    		delete[]m_source;
    		m_source = NULL;
    	}
    
    	if(m_source2)
    	{
    		delete[]m_source2;
    		m_source2 = NULL;
    	}
    
    	if(m_lookupTable)
    	{
    		delete[]m_lookupTable;
    		m_lookupTable = NULL;
    	}
    }
    


  • Grenze den Fehler mal ein.

    Im Konstruktor die Zeiger Initialisieren.
    Das Objekt nur erstellen und dann löschen ohne die Methode GetEncoded auf zu rufen.

    Wenn das klappt die Methode GetEncoded zerlegen und pürfen ob nicht
    irgendwo über den Index geschrieben wird.

    Der Debugger ist Dein Freund 🤡



  • So ein langer Code, der nicht kompilierbar ist, wird doch eh von kaum einem gelesen.

    Benutz einen Debugger und am besten Valgrind.

    Ein paar generelle Sachen:
    * C als Anfangsbuchstaben von Klassennamen ist nicht schön
    * if(a) delete a; ist überflüssig, da delete auch NULL-Pointer löschen kann (also intern wird schon auf NULL geprüft)
    * ist dein Code teilweise im Bezug auf Exception Sicherheit problematisch (siehe gotw.ca/exceptional c++)



  • Kein schlechter Gedanke Knuddlbaer.

    Haben wir im groben auch schon ausprobiert. Doch leider kann ich den Fehler nicht so leicht eingrenzen.

    Nur so viel: Die eigentliche Umwandlung funktioniert 1 mal einwandfrei!
    Nur in einer Schleife klappts halt nicht. Es hat definitiv mit den Deletes zu tun, da es läuft wenn man den Speicher NICHT frei gibt.

    Also kürzt sich der zu durchforstende Code eigentlich auf wenige Zeilen. Doch habe ich eben alles dazugepackt, um einen Zusammmenhang zu zeigen.

    Ich versuche natürlich mal die Tipps, doch habe ich nicht al zu viel Hoffnung.
    Ich denke wir haben uns schon zu sehr auf verschiedene Dinge eingeschossen.

    Kann ich irgendwie helfen, dass Ihr mir besser helfen könnt???? 😕

    Wäre nett, wenn sich doch jemand die Mühe machen könnte, mal genauer reinzuschauen. Wir hängen einfach voll frustriert fest.

    Danke!!



  • Ach ja:

    Der Fehler hat mit der "GetDecoded()" zu tun. Denn ohne funktioniert die SPeicherfreigabe soweit einwandfrei.

    Und zwar haben wir auch schon festgestellt, dass es wahrscheinlich am Delete der "source", "source2" oder "lookupTable" liegt.
    Kommentiere ich diese aus, so funktioniert es wieder.

    😕



  • Einen Code, bei dem die Variablen m_source, m_source2 und m_quelle bzw. length und length2 heißen, will ich mir ehrlich gesagt nicht genauer anschauen. Die Probleme sind hausgemacht.

    Ich würde dir raten, die ganzen Zeiger durch Vektoren zu ersetzen. resize statt new, sozusagen.



  • Danke!

    Ich habe den Code zum grossen Teil übernommen. Und leider habe ich von Vektoren noch keinen Plan. Dachte nur Ihr könntet helfen.

    Vielleicht findet sich ja noch einer, der ein wenig Nachsicht mit uns hat, zumal wir keine Programmierer sind.
    Dafür sind wir doch gar nicht sooo schlecht, als dass man uns unsere Fehler ständig unter die Nase reiben muss.
    Eine Lösung und dann Kritik ... DAS WÄRE COOL!!

    Danke!



  • Hallo,

    Mir fällt z.Bsp. bei GetEncoded auf, dass du für den Fall length2>length bei m_source2 in nicht allozierten Speicher schreibst.



  • @Guenter Mies:

    Du holst nirgendwo mit new Speicher für m_source, du kopierst nur den Zeiger von m_quelle. Daher darfst du auch m_source nicht mit delete freigeben.

    Der Fall, den Braunstein beschreibt, tritt tatsächlich ein.



  • Ich würde vorschlagen es so zu machen, wie MFK vorschlägt. Schau Dir an wie std::vector funktioniert. Es gibt viele Beispiele hier im Forum (Suchfunktion!) und wenn Du was nicht verstehst frag nach. Dann ersetzt mal alles und Du wirst sehen: mit hohere Wahrscheinlichkeit funktioniert es dann schon.

    btw.: den lookuptable würd ich eher als

    char * lookuptable = "ABCDEF..."; machen. Da kannste auch reinindizieren. Und mach ihn static in die Klasse, dann mußte nicht bei jedem Funktionsaufruf frisch anlegen.



  • Danke für die Tipps!

    Werde es mir die Tage nochmals genauer anschauen. Muss erstmal Abstand gewinnen und werde daher die Base64 Routine vorerst gegen etwas einfacheres ersetzen.

    Aber so weit waren die Tipps schon sehr hilfreich.

    Gruß
    Günni



  • Du bist ja offenbar mit MSVC zu Gange. Weißt du, dass es da fertige Funktionen gibt?

    Base64Decode und Base64Encode aus <atlenc.h>



  • [doppelt]



  • @ MFK

    Gehört das es eine include für base64 gibt haben wir schon!
    Nur leider gibt es diese Funktionalität (scheinbar) nicht auf eVC und genau da soll es laufen!

    atlenc.h ist diese header in der standardbiblothek won MSVC vorhanden? Offenbar nicht, sonst könnte ich sie ja einfach includieren, weißt du wo wir Sie herbekommen?

    Mann könnte ja mal testen .. .. ..

    Sven ( && Günni)



  • atlenc.h ist bei Visual Studio.NET 2003 dabei. Die Funktionen sind AFAIK inline, also könnte man sie direkt rauskopieren.



  • hmm haben leider kein .NET

    ???

    sven


Anmelden zum Antworten