Teilweise auftreten eines *Segmentation fault"



  • Hallo
    ich lese aus einem TGA-file die alpha-werte, welche die höhe der karte wiederspiegeln, also 1px des TGA ist 1 punkt auf der karte. bei der berechnung der normalen tritt dann aber teilweise (!) ein "segmentation fault"-error auf.

    ich habe folgenden code:

    struct PTerrain {
    	float *heights, *colors;
    	PVector *faceNormals, *vertexNormals;
    
    	int widthX, widthY;
    
    	void loadHeightMap(const char *filename);
    	void computeNormals();
    };
    typedef struct PVector {
    	float X, Y, Z;
    
    	void normalize();
    	void setValues(PVector v) { this->X = v.X; this->Y = v.Y; this->Z = v.Z; }
    	void setValues(float x, float y, float z) { this->X = x; this->Y = y; this->Z = z; }
    
    };
    --------------------------------------------------------------------------------
    void PVector::normalize() {
    	float l = sqrt(this->X * this->X + this->Y * this->Y + this->Z * this->Z);
    	if (l == 0) 
    		l=1;
    
    	this->X /= l;
    	this->Y /= l;
    	this->Z /= l;
    }
    
    --------------------------------------------------------------------------------
    void PTerrain::loadHeightMap(const char *filename) {
    	usleep(1000);
    	tgaInfo *info;
    	int aux;
    
    	info = tgaLoad(filename);
    
    	this->widthX = info->width;
    	this->widthY = info->height;
    
    	this->heights = (float *)malloc(this->widthX * this->widthY * sizeof(float));
    	if (this->heights == NULL) {
    		error();
    		return;
    	}
    
    	this->vertexNormals = (PVector *)malloc(this->widthX * this->widthY * sizeof(PVector));
    	if (this->vertexNormals == NULL) {
    		error();
    		return;
    	}
    	this->faceNormals = (PVector *)malloc(this->widthX * this->widthY * sizeof(PVector));
    	if (this->faceNormals == NULL) {
    		error();
    		return;
    	}
    
    	for (int y=0 ; y<this->widthY; y++)
    		for (int x=0; x<this->widthX; x++) {
    			aux = (y*this->widthX + x);
    			this->heights[y*this->widthX + x] = info->imageData[aux] / 256.0;
    
    		}
    
    	this->computeNormals();
    
    	tgaDestroy(info);
    
    	float startX = - this->widthX / 2.0;
    	float startY = this->widthY / 2.0;
    	float texCoord;
    
    	this->DL = glGenLists(1);
    	glNewList(this->DL,GL_COMPILE);
    	glColor3f(1.0, 1.0, 1.0);
    	for (int y=0; y<this->widthY-1; y++) {
    		glBegin(GL_TRIANGLE_STRIP);
    		glBindTexture(GL_TEXTURE_2D, textures->texId);
    		for (int x=0; x<this->widthX; x++) {
    			aux = ((y+1)*this->widthX + x);
    
    			glTexCoord2f(texCoord, 1);
    			glNormal3f(this->vertexNormals[aux].getX(), this->vertexNormals[aux].getY(), this->vertexNormals[aux].getZ());
    			glVertex3f((startX + x), (startY - (y+1)), this->heights[(y+1)*this->widthX + x]);
    
    			aux = (y*this->widthX + x);
    
    			glTexCoord2f(texCoord, 0);
    			glNormal3f(this->vertexNormals[aux].getX(), this->vertexNormals[aux].getY(), this->vertexNormals[aux].getZ());
    			glVertex3f((startX + x), (startY - y), this->heights[y*this->widthX + x]);
    			texCoord = 1-texCoord;
    		}
    		glEnd();
    	}
    
    	glEndList();
    	return;
    }
    --------------------------------------------------------------------------------
    void PTerrain::computeNormals() {
    	PVector vec1 = PVector(0.0, 0.0, 0.0), vec2 = PVector(0.0, 0.0, 0.0);
    
    	for(int y=0; y<this->widthY; y++) {
    
    		for(int x = 0; x < this->widthX; x++) {
    			vec1.setValues(0.0, 0.0, 0.0);
    			vec2.setValues(0.0, 0.0, 0.0);
    			if(y ==this->widthY && x == this->widthX) {
    				vec1.setValues(1.0, 0.0, 0.0);
    				vec2.setValues(0.0, 1.0, 0.0);
    			}else if(x == this->widthX) {
    				vec1.setValues(1.0, 0.0, 0.0);
    				vec2.setValues(0.0, 1.0, (this->heights[(y+1)* this->widthX+x] - this->heights[y* this->widthX+x]));
    			}else if(y == this->widthY) {
    				vec1.setValues(1.0, 0.0, (this->heights[y* this->widthX+x+1] - this->heights[y* this->widthX+x]));
    				vec2.setValues(0.0, 1.0, 0.0);
    			}else{
    				vec1.setValues(1.0, 0.0, (this->heights[y* this->widthX+x+1] - this->heights[y* this->widthX+x]));
    				vec2.setValues(0.0, 1.0, (this->heights[(y+1)* this->widthX+x] - this->heights[y* this->widthX+x]));
    			}
    			this->faceNormals[(y* this->widthX+x)].setValues(crossProduct(vec1, vec2));
    			this->faceNormals[(y* this->widthX+x)].normalize();
    		}
    
    	}
    }
    

    der aufruf mittels:

    PTerrain *heightMap = (PTerrain*)malloc(sizeof(PTerrain));
    heightMap->loadHeightMap("map.tga");
    

    der inhalt der funktion loadHeightMap sollte vor allem bis und mit dem aufruf von computeNormals() interessant sein. dort steckt der fehler.

    tut mir im übrigen leid für den vielen code 😃

    EDIT: cpp-Tags



  • this->heights[(y+1)* this->widthX+x]

    sicher dass das auch für y = widthY-1 innerhalb der grenzen liegt?



    1. Benutze bitte C++ Code Tags und nicht die normalen (ich editiere es dir jetzt um)

    2. Hast du keinen Debugger? Wir sind nicht dazu da, dessen Job zu übernehmen. Der Fehler müsste damit recht einfach zu finden sein, siehe unten.

    3. Wieso benutzt du malloc in C++ und nicht new oder noch besser vector oder ähnliches.

    4. Die folgende Schleife dürfte dir sterben:

    for(int y=0; y<this->widthY; y++)
    { 
       for(int x = 0; x < this->widthX; x++)
       { 
          vec1.setValues(0.0, 0.0, 0.0); 
          vec2.setValues(0.0, 0.0, 0.0);
          //passiert NIE, vgl. Schleifenbedingung
          if(y ==this->widthY && x == this->widthX)
          {
             vec1.setValues(1.0, 0.0, 0.0); 
             vec2.setValues(0.0, 1.0, 0.0); 
          }
          //dito
          else if(x == this->widthX)
          { 
             vec1.setValues(1.0, 0.0, 0.0); 
             vec2.setValues(0.0, 1.0, (this->heights[(y+1)* this->widthX+x] - this->heights[y* this->widthX+x])); 
          }
          //dito
          else if(y == this->widthY)
          { 
             vec1.setValues(1.0, 0.0, (this->heights[y* this->widthX+x+1] - this->heights[y* this->widthX+x]));
             vec2.setValues(0.0, 1.0, 0.0); 
          }
          //passiert also immer
          else
          { 
             vec1.setValues(1.0, 0.0, (this->heights[y* this->widthX+x+1] - this->heights[y* this->widthX+x])); 
             vec2.setValues(0.0, 1.0, (this->heights[(y+1)* this->widthX+x] - this->heights[y* this->widthX+x])); //auf jeden Fall diese Zeile ist böse, erklärung unten
                } 
             this->faceNormals[(y* this->widthX+x)].setValues(crossProduct(vec1, vec2)); 
             this->faceNormals[(y* this->widthX+x)].normalize(); 
          } 
       } 
    }
    

    Nehmen wir der Einfachheit halber mal an, widthX = yWidth = 2. Dann hat dein Array folgendes Layout:

    0  1
    0 0  1
    
    1 2  3
    

    Dann stirbt dir this->heights[(y+1)* this->widthX+x], denn wir nehmen den Extremfall y=x=1 an, dann greifst du zu auf den Index

    (1+1) * 2 + 1 = 5

    -> Boom

    Felix



  • zu 1: ups, sry hab ich übersehen

    zu 2: strace gibt (u.a.) folgendes aus:

    getpid()                                = 8381
    read(3, 0x60c854, 4096)                 = -1 EAGAIN (Resource temporarily unavailable)
    read(9, "", 4096)                       = 0
    nanosleep({0, 1000000}, NULL)           = 0
    open("map.tga", O_RDONLY)  = 10
    fstat(10, {st_mode=S_IFREG|0666, st_size=196652, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f31ca625000
    read(10, "\0\0\2\0\0\0\0\0\0\0\0\0\0\1\0\1\30 \331\331\331\377\377"..., 4096) = 4096
    read(10, "@@@@@@@@???BBBBBBCCC????????????"..., 192512) = 192512
    read(10, "777777777777777777\0\0\0\0\0\0\0\0TRUEVI"..., 4096) = 44
    close(10)                               = 0
    munmap(0x7f31ca625000, 4096)            = 0
    mmap(NULL, 790528, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f31c9bdc000
    mmap(NULL, 1576960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f31c9a5b000
    --- SIGSEGV (Segmentation fault) @ 0 (0) ---
    Process 8381 detached
    

    zu 3.: hab ich einfach von irgendwo übernommen. macht keinen unterschied oder?

    zu 4.: hast recht, hab ich beim code kürzen übersehen.

    dein ansatz erklärt aber nicht wieso das heightmap manchmal ohne probleme lädt und wenn ich das programm neu starte funktioniert es plötzlich nicht mehr.. :s

    danke für deine mühen und die schnelle antwort 😉 ich hoffe die ausgabe von strace reicht, ich versteh davon nicht viel 😃



  • ich seh den Sinn nicht dir zu helfen wenn du keine eigeninitiative zeigst.
    wenn du nicht lernen willst, kein problem. wir koennen uns sicher einen preis ausmachen, dann schreib ich dir das programm fertig.



  • Mal anders gesagt, mit deinem "strace" können/wollen wir nichts anfangen. Keiner hier hat Lust, anderen die Arbeit abzunehmen. Für Fragestellungen und Hilfe sind wir gerne bereit, aber etwas Eigeninitiative sollte schon vorhanden sein...

    Es wurde ja bereits erwähnt: Nimm einen Debugger, geh den Code schrittweise durch, überprüfe die Variablen und du wirst den Fehler relativ schnell finden.
    Darum herum kommst du - gerade bei grösseren Projekten - sowieso nicht, also lerne lieber gleich, mit Debuggern umzugehen.



  • ah jetzt funktionierts. hab einfach für heights noch eine reihe hinzugefügt, schiesst jetzt nicht mehr über den index raus.

    aber kann mir jemand sagen wieso das "segmentation fault" nicht immer kommt? es arbeitet jedes mal das gleiche durch, sollte also immer über den index von this->heights hinausschiessen. tut es aber anscheinend nicht.... 😕



  • ..-.. schrieb:

    aber kann mir jemand sagen wieso das "segmentation fault" nicht immer kommt?

    Bei jedem Programmdurchgang sieht der Arbeitsspeicher anders aus. Auch die selber angelegten Variablen werden nicht immer am gleichen Ort abgespeichert. Es kann also durch puren Zufall geschehen, dass nichts passiert. Ein Paradebeispiel ist die Rückgabe von lokalen Objekten als Referenz oder Zeiger und der Zugriff darauf kurz danach.


Anmelden zum Antworten