DAMAGE: after normal block(xx) at (0xyy)



  • Hallo,

    ich habe ein Programm das die Fehlermeldung DAMAGE: after normal block(xx) at (0xyy) ausgibt.
    Beim Debuggen sieht es dann folgendermaßen aus:

    _free_dbg_lk(void*,int)
    _free_dbg_lk(pUserData, nBlockUse)
    operator delete(void*)
    GiST::WriteNode(GiSTnode*)

    wobei die Methode WriteNode so implementiert ist:

    void 
    GiST::WriteNode(GiSTnode *node)
    {
    	cout << "gist.cpp writenode-methode\n" << endl;
    	cout << "buffer size " << store->PageSize() << "\n" << endl;
    	char *buf=new char[store->PageSize()];
    
    	// make Purify happy
    	memset(buf, 0, store->PageSize());
    
    #ifdef PRINTING_OBJECTS
    	if(debug) {
    		cout << "WRITE PAGE " << node->Path().Page() << ":\n";
    		node->Print(cout);
    	}
    #endif
    	node->Pack(buf);
    	store->Write(node->Path().Page(), buf);
    	delete buf;
    }
    

    Beim Befehl delete buf bleibt er mit dem fehler hängen. Allerdings nicht immer, sondern nur wenn der Aufruf von writenode durch diese methode passiert (die ruft writenode zweimal auf - einmal funktioniert beim anderen nicht):

    void 
    GiST::Split(GiSTnode **node, const GiSTentry& entry)
    {
    	int went_left=0, new_root=0;
    
    	if((*node)->Path().IsRoot()) {
    		new_root=1;
    		(*node)->Path().MakeChild(store->Allocate());
    	}
    
    	GiSTnode *node2=(*node)->PickSplit();
    	node2->Path().MakeSibling(store->Allocate());
    	GiSTentry *e=(*node)->SearchPtr(entry.Ptr());
    
    	if(e!=NULL) {
    		went_left=1;
    		delete e;
    	}
    	node2->SetSibling((*node)->Sibling());
    	(*node)->SetSibling(node2->Path().Page());
    	WriteNode(*node);   //dieses writeNode wird noch korrekt ausgeführt
    	WriteNode(node2);   //dieses nicht mehr
    
    	GiSTentry *e1=(*node)->Union();
    	GiSTentry *e2=node2->Union();
    
    	e1->SetPtr((*node)->Path().Page());
    	e2->SetPtr(node2->Path().Page());
    	// Create new root if root is being split
    	if (new_root) {
    		GiSTnode *root=NewNode(this);
    
    		root->SetLevel((*node)->Level()+1);
    		root->InsertBefore(*e1, 0);
    		root->InsertBefore(*e2, 1);
    		root->Path().MakeRoot();
    		WriteNode(root);
    		delete root;
    	}
    	else {
    		// Insert entry for N' in parent
    		GiSTpath parent_path=(*node)->Path();
    		parent_path.MakeParent();
    		GiSTnode *parent=ReadNode(parent_path);
    		// Find the entry for N in parent
    		GiSTentry *e=parent->SearchPtr((*node)->Path().Page());
    		assert(e!=NULL);
    		// Insert the new entry right after it
    		int pos=e->Position();
    
    		parent->DeleteEntry(pos);
    		parent->InsertBefore(*e1, pos);
    		parent->InsertBefore(*e2, pos+1);
    		delete e;
    		if(!parent->IsOverFull(*store)) WriteNode(parent);
    		else {
    			Split(&parent, went_left? *e1: *e2);
    			GiSTpage page=(*node)->Path().Page();
    
    			(*node)->Path()=parent->Path();
    			(*node)->Path().MakeChild(page);
    			page=node2->Path().Page();
    			node2->Path()=(*node)->Path();
    			node2->Path().MakeSibling(page);
    		}
    		delete parent;
    	}
    	if(!went_left) {
    		delete *node;
    		*node=node2;
    	}
    	else delete node2;
    	delete e1;
    	delete e2;
    }
    

    Ich habe echt keine Ahnung mehr woran das liegt. Habe diverses in Google gefunden, aber geholfen hat nichts. Irgendwas mit dem local Heap geht wohl nicht.

    Gruß Simpson84



  • Boar... Also nicht nur, dass die Fkt. viel zu lang ist, ich seh auch nicht durch, wo dort ein Objekt wem gehört - also wer es zerstören darf/muss/sollte und wer eben nicht... (und dort wird der fehler auch liegen)

    allein schon das ständige (*node)-> ist sehr eklig anzusehen 😛

    Splitte die Fkt doch mal in paar Unterfkt. auf, dann sieht man da vll auch noch durch...

    bb



  • Du schreibst irgendwo in Speicher, der dir nicht gehört. Dass passiert meistens wenn man irgendwas mit new[] gefrickelt hat statt Container zu benutzen, und mehr in den Speicherbereich reingeschrieben hat als reinpasst. Beim delete merkt die Runtime das und bringt diese "damage after normal block"-Fehler.
    Die genaue Stelle ist oft nicht offensichtlich. Die Kristallkugel sagt, dass du dir

    store->Write(node->Path().Page(), buf);
    

    mal genauer anschauen sollst.



  • Meine Verteidigung zu der sehr langen Funktion ist, dass ich den Code nicht selber geschrieben habe, sondern einfach nur verwenden möchte. Ich habe auch nicht besonders viel C++ Erfahrung, da ich bis jetzt immer alles in Java implementiert habe. Dort muss man sich ja auch nicht mit der Speicherfreigabe beschäftigen.
    Der Aufruf store->Write(node->Path().Page(), buf) führt hier hin.

    void 
    MTfile::Write(GiSTpage page, const char *buf)
    {
    	if(IsOpen()) {
    		lseek(fileHandle, page*PageSize(), SEEK_SET);
    		write(fileHandle, buf, PageSize());
    		IOwrite++;
    	}
    }
    

    Wenn ich die write-Methode hier richtig interpretiere, dann wird in fileHandle der Inhalt von buf hineingeschrieben, oder? Dann kann hier buf nicht übergelaufen sein. Auch der zweite Aufruf node->Pack(buf), in dem der buf eine Rolle spielt macht für mich den Eindruck, als würde buf dabei nicht verändert.

    void 
    GiSTnode::Pack(char *page) const
    {
    	// Pack the header
    	GiSTheader *h=(GiSTheader *) page;
    
    	h->level=Level();
    	h->numEntries=NumEntries();
    	h->sibling=Sibling();
    
    	int fixlen=FixedLength();
    	GiSTlte *ltable=(GiSTlte *)(page+tree->Store()->PageSize());
    	GiSTlte ltptr=GIST_PAGE_HEADER_SIZE;
    
    	for(int i=0; i<numEntries; i++) {
    		GiSTcompressedEntry compressedEntry=(*this)[i]->Compress();
    
    		if(fixlen) assert(fixlen==compressedEntry.keyLen);
    		// Copy the entry onto the page
    		if(compressedEntry.keyLen>0) memcpy(page+ltptr, compressedEntry.key, compressedEntry.keyLen);
    		memcpy(page+ltptr+compressedEntry.keyLen, &compressedEntry.ptr, sizeof(GiSTpage));
    		// Be tidy
    		if(compressedEntry.key) delete compressedEntry.key;
    		// Enter a pointer to the entry in the line table
    		if(!fixlen) *--ltable=ltptr;
    		ltptr+=compressedEntry.keyLen+sizeof(GiSTpage);
    	}
    	// Store extra line table entry so we know last entry's length
    	*--ltable=ltptr;
    }
    

    Für mich sieht das also so aus, als wird buf in GiST::WriteNode erstellt, dann passiert nicht mehr viel mit ihm und dann wird er dort wieder gelöscht.



  • Simpson84 schrieb:

    Meine Verteidigung zu der sehr langen Funktion ist, dass ich den Code nicht selber geschrieben habe, sondern einfach nur verwenden möchte.

    Das ist keine Entschuldigung 😉 Man sollte keinen Code verwenden, den man nicht versteht.
    Wenn man ihn aber versteht, gibts keine Entschuldigung, ihn nicht etwas übersichtlicher zu machen (d.h. in kleinere Funktionen zu zerlegen) 😉



  • Ich habe in den Sourcecode mal mehrere assert(_CrtCheckMemory()); eingefügt und dabei crashed das ganze in der Pack-Methode direkt nach

    // Copy the entry onto the page
    if(compressedEntry.keyLen>0) memcpy(page+ltptr, compressedEntry.key, compressedEntry.keyLen);
    

    Sieht jemand die Ursache dafür?



  • Ein Debugger könnte dir sicher besser weiterhelfen.



  • char *buf=new char[store->PageSize()]; 
    
        //...
    
        delete[] buf; // <-- statt delete buf;
    


  • So ein einfacher Fehler und keiner sieht ihn ^^

    Ich hab ihn auch nicht gesehen.

    gw,
    seldon



  • _))) schrieb:

    So ein einfacher Fehler und keiner sieht ihn ^^

    Ich hab ihn auch nicht gesehen.

    gw,
    seldon

    dacht ich mir auch... -.-



  • Oh ja, da lag ich wohl voll daneben. Das wusste ich gar nicht, dass so auch der Fehler kommen kann.



  • Besten Dank!
    Das war mir noch gar nicht aufgefallen. Das alleine war zwar noch nicht die Lösung, da auch noch inhaltlich im Programm was schief lief.


Anmelden zum Antworten