C++: Corruption of heap error bei fclose()
*jiriki*
- programmiertechnik
Moin Leute,
Bin gerade dabei, ne kleine C++-/OpenGL-Anwendung zu schreiben, in der kleine Raumschiffmodelle geladen werden und durchs Weltall fliegen können. Um die leider nicht unendlichen Weiten des Weltalls zu simulieren, will ich ne ziemlich große Kugel um den Weltkoordinatenursprung legen, mit Normalen nach innen und ner Weltall-Textur belegen.
Fürs Laden der Modellkoordinaten aus einem obj-File in entsprechende Arrays (Vertices,Vertices der Texturen,Faces) hab ich nun ne Funktion WavefrontIrrakuri von meinem baskischen Prof genommen und angepasst. Soweit so schön, er lädt mir jetzt alle Koordinaten entsprechend in die Arrays. Leider bringt er mir jedoch beim Schließen (fclose()) des Filestreams (Stream zu obj-File) den folgenden Fehler:
HEAP[Universo.exe]: Invalid Address specified to RtlValidateHeap( 00880000, 014B3960 )
Windows has triggered a breakpoint in Universo.exe.
This may be due to a corruption of the heap, and indicates a bug in Universo.exe or any of the DLLs it has loaded.
Der Code von Beginn des Dateilesens bis dessen Ende ist:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
fitx=fopen(fitxiz,"r");
k=0;
j=0;
m=0;
for (i=0;i<numvert;i++) {
tablavert[i].zenbataurpegitan=0;
tablavert[i].normala.x = 0.0;
tablavert[i].normala.y = 0.0;
tablavert[i].normala.z = 0.0;
}
while (fscanf(fitx,"\n%[^\n]",lerroa)>0)
{
switch (lerroa[0])
{
case 'v':
{
if( lerroa[1] == ' ' )
{
printf( "v!" );
sscanf(lerroa+2,"%lf%lf%lf", &(tablavert[k].koord.x), &(tablavert[k].koord.y), &(tablavert[k].koord.z));
k++;
}
else if( lerroa[1] == 't' )
{
printf( "vt!" );
sscanf(lerroa+3,"%lf%lf",&(tablatexturas[m].x), &(tablatexturas[m].y));
m++;
}
}
break;
case 'f':
{
tablacaras[j].numvert = 3;
tablacaras[j].tablaindvert = (int *)malloc(tablacaras[j].numvert*sizeof(int));
tablacaras[j].tablaindtext = (int *)malloc(3*sizeof(int));
sscanf(lerroa+2,"%d/%d/%d %d/%d/%d", &(tablacaras[j].tablaindvert[0]), &(tablacaras[j].tablaindvert[1]), &(tablacaras[j].tablaindvert[2]), &(tablacaras[j].tablaindtext[0]), &(tablacaras[j].tablaindtext[1]), &(tablacaras[j].tablaindtext[2]));
// Jeder Vertex speichert in zenbataurpegitan in wievielen Faces er vertreten ist
for (i=0; i<tablacaras[j].numvert; i++)
{
tablavert[tablacaras[j].tablaindvert[i]].zenbataurpegitan++;
}
j++;
}
break;
}
}
fclose(fitx);
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Danke für jeden Hinweis.
Hallo,
for (i=0;i<numvert;i++) {
tablavert[i].zenbataurpegitan=0;
..
}
zu prüfen wäre, ob für `tablavert`{:.language-c} numvert Records allociert sind und `k<numvert`{:.language-c} bleibt.
im folgenden wird nicht geprüft, ob m oder j den zulässigen Bereich überschreiten. Die Logik kann man anhand dieser Codeschnipsel nicht erkennen. Müsstest also noch suchen wieviel Speicher für tablatexturas und tablacaras allociert ist.
> sscanf(lerroa+2,"%lf%lf%lf", &(tablavert[k].koord.x), &(tablavert[k].koord.y), &(tablavert[k].koord.z));
> k++;
> sscanf(lerroa+3,"%lf%lf",&(tablatexturas[m].x), &(tablatexturas[m].y));
> m++;
>
> tablacaras[j].numvert = 3;
> tablacaras[j].tablaindvert = (int \*)malloc(tablacaras[j].numvert\*sizeof(int));
> ...
> j++;
> [/code]
>
Gruß plan\_B
--
\*®\*´¯`·.¸¸.·
Über das fclose kommt er jetzt drüber hinweg. Kann mich nicht dran erinnern, was ich eigentlich geändert hab, aber das klappt jetzt. Wo es jetzt hakt, ist, wenn er die eingelesenen Faces wieder zur Berechnung derer Normalen aufrufen möchte.
Was ich jetzt beim Testen herausgefunden hab: Ich kann komischerweise nicht mehr als 468 caras/faces (im folgenden caras) abspeichern. Unabhängig von der Anzahl der eingelesenen caras bzw. numcara bzw. des abhängig von numcara allocierten Speichers. Ich hab gemerkt, dass wenn ich mehr als 468 caras einlese, die Index-Werte der Vertices der einzelnen caras nach dem ersten cara[0] (also ab cara[1]) auf ziemlich willkürliche Werte verweisen. Wenn ich den allokierten Speicherbereich verdopple, tut sich da leider nichts.
Der zugehörige Code ist:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Calculating the normals
for (i=0; i< objektuptr->numcaras; i++) {
bektorea3 v1, v2; // Vektoren
// Reading out values of vertices
i0 = objektuptr->tablacaras[i].tablaindvert[0];
i1 = objektuptr->tablacaras[i].tablaindvert[1];
i2 = objektuptr->tablacaras[i].tablaindvert[2];
// Calculating two vectors out of three vertices
v1.x= objektuptr->tablavert[i0].koord.x - objektuptr->tablavert[i1].koord.x ;
v1.y= objektuptr->tablavert[i0].koord.y - objektuptr->tablavert[i1].koord.y ;
v1.z= objektuptr->tablavert[i0].koord.z - objektuptr->tablavert[i1].koord.z ;
v2.x= objektuptr->tablavert[i1].koord.x - objektuptr->tablavert[i2].koord.x ;
v2.y= objektuptr->tablavert[i1].koord.y - objektuptr->tablavert[i2].koord.y ;
v2.z= objektuptr->tablavert[i1].koord.z - objektuptr->tablavert[i2].koord.z ;
// Calculating the vectors out of two vectors
// Cross product
...
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Wenn das Modell also mehr als 468 caras hat, kommen ab i=1 Fabelwerte für i0 bis i2 heraus, und beim entsprechenden tablavert[i0] bricht das Programm mit der Fehlermeldung ab, dass es die angegebene Adresse verständlicherweise nicht finden kann.
Hallo,
for (i=0;i<numvert;i++) {
tablavert[i].zenbataurpegitan=0;
..
}
> zu prüfen wäre, ob für `tablavert`{:.language-c} numvert Records allociert sind und `k<numvert`{:.language-c} bleibt.
Ja, der zugehörige Code sieht so aus:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
~~~c
tablavert=(vertice *)malloc(numvert*sizeof(vertice));
tablacaras=(cara *)malloc(numcaras*sizeof(cara));
tablanormales= (puntua3 *)malloc(numcaras*sizeof(puntua3));
tablatexturas = (puntua2 *)malloc(numtext*sizeof(puntua2));
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
wobei vertice,cara,puntua3 und puntua2 in der Header-File definierte Strukte sind:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
typedef struct {
double x,y;
} puntua2;
typedef struct {
double x,y,z;
} puntua3;
typedef struct {
puntua3 koord; // Koordinaten
int zenbataurpegitan; // Anzahl Caras
bektorea3 normala; // Normale
} vertice;
typedef struct {
int numvert; // Anzahl der Vertices
int *tablaindvert; // Index der zugehörigen Vertices
int *tablaindtext; // Index der zugehörigen Texturkoordinaten
} cara;
im folgenden wird nicht geprüft, ob m oder j den zulässigen Bereich überschreiten. Die Logik kann man anhand dieser Codeschnipsel nicht erkennen. Müsstest also noch suchen wieviel Speicher für tablatexturas und tablacaras allociert ist.
Ich habe oben den Link zum ganzen Code gepackt: zur wavefront.pdf.
Gruß plan_B
Danke und Gruß
Hallo,
Was ich jetzt beim Testen herausgefunden hab: Ich kann komischerweise nicht mehr als 468 caras/faces (im folgenden caras) abspeichern. Unabhängig von der Anzahl der eingelesenen caras bzw. numcara bzw. des abhängig von numcara allocierten Speichers. Ich hab gemerkt, dass wenn ich mehr als 468 caras einlese, die Index-Werte der Vertices der einzelnen caras nach dem ersten cara[0] (also ab cara[1]) auf ziemlich willkürliche Werte verweisen. Wenn ich den allokierten Speicherbereich verdopple, tut sich da leider nichts.
meine C-Kenntisse habe ich schon etliche Jahre nicht mehr aufgefrischt. Deswegen kann ich dir jetzt wahrscheinlich auch nicht viel weiterhelfen.
Wenn ich mich nicht irre, kann man mit malloc nicht mehr als 64kb allocieren. Möglich, dass durch verdoppeln diese Schranke überschritten wurde. Ob man jetzt einfach auf calloc umstellen kann oder sich damit andere Schwierigkeiten (Adresslänge) einhandelt, wirst du wohl eher überblicken können.
so richtig in den Quellcode vertiefen mag ich mich aber auch nicht...
Gruß plan_B