valgrind Invalid write of size 4
-
Hallo
Ich bin langsam echt am verzweifeln. Ich erhalte bei valgring mittels vollem leak-check immer diesen Fehler:
==6691== Command: ./HopfieldMain ==6691== A: 0 0 0 0 ==6691== Invalid read of size 4 ==6691== at 0x404CC8: Attractor::AnalysisBinary(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&) (Attractor.cpp:286) ==6691== by 0x408B7F: main (HopfieldMain.cpp:68) ==6691== Address 0x5aa5d94 is 0 bytes after a block of size 20 alloc'd ==6691== at 0x4C2C23F: operator new(unsigned long) (vg_replace_malloc.c:334) ==6691== by 0x40239D: __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) (new_allocator.h:104) ==6691== by 0x402118: std::allocator_traits<std::allocator<int> >::allocate(std::allocator<int>&, unsigned long) (alloc_traits.h:416) ==6691== by 0x401EEB: std::_Vector_base<int, std::allocator<int> >::_M_allocate(unsigned long) (stl_vector.h:170) ==6691== by 0x401C08: std::_Vector_base<int, std::allocator<int> >::_M_create_storage(unsigned long) (stl_vector.h:185) ==6691== by 0x401862: std::_Vector_base<int, std::allocator<int> >::_Vector_base(unsigned long, std::allocator<int> const&) (stl_vector.h:136) ==6691== by 0x402486: std::vector<int, std::allocator<int> >::vector(std::vector<int, std::allocator<int> > const&) (stl_vector.h:322) ==6691== by 0x402336: void std::_Construct<std::vector<int, std::allocator<int> >, std::vector<int, std::allocator<int> > const&>(std::vector<int, std::allocator<int> >*, std::vector<int, std::allocator<int> > const&) (stl_construct.h:75) ==6691== by 0x4021FE: std::vector<int, std::allocator<int> >* std::__uninitialized_fill_n<false>::__uninit_fill_n<std::vector<int, std::allocator<int> >*, unsigned long, std::vector<int, std::allocator<int> > >(std::vector<int, std::allocator<int> >*, unsigned long, std::vector<int, std::allocator<int> > const&) (stl_uninitialized.h:202) ==6691== by 0x401FEB: std::vector<int, std::allocator<int> >* std::uninitialized_fill_n<std::vector<int, std::allocator<int> >*, unsigned long, std::vector<int, std::allocator<int> > >(std::vector<int, std::allocator<int> >*, unsigned long, std::vector<int, std::allocator<int> > const&) (stl_uninitialized.h:247) ==6691== by 0x401DD5: std::vector<int, std::allocator<int> >* std::__uninitialized_fill_n_a<std::vector<int, std::allocator<int> >*, unsigned long, std::vector<int, std::allocator<int> >, std::vector<int, std::allocator<int> > >(std::vector<int, std::allocator<int> >*, unsigned long, std::vector<int, std::allocator<int> > const&, std::allocator<std::vector<int, std::allocator<int> > >&) (stl_uninitialized.h:358) ==6691== by 0x401A7F: std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >::_M_fill_initialize(unsigned long, std::vector<int, std::allocator<int> > const&) (stl_vector.h:1299) ==6691== ==6691== Invalid write of size 4 ==6691== at 0x404CCA: Attractor::AnalysisBinary(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&) (Attractor.cpp:286) ==6691== by 0x408B7F: main (HopfieldMain.cpp:68) ==6691== Address 0x5aa6aa0 is 0 bytes after a block of size 16 alloc'd ==6691== at 0x4C2C23F: operator new(unsigned long) (vg_replace_malloc.c:334) ==6691== by 0x40239D: __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) (new_allocator.h:104) ==6691== by 0x402118: std::allocator_traits<std::allocator<int> >::allocate(std::allocator<int>&, unsigned long) (alloc_traits.h:416) ==6691== by 0x401EEB: std::_Vector_base<int, std::allocator<int> >::_M_allocate(unsigned long) (stl_vector.h:170) ==6691== by 0x401C08: std::_Vector_base<int, std::allocator<int> >::_M_create_storage(unsigned long) (stl_vector.h:185) ==6691== by 0x401862: std::_Vector_base<int, std::allocator<int> >::_Vector_base(unsigned long, std::allocator<int> const&) (stl_vector.h:136) ==6691== by 0x40159D: std::vector<int, std::allocator<int> >::vector(unsigned long, std::allocator<int> const&) (stl_vector.h:280) ==6691== by 0x404AD3: Attractor::AnalysisBinary(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&) (Attractor.cpp:272) ==6691== by 0x408B7F: main (HopfieldMain.cpp:68) ==6691==Ich kann mir echt nicht erklären was da nicht passt, vor allem da mir das Progamm beim debuggen immer die richtigen Werte angezeigt werden. Der releante Code ist:
// Calculate inner products and Hamming distances < attractors | adjoint state vectors> std::vector< std::vector<int> > DotProductAttractorsAdjointCSpace(nattractor-1, std::vector<int>(Var._SampleSize)); std::vector< std::vector<int> > HammingDistanceAttractorsAdjointSpace(nattractor-1, std::vector<int>(Var._SampleSize)); std::vector<int> vectorA(Net._AdSize); std::vector<int> vectorB(Net._AdSize); std::vector<int> index(nattractor-1); for( int y = 0; y < Var._SampleSize; y++) { for(i=0; i<Net._AdSize; ++i){ vectorA[i] = Attractors[CSpace[y][0]-1 ][i]; } std::cout << "A: "; for(auto i:vectorA){std::cout << i << " ";} std::cout << std::endl; for( int x = 1; x <= nattractor; x++){ vectorB[x -1] = CSpace[y][x]; // HIER IST DER VALGRIND FEHLER (Attractor.cpp:286) } std::cout << "B: "; for(auto i:vectorB){std::cout << i << " ";} std::cout << std::endl; HammingDistanceAttractorsAdjointSpace[ CSpace[y][0] -1][index[ CSpace[y][0] -1] ] = Routine::HammingDistance(vectorA, vectorB); // Calculate Hamming distance DotProductAttractorsAdjointCSpace[ CSpace[y][0] -1][index[ CSpace[y][0] -1] ] = inner_product(vectorA.begin(), vectorA.end(), vectorB.begin(), 0); // Calculate inner product index[CSpace[y][0]-1] += 1; }Net._AdSize lasse ich über einen Konstruktor zu 4 zuweisen, Var._SampleSize wird zu 16 deklariert.
Die Matrix CSpace wird wie folgt von mir bestimmt.
// Initialize configuration space std::vector< std::vector<int> > CSpace(Var._SampleSize, std::vector<int>(Net._AdSize +1)); int ipattern; for(i=0; i<Var._SampleSize; i++) { for(j=0; j<Net._AdSize+1; j++) { CSpace[i][j] = 0; } } // Set configuration space for(ipattern=0; ipattern<Var._SampleSize; ++ipattern) { j=ipattern; k=0; for (i=1; i<Net._AdSize; i++) {CSpace[ipattern][i+1]=0;} while(j>0) // Set Pattern from ipattern { CSpace[ipattern][k+1]=j%2; j=(j-j%2)/2; k=k+1; } } // Append attractor counter to the configuration space. First Column correspond to the attractor std::vector<int> AttrCount(Var._SampleSize); for(i=0; i<Var._SampleSize; i++){AttrCount[i]=basins[i];} for(i=0; i<Var._SampleSize; ++i) { int AttrIndex = AttrCount[i]; CSpace[i][0]=AttrIndex; }Und die Matrix Attractors wird als Ergebnis dieser Berechnung bestimmt:
// Analysis for the attractor landscape in binary encoding std::vector<std::vector<int> > Attractor::AnalysisBinary(std::vector< std::vector<int> > & Matrix){ std::ofstream print("./Output.txt",std::ios_base::app); std::ofstream print2Rbin_SizeOfBasins("./SizeOfBasinsBin.txt",std::ios_base::out); std::ofstream print2Rbin_DotProductAttractorsAdjointCSpace("./DotProductAttractorsAdjointCSpaceBin.txt",std::ios_base::out); std::ofstream print2Rbin_HammingDistanceAttractorsAdjointSpace("./HammingDistanceAttractorsAdjointSpaceBin.txt",std::ios_base::out); // Declare attractor analysis Network Net; Network Var; TransferFunction Theta; std::vector<int> basins(Var._SampleSize); std::vector< std::vector<int> > attractor(100, std::vector<int>(52)); std::vector<int> neurons(Net._AdSize); std::vector<int> helpneurons(Net._AdSize); int ncounter; int nattractor; int ntest; int ih1, ih2, ih3, i_att; int nNumber; int i, j, k; // Initialize attractor counter for(i=0; i<Var._SampleSize; ++i){basins[i]=0;} for(i=0; i<100; ++i){ for(j=0; j<52; ++j){ attractor[i][j]=0; } } neurons = {0}; ncounter=0; nattractor=1; basins[0]=1; // Investigate attractors while(ncounter<Var._SampleSize){ helpneurons = {0}; helpneurons = Update::Hebb(Matrix, neurons); // Update neurons = TransferFunction::StepFunctionBin(helpneurons); //Activation function nNumber=0; nNumber=ActivityToNumber(neurons); // Neural activity to number if(basins[nNumber]==0){basins[nNumber]=nattractor;} else{if(basins[nNumber]==nattractor) { if(nattractor>100){ print << "Warning: attractor > 100"; exit(EXIT_FAILURE);} ++nattractor; while ( ( ncounter < Var._SampleSize ) && ( basins[ncounter] > 0 ) ) {++ncounter;} if ( ncounter == Var._SampleSize ) {break;} basins[ncounter]=nattractor; neurons=NumberToActivity(ncounter); // Number to neural activity } else{ for(i=0; i<Var._SampleSize; ++i){ if(basins[i]==nattractor){ basins[i]=basins[nNumber];}} while ( ( ncounter < Var._SampleSize ) && ( basins[ncounter] > 0 ) ) {++ncounter;} if ( ncounter == Var._SampleSize ) {break;} basins[ncounter]=nattractor; neurons=NumberToActivity(ncounter); } } } for(i=0; i<Var._SampleSize; ++i){attractor[basins[i]][50]=attractor[basins[i]][50]+1;} for(i_att=1;i_att<nattractor;++i_att){ ih1=0; while(basins[ih1]!=i_att){ih1++;} neurons=NumberToActivity(ih1); //Update neural activity 70 times for(k=0; k<70; ++k){ helpneurons = {0}; helpneurons = Update::Hebb(Matrix, neurons); // Update neurons = TransferFunction::StepFunctionBin(helpneurons); // Activation function } nNumber=0; nNumber=ActivityToNumber(neurons); // Neural activity to number ntest=0; ih2=1; ih3=nNumber; while(nNumber!=ih2){ ntest++; attractor[i_att][ntest]=ih3; helpneurons = {0}; helpneurons = Update::Hebb(Matrix, neurons); // Update neurons = TransferFunction::StepFunctionBin(helpneurons); // Activation function ih3=0; ih3=ActivityToNumber(neurons); // Neural activity to number ih2=ih3; } attractor[i_att][51]=ntest; if(ntest>50){ print << "Warning: size of attractor > 50"; exit(EXIT_FAILURE);} } // Print first results of the attractor analysis print << "\nResults of the attractor analysis:" << "\n"; print << "\nNumber of basins: " << (nattractor-1) << "\n"; for(i=1;i<nattractor;++i){ print << "\nAttractor: " << i; print << "\nSize of the basin: " << attractor[i][50]; print << "\nNumber of states: " << attractor[i][51] << "\n"; for(j=1;j<(attractor[i][51]+1);++j){ //print << "Binary exponentiation: " << attractor[i][j]; print << "\nNeural Activity: "; ih1=attractor[i][j]; neurons=NumberToActivity(ih1); // Number to neural activity for(k=0; k<Net._AdSize; ++k) { print << neurons[k] << " "; } print << "\n"; } } // Print the size of the basins print2Rbin_SizeOfBasins << "#Size of the basins" << "\n"; for(i=1; i<nattractor; ++i){print2Rbin_SizeOfBasins << attractor[i][50] << "\n";} // Store attractors in a matrix std::vector< std::vector<int> > Attractors(nattractor-1, std::vector<int>(Net._AdSize)); for(i=1;i<nattractor;++i) { for(j=1;j<(attractor[i][51]+1);++j) { ih1=attractor[i][j]; for(k=0; k<Net._AdSize; ++k){Attractors[i-1][k]=ih1%2; ih1=(ih1-Attractors[i-1][k])/2;} } }Ich bin für Hilfe extrem dankbar. Falls fragen zum Code sind oder Unklarheiten beantworte ich das gerne.
Grüße
-
Du indexierst wohl irgendwo außerhalb der Grenze.
Ich habe jetzt ehrlich gesagt keine Lust deinen Code durchzuforsten, aber wenn du den Debugger (GDB) in der IDE anschmeißt, und es kracht, müsste er dir die genaue Stelle zeigen, wo das sein soll.
-
Hi
der gdb liefert gar keine Fehlermeldung. Der rennt durch ohne Warnung. Nur valgrind erkennt das. Die Variablen für die Indizes habe ich mir alle ausgeben lassen. Die stimmen auch alle. Die Ergebnisse des Programms stimmen ebenfalls. Habe ich von Hand alles nachgerecnet.
Deswegen verstehe ich ja nicht was das Problem ist

-
Dann ersetzt du an der relevanten Stelle mal alle [] durch at().
-
Den Code gab es doch schon mal.
Ich hatte gehofft, dass sich seitdem wenigstens die Formatierung verbessert hätte, so will das niemand lesen.
valgrind beschwert sich über den Zugriff auf vectorB, offenbar ist dieser zu klein (oder die Schleifenbedingung fehlerhaft).
-
manni66 schrieb:
Dann ersetzt du an der relevanten Stelle mal alle [] durch at().
Hi
Die Methode at() zum debuggen zu nutzen ist super. Vielen Dank für diesen Hinweis. Ich nehme das in mein Standard Repotoire auf.
Ich konnte den Fehler nun durch viel try an error in Kombination mit debugging lösen. Ein Fehler dieser Art ist mir nun zum ersten mal passiert. Sehr, sehr lehrreich und zwar:
In der Rechnung wo ich mir die Arbeit genommen habe und sämtliche Konfigurationen des neuronalen Netzes von Hand berechnet habe (17 doppelseitig beschriebene Blätter), ist durch purer Zufall die Anzahl der Attraktoren gleich der Anzahl der Neuronen gewesen. Für alle diese Situationen lief mein Programm korrekt und fehlerfrei. Für jeden Parametersatz bei dem das Netz aber mehr oder weniger Attraktoren erhält als die Anzahl der Neuronen, kommt dann von valgrind zurecht gemeckert die Felermeldung.
Die for Anweisung darf nicht über die Variable nattractor gehen sondern über Net._AdSize+1, die Neuronenanzahl plus 1 wegen dem Attraktorindex.
Danke für die Hilfe, das hat mir sehr geholfen.

Grüßep.s.
@camper
Ich kann meinen Code gut lesen und achte auch auf Einschübe wie man sieht. Was findest du schlecht an meiner Formatierung bzw. würdest besser machen?
-
cpp_Jungspund schrieb:
achte auch auf Einschübe wie man sieht.
Sehe ich nicht, und jedenfalls ist es nicht konsequent. Ich bin mir auch nicht sicher, ob du dir klar gemacht hast, wofür sie eigentlich gut sind.
Nehmen wir z.B. den Ausschnitt:else{ for(i=0; i<Var._SampleSize; ++i){ if(basins[i]==nattractor){ basins[i]=basins[nNumber];}} while ( ( ncounter < Var._SampleSize ) && ( basins[ncounter] > 0 ) ) {++ncounter;} if ( ncounter == Var._SampleSize ) {break;} basins[ncounter]=nattractor; neurons=NumberToActivity(ncounter); } } }Formatierung dient dazu, einen visuellen Hinweis zur Struktur eines Programmes zu liefern. Das kann sie nur, wenn sie konsequent durchgeführt wird.
Wozu sind Einschübe gut? Doch wohl um klar zu machen, in wieweit der Programmablauf von der einfachen sequentiellen Ausführung abweicht. Ein eingerücktes Element hängt immer von einem steuernden Element ab, sei es bedingte (if/case) oder wiederholte (for/do/while) Ausführung. Umgekehrt erwarte ich bei Auftreten eines solchen Sprachelementes immer eine Einrückung. Hier ist alles nach dem else gleichartig eingerückt, aber die schliessenden Klammern am Ende sind nicht entsprechend ausgerichtet. Auch muss man schon genau hinschauen (ans Ende einer Zeile!) um herauszufinden, wo das for-Statement denn nun eigentlich aufhört.
Alles in eine Zeile zu schreiben, ist für gewöhnlich nicht empfehlenswert (es kann in bestimmten Ausnahmefällen berechtigt sein, etwa wenn struktuell einfacher und ähnlicher Code mehrfach auftritt), zudem erschwert es das Debuggen.
Es sollte eher ungefähr so ausssehen:else{ for(i=0; i<Var._SampleSize; ++i){ if(basins[i]==nattractor){ basins[i]=basins[nNumber]; } } while ( ( ncounter < Var._SampleSize ) && ( basins[ncounter] > 0 ) ) { ++ncounter; } if ( ncounter == Var._SampleSize ) { break; } basins[ncounter]=nattractor; neurons=NumberToActivity(ncounter); } } }(nur Einrückung korrigiert).
Eine Menge anderer Dinge wären zu bemängeln (kein Anspruch auf Vollständigkeit oder Signifikanz der Reighenfolge):
- magische Zahlen
- wiederholte Zuweisungen zur gleichen Variablen
- Namen ohne Aussagekraft (ih3?) in Verbindung mit zu goßen Gültigkeitsbereichen und Wiederverwendung von Variablen für verschiedene Zwecke
-
cpp_Jungspund schrieb:
@camper
Ich kann meinen Code gut lesen und achte auch auf Einschübe wie man sieht. Was findest du schlecht an meiner Formatierung bzw. würdest besser machen?Beherzige das was camper geschrieben hat.
Dass du deinen Code "super" lesen kannst mag ja sein.
Aber bedenke zwei Dinge:-
Vielleicht könntest du deinen Code (nach einer kleinen Eingewöhnungsphase) noch viel superiger lesen wenn du ihn anders einrücken würdest.
-
Sobald du mit anderen zusammenarbeiten musst, ist es ziemlich Wurst was du höchstpersönlich super lesen kannst, wenn andere es nicht lesen können oder Akne davon bekommen. Natürlich gibt es verschiedenste Stile, aber einige Dinge haben sich dabei als quasi-Standard herauskristallisiert. Und zwar.
- Flow-Control heisst Zeilenumbruch
Also
if (dings) dongs(); // schlecht if (dings) dongs(); // noch nicht wirklich besser- Verschachtelte Blöcke werden mehr eingerückt als der umgebende Code
Alsoif (dings) dongs(); // schlecht if (dings) dongs(); // VIEL besserUswusf.
Die anderen Dinge die camper anspricht sind ähnlich zu sehen. Sind im Prinzip auch Stilfragen, nur halt eine Ebene höher sozusagen. Also z.B. dass man nicht Variablen für was anderes wiederverwendet. Code der das macht ist einfach viel viel schwerer zu lesen als Code der das nicht macht. Und ganz besonders, wenn man anfängt vernünftige & verständliche Variablennamen zu vergeben. Was bei "wiederverwendeten" Variablen einfach nicht möglich ist. Falls du es nicht glaubst, kram einfach mal einen 1-2 Jahre alten Code von dir raus, und versuche den jetzt zu lesen. Oder, alternativ: Glaub es uns einfach

-