Moi.
Olen nyt toista viikkoa taas paininut erään ongelman kanssa ja en millään saa kyseistä virhettä selville. Asensin kubuntunkin, jotta pääsen valgrindillä etsimään mahdollista virheen aiheuttajaa mutta turhaan. Joko en ymmärrä mitä se sanoo tai ymmärrän mutta valgrind ei löydä ongelmaa. Siispä nyt ajattelin kysyä täällä jospa joku löytäisi virheen tai jonkin suunnitteluvirheen tai muun koodista joka aiheuttais virheen.
Eli siis syvemmälle ongelmaan: Teinpäs tuollaisen systeemin, joka lataa 3D-mallin ja sille skeletonin. Ymmärtääkseni kaikki sujuu latauksissa hyvin, mutta kun alan kiertämään ja laskemaan skeletonia yhtäkkiä luiden Rot-muuttuja muuttuu, vaikkei siihen missään kirjoteta mitään, luetaan vain ja kierretään luuta tai ulottuvuutta niiden mukaan.
Valgrind sanoo, että "Conditional jump or move depends on uninitialised value(s)", mutta ymmärtääkseni kyseinen bone :: Rot-muuttuja alustetaan kun luu eli bone luodaan, sillä Rot on vec3-luokan muuttuja joka aina luodessa alustetaan nolliksi. Tuokin virhe hävisi kun mat4:: RotX funktiota muutin ottamaan vastaan const float angle-arvon float anglen sijasta...
Eli vielä: ennen kun kutsun luulle Rotate()-funktiota luiden Rot on 0.0 0.0 0.0, mutta kun Rotate()-funktio on kutsuttu lapsien Rot muuttuu 1.0 0.0 0.0ksi. Jostakin joku kirjoittaa jotain väärään muistipaikkaan mutta en löydä mistään sitä mikä sen tekee?
Koodia:
main.cpp
#include <iostream> #include <cstdio> #include <stdlib.h> #include <string.h> #include <math.h> #include <ctime> #include <GL/gl.h> using namespace std; #include "esittelyt.hpp" #include "vektorit.hpp" #include "tietueet.hpp" int main(void) { bone *root=0; model malli; mat4 dim; vec3 Rot; bone *u=0; root = new bone; if( root->LoadSkeleton("skeleton.m3d") == 0 ) { delete root; return 1; } else printf("Ladattiin skeleton.\n"); if( malli.LoadMesh("skeleton.m3d") == 0 ) { delete root; return 1; } else printf("Ladattiin malli.\n"); if( malli.AttachBonesToVertexes("skeleton.m3d", root) == 0) { delete root; return 1; } else printf("Yhdistettiin luuranko malliin.\n"); u = boneFindByID(root, 1); if(u) Rot = u->GiveRotation(); printf("Rotation: %f %f %f\n", Rot.x, Rot.y, Rot.z); root->Rotate(); printf("Kierrettiin luurankoa!\n"); // mahdolliset sekoilun aiheuttajat: // Rotate(); // GiveDimension(); // Rotate(mat4 a); // GiveDimension2(); // mat4:n kertolasku // GiveDimension():ssa // matriisien kiertomuodostajat mat4 :: Rot.x Rot.y Rot.z // LoadSkeleton-funktio // AddChild-funktio // bonen kopiointifunkkari // SetName() // SetID() // SetDimension() //malli.CalcVertexes(true); //printf("Laskettiin verteksien paikat."); if(root) delete root; return 0; }
tietueet.hpp (karsittu epäolennaisuuksia pois)
bone :: bone() { ID = 0; Children = 0; Child = 0; Scale = vec3(1.0, 1.0, 1.0); name = ""; } bone :: bone(unsigned int a, mat4 b) { ID = a; dimension = b; Children = 0; Child = 0; Scale = vec3(1.0, 1.0, 1.0); name = ""; } bone :: ~bone() { Free(); // tyhjennä } void bone :: Free() { unsigned int i; for(i=0; i<Children; i++) { // ensin käydään kaikki lapset läpi ja tyhjennetään niiden muistit Child[i].Free(); } // lopuksi tyhjennetään omat ID = 0; if(Child != 0) { delete [] Child; Child=0; } //if(name != 0) { delete [] name; name = 0; } Children = 0; name = ""; } bool bone :: AddChild(unsigned int bID, const char* bName, mat4 bDim ) { // lisää luulle lapsen // ehkä jonkilainen lista tai vektori systeemi olis kätevämpi? bone *temp=0; unsigned int i; if(Children > 0) // jos oli lapsia { temp = new bone[Children]; // tehdään taulukko jonne mahtuu kaikki lapset if(temp == 0) { fprintf(stderr, "Muistin varaaminen epäonnistui!\n"); return false; } for(i=0; i<Children; i++) // käydään lapset yksitellen läpi ja kopioidaan ne { if(!(temp[i] = Child[i])) { fprintf(stderr, "Virhe luiden kopioinnissa!\n"); if(temp != 0) { delete [] temp; temp = 0; } // jos temp luotiin return false; } } } if(Child != 0) { delete [] Child; Child=0; } // poistetaan edellinen taulukko Child = new bone[Children+1]; // luodaan uus taulukko johon mahtuu myös uus lapsi if(Child == 0) { fprintf(stderr, "Muistin varaaminen epäonnistui!\n"); if(temp != 0) { delete [] temp; temp = 0; } // jos temp luotiin return false; } for(i=0; i<Children; i++) // käydään lapset yksitellen läpi ja kopioidaan ne { if( !(Child[i] = temp[i]) ) { fprintf(stderr, "Virhe luiden kopioinnissa!\n"); if(temp != 0) { delete [] temp; temp = 0; } // jos temp luotiin return false; } } if(temp != 0) { delete [] temp; temp = 0; } // jos temp luotiin Child[Children].SetID( bID ); Child[Children].SetName( bName ); Child[Children].SetDimension( bDim ); Children++; // kasvatetaan lapsien määrää return true; // onnistunut suoritus } void bone :: SetDimension( mat4 a ) // aseta alkup. ulottuvuus { dimension = a; } void bone :: SetID( unsigned int a ) // aseta ID, tunniste { ID = a; } void bone :: SetName( const char *nimi ) // aseta luun nimi { name = nimi; } unsigned int bone :: GiveID() // anna ID { return ID; } const char* bone :: GiveName() // anna nimi { return name.c_str(); } mat4 bone :: CalcDimension() // laskee tämän hetkisen absoluuttisen ulottuvuuden { // globaalien akseleiden mukaan mat4 a, b; // nyt x z y a.RotX(Rot.x); b*=a; // muutetaan myöhemmin qvaternioilla laskemiseksi a.RotZ(Rot.z); b*=a; a.RotY(Rot.y); b*=a; b.arvo[0] *= Scale.x; b.arvo[1] *= Scale.x; b.arvo[2] *= Scale.x; b.arvo[4] *= Scale.y; b.arvo[5] *= Scale.y; b.arvo[6] *= Scale.y; b.arvo[8] *= Scale.z; b.arvo[9] *= Scale.z; b.arvo[10] *= Scale.z; b.arvo[12] = Pos.x; b.arvo[13] = Pos.y; b.arvo[14] = Pos.z; return dimension*b; // elikkä alkup.dimensio*b on uusi ulottuvuus dimension*b } mat4 bone :: GiveDimension() // palauttaa tämän hetkisen absoluuttisen ulottuvuuden { return dimension_new; } mat4 bone :: getDimension() { return dimension; } vec3 bone :: GiveRotation() { return Rot; } bone* bone :: FindByID(unsigned int f_ID) { unsigned int i; bone* u=0; for(i=0; i<Children; i++) { if(Child[i].GiveID() == f_ID) return &Child[i]; u = Child[i].FindByID(f_ID); if(u != 0) return u; } return 0; } bone* bone :: FindByName( const char* nimi ) { unsigned int i; bone* u=0; for(i=0; i<Children; i++) { if( strcmp( Child[i].GiveName() ,nimi) == 0 ) return &Child[i]; u = Child[i].FindByName( nimi ); if(u != 0) return u; } return 0; } void bone :: Rotate() { // tämä laskee dimension_new:iin uuden ulottuvuuden // ja kiertää sitten sen mukaan lapsia unsigned int i; //if(ID != 0) dimension2 = dimension; // locaalit dimension_new = CalcDimension(); // globaalien pyörimisakseleiden mukaan laskettu ulottuvuus for(i=0; i<Children; i++) { //if( ID == 0) Child[i].Rotate( dimension ); // locaalit //else Child[i].Rotate( dimension2 ); // locaalit Child[i].Rotate( dimension_new ); // kierrä sen mukaan lapsia (globaalit kiertoakselit) } } void bone :: Rotate( mat4 a ) { // annetulla matriisilla kierretään ja translatoidaan ja skaalataan tätä bonea unsigned int i; mat4 b, c; //if(ID != 0) dimension2 = a*dimension; // locaalit b = CalcDimension(); c = a * b; // matriisien kertolasku sekoilee täh?!? dimension_new = c; // eli mun ulottuvuus on parentin ulottuvuus * oma relatiivinen ulottuvuus... // ...(jossa skaalaus rotaatio ja translaatio) parenttiin for(i=0; i<Children; i++) { // lapsia sen jälkeen kierretään taas oman ulottuvuuden mukaan //if(ID == 0) Child[i].Rotate( dimension ); // locaalit //else Child[i].Rotate( dimension2 ); // locaalit Child[i].Rotate( dimension_new ); // globaalit } } int bone :: LoadSkeleton(const char *fileName) // lataa tiedostosta skeletonin { FILE *tiedosto=0; unsigned int i=0; unsigned int f_ID = 0; unsigned int f_childof=0; char buffer[512]; string nimi; char joku[512]; float f[16]; vec4 a, b, c, d; //bone temp; tiedosto = fopen(fileName, "r"); if(tiedosto == NULL) { //fclose(tiedosto); // ei kai sitä tarvitse sulkea jos se ei edes auennu? fprintf(stderr, "Tiedoston avaaminen ei onnistu: %s\n", fileName); return 0; } while(!feof(tiedosto)) { strcpy(buffer, ""); fgets(buffer, 512, tiedosto); if( sscanf(buffer, "b %u %u %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %s\n", &f_ID, &f_childof, &f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9], &f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &joku) == 19 ) { a = vec4(f[0], f[1], f[2], f[3]); // pystyvektoreita! b = vec4(f[4], f[5], f[6], f[7]); c = vec4(f[8], f[9], f[10], f[11]); d = vec4(f[12], f[13], f[14], f[15]); nimi = joku; if(ID == 0 && f_ID == ID) { dimension = mat4(a, b, c, d); // ulottuvuus rootille SetName( nimi.c_str() ); } else if(f_childof == ID) { //temp.SetDimension( mat4(a, b, c, d) ); //temp.SetID( f_ID ); //temp.SetName( nimi.c_str() ); //if(!AddChild( temp ) ) return 0; if( !AddChild( f_ID, nimi.c_str(), mat4(a, b, c, d) ) ) return 0; } } } fclose(tiedosto); for(i=0; i<Children; i++) { if( Child[i].LoadSkeleton(fileName) == 0) { fprintf(stderr, "Luurangon lataaminen epäonnistui! Tiedosto: %s\n", fileName); return 0; } } return 1; // onnistunut } bool bone :: operator = (bone a) // kopioidaan pari muuttujaa luusta toiseen { ID = a.GiveID(); // kopioi ID Children = 0; // lapsia ei kopioida koska niitä ei tätä funktiota kutsuessa vielä ole! if(Child != 0) { delete [] Child; Child = 0; } // varmistetaan dimension = a.getDimension(); // ulottuvuudet kopataan //dimension_new = a.GiveDimension2(); // ei välttistä tartte koska tätä kopiointia käytetään vaan kun malli ladataan! name = a.GiveName(); return true; } void bone :: TellMe() // kertoo luusta ja sen lapsista eri asioita { unsigned int i; mat4 temp_mat; //fprintf(stdout, "ID: %i Name: %s Children: %i\n", ID, name, Children); fprintf(stdout, "ID: %i Name: %s Children: %i\n", ID, name.c_str(), Children); //printf("Rot: %f %f %f\n", Rot.x, Rot.y, Rot.z); for(i=0; i<Children; i++) { Child[i].TellMe(); } } bone* boneFindByID(bone *luu, unsigned int ID) // palauttaa osoittimeen haluttuun luuhun { bone* u; if(!luu) return NULL; // tarkistetaan että luu on olemassa if(luu->GiveID() == ID) return luu; else { u = luu->FindByID( ID ); if(!u) return NULL; else return u; } } bone* boneFindByName(bone *luu, const char *name) // palauttaa osoittimeen haluttuun luuhun { bone* u; if(!luu) return NULL; if( strcmp(luu->GiveName() ,name) == 0 ) return luu; else { u = luu->FindByName( name ); if(!u) return NULL; else return u; } }
vektorit.hpp tiedostossa ainoa joka voi sekottaa on matriisien kiertomuodostajat
laitetaan nyt vielä vähä muutaki
vec3 :: vec3() // vektoriluokan muodostaja { x=0.0; // kyllä! nämä on alustettu! y=0.0; z=0.0; } void mat4 :: RotX(const float angle) { arvo[0]=1.0; arvo[4]=0.0; arvo[8]=0.0; arvo[12]=0.0; arvo[1]=0.0; arvo[5]=cos(angle); arvo[9]=sin(angle); arvo[13]=0.0; arvo[2]=0.0; arvo[6]=-sin(angle); arvo[10]=cos(angle); arvo[14]=0.0; arvo[3]=0.0; arvo[7]=0.0; arvo[11]=0.0; arvo[15]=1.0; } void mat4 :: RotY(const float angle) { arvo[0]=cos(angle); arvo[4]=0.0; arvo[8]=-sin(angle); arvo[12]=0.0; arvo[1]=0.0; arvo[5]=1.0; arvo[9]=0.0; arvo[13]=0.0; arvo[2]=sin(angle); arvo[6]=0; arvo[10]=cos(angle); arvo[14]=0.0; arvo[3]=0.0; arvo[7]=0.0; arvo[11]=0.0; arvo[15]=1.0; } void mat4 :: RotZ(const float angle) { arvo[0]=cos(angle); arvo[4]=-sin(angle); arvo[8]=0.0; arvo[12]=0.0; arvo[1]=sin(angle); arvo[5]=cos(angle); arvo[9]=0.0; arvo[13]=0.0; arvo[2]=0.0; arvo[6]=0; arvo[10]=1.0; arvo[14]=0.0; arvo[3]=0.0; arvo[7]=0.0; arvo[11]=0.0; arvo[15]=1.0; }
esittelyt.hpp
class vec3 { public: float x, y, z; vec3(); ~vec3(); // ... muutaki löytyy }; class mat4 { public: float arvo[16]; // 0 4 8 12 // 1 5 9 13 // 2 6 10 14 // 3 7 11 15 void RotX(float angle); // Tekee matriisista X-akselin suhteen vektoria pyörittävän kulman angle verran void RotY(float angle); // Sama Y-akselille void RotZ(float angle); // Sama Z-akselille }; class bone { private: unsigned int ID; // tunnistenumero unsigned int Children; // lasten määrä bone *Child; // lapsi-osoitin mat4 dimension; // luun ulottuvuus alussa, "relatiivinen" parenttiin mat4 dimension_new; // luun ulottuvuus NYT, "absoluuttinen" vec3 Rot; // rotaatio, globaalien akseleiden ympäri! vec3 Pos; // positio, relatiivinen edelliseen boneen vec3 Scale; // skaalaus string name; // bonen nimi (tällä kertaa string!) :D jospa se toimisi public: bone(); bone(unsigned int a, mat4 b); // id ja dimension ~bone(); bool AddChild(unsigned int bID, const char* bName, mat4 bDim); // lisätään lapsi void Free(); // tyhjennä lapset ja itsesi void SetDimension( mat4 a ); // aseta dimension void SetID( unsigned int a ); // aseta ID void SetName( const char *nimi ); // aseta nimi unsigned int GiveID(); // anna ID const char* GiveName(); // anna osoitin nimeen mat4 CalcDimension(); // anna ulottuvuus kierrettynä, skaalattuna ja translatoituna (relatiivinen parenttiin) mat4 GiveDimension(); // anna ulottuvuus NYT (absoluuttinen) mat4 getDimension(); // anna ihan alkuperäinen ulottuvuus vec3 GiveRotation(); // anna kierto (Rot) bone* FindByID(unsigned int f_ID); // palauta osoitin ID:n mukaan etsittyyn luuhun bone* FindByName( const char *name ); // sama mut etsi nimen mukaan void Rotate(); // laske lapsille uudet ulottuvuudet void Rotate( mat4 a ); // laske ulottuvuus kiertäen a:n verran int LoadSkeleton(const char *fileName); // lataa luuranko bool operator = (bone a); // kopiointi void TellMe(); // kerro asioita };
Tämmöstä säätöä:D
Ohjelman käänsin näin:
g++ /home/tuomas/Ohjelmointi/bonetesti/main.cpp -o /home/tuomas/Ohjelmointi/bonetesti/ohjelma.o -g
Ja valgrindiä käytin näin:
valgrind --leak-check=yes --tool=memcheck --track-origins=yes /home/tuomas/Ohjelmointi/bonetesti/ohjelma.o
Jos jotain kiinnostaa katsoa ihan koko koodia nii seki onnistuu.
Koko koodi olisi kyllä kätevä, jos saat vaikka zippinä jonnekin. Mukaan vielä jokin esimerkkimalli tai mitä ohjelma ikinä tarvitseekin.
Suosittelen jo etukäteen muistin varaamista standardikirjaston vector-luokalla, niin tulee vähemmän virheitä. Jos joskus herää epäilys, että tuossa olisi pullonkaula, voit helposti vaihtaa jälkikäteen tilalle oman luokan, jossa on samanlainen rajapinta mutta joka käyttää suoraan new-operaattoria. Käytännössä nopeuseroa tuskin kuitenkaan on.
Tämä tuskin ratkaisee varsinaista ongelmaasi, mutta ainakin yksi epäilyttävän näköinen kohta on funktio bone::CalcDimension, jossa matriisia b ei alusteta mitenkään ennen kuin sitä aletaan kertoa a:lla.
Mutta tosiaan kuten Metabolix sanoi, koko koodi kääntämiskelpoisessa muodossa helpottaisi virheen hakua.
Oletko kokeillut jollakin toisella koneella. Joskus on koneissa jokin muistipaikka jossain toisessa käytössä. Epäilykseni:
1. muistipaikka alustetaan ja sille annetaan arvo(kaikki hyvin)
2. joku ohjelma muuttaa muistipaikkaa(ongelma)
3. muistipaikka luetaan ja arvot ovat ihan outoja(seuraus)
Jokotai kirjoitti:
Oletko kokeillut jollakin toisella koneella. Joskus on koneissa jokin muistipaikka jossain toisessa käytössä.
Öh, miksi kannattaisi kokeilla toisella koneella, jos kerran ongelma esiintyy nykyiselläkin koneella? Se, että ohjelma sattumalta toimisi jossain toisessa koneessa, ei poistaisi bugia.
Missään nykyaikaisessa käyttöjärjestelmässä ei toiset ohjelmat muuttele sinun ohjelman muistipaikkoja.
Pitänee tutustua näihin nykyaikaisiin käyttöjärjestelmiin :)
Juu, kannattaa ihmeessä. Niitähän on mm Mac OS X, Linuxit, BSD:t, 98:a uudemmat WIndowsit (2000, XP, Vista, 7), OS/2, jne jne
Sisuaskille: b-matriisi kyllä alustetaan. Se on oma luokkansa joka alustetaan aina kun se luodaan.
Mutta nyt on kaikki koodi saatavilla täältä: http://joose.servehttp.com/Bonetesti/bonetesti.
Mukana on myös skeleton.m3d-tiedosto, jota tarvitaan, että koko ohjelma edes toimii. (jos siis kääntämään haluaa ruveta) Tiedostomuoto on vähän oma muunnelma .obj-tiedostomuodosta, jotta sinne saadaan skeleton mukaan...
Jos toi on oikeaoppinen tapa koodata C++:aa, niin luojan kiitos en sillä paljon koodaile.
Tai oon ainakin kuvitellut että hpp:t olisi header-tiedostoja joihin ei kuulu laittaa koodia.
Ongelman aiheuttaja taitaa olla tässä:
void mat4 :: operator=(mat4 a) { unsigned int i; for (i=0; i<19; i++) { arvo[i]=a.arvo[i]; } }
Miten suuri taulukko arvo onkaan ja miten pitkälle sinne yritetään kirjoittaa?
:D Eipä oo kukaan mulle opettanu sitä oikeaa tapaa:D Oon oppinu asioita nii miten oon oppinu, mut nyt ku ajattelen asiaa nii ehkä joku cpp-tiedosto vois olla fiksumpi missä suurin osa koodista olis..? Pitääpä ajan kuluks selvitellä et miten koodit mitäs levitellä eri tiedostoihin. Mut eipä se silti varmaan tota virhettä silti poistais mikä ohjelmassa sekoilee.
Ei saa olla mahollista! Tässä käy aina näin. Joku tommone iha pikkuviba mitä ei hoksaa ku kattelee ihan muualle ja etsii virhettä toisaalta.. Ei nää metsää puilta. Joo kyllä nyt taas hävettää, heh:D Miten muuten tuli vaa mielee, et pitäskö jonku tommosen valgrindin tuo hoksata että mennään taulukosta yli vai? Ku ei se ainakaan mun käytöllä tuota hoksannu..
Kiitokset kyllä sulle Sisuaski! :)
Kato sisuaski oli nopeempi, olin just postaamassa samaa.
Mä vähän luulen, että valgrindinkin on vaikee huomata tuollaista, kun noi taulukot on vaan muistiosoitteita ja kuitenkin kaksi peräkkäistä muuttujaa on ihan yhtä lailla sun oman ohjelman muuttujia joita se saisi käpistellä ihan mielensä mukaan. Luulisin, että jos varaisit noi muistit dynaamisesti niin se varmaan jopa huomaisikin.
Vielä varmemmaksi vakuudeksi tuossahan on kyse heti ensimmäisestä esimerkistä kappaleesta "What won't Valgrind find" tuolta sivulta: http://www.cprogramming.com/debugging/valgrind.
"Valgrind doesn't perform bounds checking on static arrays (allocated on the stack)."
Helpostihan tuon huomaa kun debuggerissa ajaa rivi kerrallaan koodia ja katsoo missä kohti virhe tapahtuu.
Ratkaisu ongelmaan olisi ollut debuggerin watch-toiminto, jolla saa ohjelman pysähtymään, kun tiettyyn muistiosoitteeseen kirjoitetaan.
verho88 kirjoitti:
Pitääpä ajan kuluks selvitellä et miten koodit mitäs levitellä eri tiedostoihin.
Asian taustoista kerrotaan tässä oppaassa, lue kokonaan. Oppaassa on myös pari linkkiä koodivinkkeihin, joissa asiaa käsitellään käytännössä.
Grez kirjoitti:
Missään nykyaikaisessa käyttöjärjestelmässä ei toiset ohjelmat muuttele sinun ohjelman muistipaikkoja.
[offtopic]Olet oikeassa, eivät normaalitilanteessa :). Kuitenkin on olemassa ja on melko vaivatonta myös tehdä ohjelmia, jotka tarkoituksenomaisesti tutkivat ja muokkaavat muiden ohjelmien muisteja. Melko hyvä käytännön esimerkki on ohjelma Process Hacker. Anteeksi saivarteluni, koin tarpeelliseksi oikaista asian.[/offtopic]
En kyllä näe mitään tarvetta oikaisuun kun missään realistisessa tilanteessa mikään ohjelma ei muuttele juuri ohjelmoimasi, kääntämäsi ja käynnistämäsi ohjelman muistipaikkoja - joka on siis tilanne johon kommentoin.
Oikeastaan ainoa teoreettinen tilanne joka tulisi mieleen olisi, että joku olisi tehnyt koodareiden kiusaksi ohjelman, joka piinaa nimenomaan huomaamiaan uusia ohjelmatiedostoja. Yksi realistinen mahdollisus olisi buginen laiteajuri, mutta siinä tapauksessa luultavasti koko kone olisi melko epävakaa.
Toisen ohjelman muistialueelle kirjoittaminen vaatii kuitenkin (nykykäyttiksissä) sen verran vaivaa, että ihan vaan huonosti koodattu normisofta ei vahingossa sitä tee. Näinhän usein tapahtui vanhoissa moniajokäyttiksissä, jossa ohjelmien muistialueita ei voinut suojata. Eli täysin bugiton softa saattoi kaatua tai sekoilla, kun jokin buginen softa kirjoitti vahingossa sen muistialueelle.
Sitten hakkerointi ja esim. huijausohjelmat yleensä tarvitsee itse käynnistää ja käskeä tekemään jotain. Jopa troijalaiset ja sen sellaiset yleensä kohdistavat muuttelunsa joihinkin tiettyihin ohjelmiin, ei satunnaiseen itse tehtyyn softaan. Toki pienen pieni mahdollisuus, että troijalainen erehtyisi on tietenkin olemassa.
Aihe on jo aika vanha, joten et voi enää vastata siihen.