Nochmal im richtigen Forum: Speicherzugriffsfehler auf 64-Bit Architektur



  • Hallo,

    ich habe leider ein etwas schwierigeres Problem, deshalb versuche ich das Ganze möglichst genau und trotzem knapp zu schildern.
    Ich soll für ein recht umfangreiches Programm Programmteile schreiben, und Fehler beheben.

    Das Programm funktioniert auf 32-Bit Architekturen wunderbar, auf 64-Bit Rechnern kommt es zu einem Speicherzugriffsfehler. Da weder ich, noch meine Kollegen Informatiker sind, sind wir mit dem Problem etwas überfordert.

    Der Programmteil, in dem der Fehler auftritt, liest eine Triangulierung ein. Die Triangulierung besteht eigentlich nur aus Punkten, deren Koordinaten, und deren Nachbarpunkten und Dreiecken, welche durch die Punktkoordinaten definiert sind. Das kleinste Versuchsbeispiel, das möglich ist, besteht aus 4 Punkten, im Code npoints, und drei Dreiecken, im Code ntriangles. Hiefür wird im Programm mit malloc Speicher bereitgestellt, und die Punkte abgespeichert. Allerdings wird oft Speicher für verschiedene Variablentypen benutzt, mit Zeigern und Adressen rumgespielt, wo ich ehrlich gesagt einfach nicht durchblicke. Deshalb will ich auch keine komplett kommentierte Version reinstellen, da ich nicht falsch kommentieren will.

    Meine Vermutung ist, da ja oft sizeof verwendet wird, und die Datentypen, z.b. long zum Teil verschiedene Größen auf den verschiedenen Architekturen haben, hier ein Fehler auftritt.

    Das Programm bricht erst ziemlich zum Schluss in Zeile 110, in der vorletzten For-Schleife, schon im ersten Durchgang ab. Und zwar kann es nicht auf pt_ptr[three_long_buf[i][j]] zugreifen.

    Hier die so gut wie möglich abgespeckte Version:

    void read_triangulation(char *name){
      int i, j, n, npoints, ntriangles;
      int cdfid, tri_points_var, tri_neighbours_var, points_xc_var, points_yc_var;
      int points_bdry_var, hist_bytes = 0, bsize;
      int hist_bytes_var=0, hist_depth_var=0, hist_stat_var=0;
      Point *pt, **pt_ptr;
      Triangle *tri, **tri_ptr;
      NetcdfInfo info;
      void *buffer;
      long (*three_long_buf)[3];
      double *double_buf;
      unsigned char *byte_buf;
      short *short_buf;
      long *long_buf;
    
      hist_bytes = 0     /*Eigentlich anders ermittelt, im Versuchsbeispiel jedoch 0*/
    
      triangulation.ntriangles = ntriangles;    /*im Versuchsbeispiel 3*/
      triangulation.npoints = npoints;          /*im Versuchsbeispiel 4*/
      triangulation.triangle = NULL;
      triangulation.point = NULL;
    
      bsize = hist_bytes * triangulation.ntriangles * (int)sizeof(unsigned char);
    
      if(3 * triangulation.ntriangles * (int)sizeof(long) > bsize)
         bsize = 3 * triangulation.ntriangles * (int)sizeof(long);
    
      if(triangulation.npoints * (int)sizeof(double) > bsize){
         bsize = triangulation.npoints * (int)sizeof(double);
      }
    
      if((buffer = malloc(bsize)) == NULL)
        fatal_error("Out of memory!");
    
      if((pt_ptr = (Point **)malloc(npoints * sizeof(*pt_ptr))) == NULL)
        fatal_error("Out of memory!");
    
      for(i = 0; i < npoints; i++){
        pt = alloc_point();
        cout << "triangulation.point " << triangulation.point << endl;
        pt->succ = triangulation.point;
        triangulation.point = pt;
      }
    
      for(i = 0, pt = triangulation.point; i < npoints; i++, pt = pt->succ){
         cout << "pt" << pt << endl;  
         pt_ptr[i] = pt;
      }
    
      if((tri_ptr = (Triangle **)malloc(ntriangles * sizeof *tri_ptr)) == NULL)
        fatal_error("Out of memory!");
    
      for(i = 0; i < ntriangles; i++){
        tri = alloc_triangle();
        tri->succ = triangulation.triangle;
        triangulation.triangle = tri;
      }
    
      for(i = 0, tri = triangulation.triangle; i < ntriangles; i++, tri = tri->succ)
        tri_ptr[i] = tri;
    
      for(tri = triangulation.triangle; tri != NULL; tri = tri->succ){
          tri->hist.depth = 0;
          tri->hist.green = FALSE;
        }
    
      long_buf = (long *)buffer;
    
      nctri_read_tri_pkt_bdry(cdfid, points_bdry_var, long_buf, 0, npoints);
    
      for(i = 0; i < npoints; i++)
        pt_ptr[i]->bdry = (short)long_buf[i];
    
      double_buf = (double *)buffer;
    
      nctri_read_tri_pkt_x_or_y_c(cdfid, points_xc_var, double_buf, 0, npoints);
    
      for(i = 0; i < npoints; i++)
        pt_ptr[i]->x[0] = double_buf[i];
    
      nctri_read_tri_pkt_x_or_y_c(cdfid, points_yc_var, double_buf, 0, npoints);
    
      for(i = 0; i < npoints; i++)
        pt_ptr[i]->x[1] = double_buf[i];
    
      for(n = 0, pt = triangulation.point; pt != NULL; pt = pt->succ)
        pt->n = n++;
    
      for(n = 0, tri = triangulation.triangle; tri != NULL; tri = tri->succ)
        tri->n = n++;
    
      three_long_buf = (long (*)[3])buffer;
    
      nctri_read_tri_pts_or_nbs(cdfid, tri_points_var, three_long_buf, 0,
                                ntriangles);
    
      for(i = 0, tri = triangulation.triangle; i < ntriangles; i++, tri = tri->succ)
        for(j = 0; j < 3; j++){
    
          tri->pnt[j] = pt_ptr[three_long_buf[i][j]]; /*Hier tritt der Speicherzugriffsfehler auf.*/
        }
    
      nctri_read_tri_pts_or_nbs(cdfid, tri_neighbours_var, three_long_buf, 0,
                                ntriangles);
    
      for(i = 0, tri = triangulation.triangle; i < ntriangles; i++, tri = tri->succ)
        for(j = 0; j < 3; j++)
          tri->ngb[j] = three_long_buf[i][j] < 0 ? NULL
                                                 : tri_ptr[three_long_buf[i][j]];
    
      free(tri_ptr);
      free(pt_ptr);
      free(buffer);
    
      ncclose(cdfid);
    } /*** read_triangulation() ***/
    

    Vielen Dank im Voraus schon mal. Ich hoffe, jemand von euch hat eine Idee.

    Liebe Grüße, Elina



  • Wurde das Programm separat für eine 64-Bit-Umgebung kompiliert?



  • cout << "triangulation.point " << triangulation.point << endl;

    Sieht so aus, als wenn du immer noch nicht im richtigen Forum bist und die Möchtegern-OOPler besser passen würden, aber da du malloc benutzt, sei dir verziehen 🙂

    Dass dein Code dringend eine Aufräumorgie nötig hat, um z.B. solche wie die geschilderten Probleme besser analysieren zu können, dürfte auch dir als Nichtinformatiker klar sein? (zu lange Funktion, zuviele for, zuviele Variablen...)

    long_buf = (long *)buffer;
      nctri_read_tri_pkt_bdry(cdfid, points_bdry_var, long_buf, 0, npoints);
    

    Hier wird mit dem fraglichen Speicherbereich was gemacht, auch schreibend?

    double_buf = (double *)buffer;
      nctri_read_tri_pkt_x_or_y_c(cdfid, points_xc_var, double_buf, 0, npoints);
    

    Hier wird mit demgleichen armen Speicherbereich nochmal was gemacht, dieser aber komplett anders interpretiert als zuvor. Müsste hier schon knallen, wenn sizeof(long)!=sizeof(double).

    three_long_buf = (long (*)[3])buffer;
      nctri_read_tri_pts_or_nbs(cdfid, tri_points_var, three_long_buf, 0,
                                ntriangles);
    

    Zum 3.Mal wird der Speicherbereich anders interpretiert, das auch noch mit einem häßlichen Cast und hier knallt es dann ja wohl auch:

    tri->pnt[j] = pt_ptr[three_long_buf[i][j]]; /*Hier tritt der Speicherzugriffsfehler auf.*/
    

    Der Fehler dürfte sein, dass du den alles entscheidenden buffer zuwenig Speicherraum zuweist in

    bsize = 3 * triangulation.ntriangles * (int)sizeof(long);
    

    Versuche es mal mit

    bsize = 3 * triangulation.ntriangles * (int)sizeof(*long);
    

    da auf 32-Bit Systemen meistens sizeof(long)==sizeof(*long) ist, bei 64-Bit jedoch nicht, dürfte hier schon mal nach rein visuellem Test, ohne den Compiler/Debugger zu bemühen, der (ein?) Fehler liegen.

    Zur Erinnerung vielleicht noch mal, gemäß ANSI C gilt:
    sizeof(*double)==sizeof(*float)==sizeof(*long)==sizeof(*int)==sizeof(*short)==sizeof(*char)==sizeof(*void)==sizeof(size_t)==sizeof(ptrdiff_t)
    sowie
    1==sizeof(char)<=sizeof(short)<=sizeof(int)<=sizeof(long)



  • Hallo, danke fuer deine ausfuehrliche Antwort, im C++ Forum wollten wurde ich hierher geschickt 😃

    Leider weiss ich nicht, was da im Code genau passiert, und vor allem warum, sonst könnte ich da mal aufräumen. So trau ich mich da nicht ran. 🙂

    Die nctri_...funktionen ueberschreiben tatsächlich den Speicher. Wie genau weiss ich nicht, da ich keinen Zugriff auf die Funktionen habe.

    Müsste hier schon knallen, wenn sizeof(long)!=sizeof(double).

    Hm, bei 32-Bit gilt doch sizeof(long)==sizeof(double)?

    bsize = 3 * triangulation.ntriangles * (int)sizeof(*long);

    Das hab ich jetzt versucht, und bekomm eine Fehlermeldung. Ich verstehe ehrlich gesagt nicht wozu man das machen soll?



  • @Elina: Ich würde den Code vielleicht wie folgt debuggen: In deinem Code-Ausschnitt

    for(i = 0, tri = triangulation.triangle; i < ntriangles; i++, tri = tri->succ) 
        for(j = 0; j < 3; j++){ 
    
          tri->pnt[j] = pt_ptr[three_long_buf[i][j]]; /*Hier tritt der Speicherzugriffsfehler auf.*/ 
        }
    

    gibt es 3 Zeiger (weil ntriangles ist scheinbar 3): three_long_buf[0], three_long_buf[1], three_long_buf[2]. Diese müssen gültig sein (ungleich NULL, "sinnvolle" Adressen). Wenn nicht, dann im Code davor schauen, warum nicht...

    Diese Zeiger werden in den Schleifen noch dereferenziert: three_long_buf[0][0], three_long_buf[0][1], three_long_buf[0][2], three_long_buf[1][0], three_long_buf[1][1], three_long_buf[1][2], three_long_buf[2][0], three_long_buf[2][1], three_long_buf[2][2]. Was immer da dereferenziert wird, es muss einen Wertebereich [0...3] haben, weil es gibt nur pt_ptr[0], pt_ptr[1], pt_ptr[2] und pt_ptr[3] (weil npoints ist scheinbar 4). Ist three_long_buf[i][j] kleiner 0 (es kann kleiner 0 sein, weil Datentyp long) oder größer 3 - das ist falsch, d.h. davor im Code schauen, warum...

    Wenn die ganzen Zeiger und Wertdebereiche ok sind, dann stimmt irgendwas mit dem tri-Zeiger nicht und folglich mit dem tri->succ...

    Viel Glück beim Debuggen 🙂



  • Wutz schrieb:

    Zur Erinnerung vielleicht noch mal, gemäß ANSI C gilt:
    sizeof(*double)==sizeof(*float)==sizeof(*long)==sizeof(*int)==sizeof(*short)==sizeof(*char)==sizeof(*void)==sizeof(size_t)==sizeof(ptrdiff_t)

    kann doch fast nicht sein oder etwa doch 😮



  • Elina schrieb:

    Hm, bei 32-Bit gilt doch sizeof(long)==sizeof(double)?

    nee das kann man so nicht sagen oder?

    und da ich jetzt zu faul bin um das rauszusuchen

    5.2.4.2



  • ich dachte immer sizeof(*int) == sizeof(int)



  • Elina schrieb:

    bsize = 3 * triangulation.ntriangles * (int)sizeof(*long);

    Das hab ich jetzt versucht, und bekomm eine Fehlermeldung. Ich verstehe ehrlich gesagt nicht wozu man das machen soll?

    ist ja auch logisch bei so nem prallen beispiel... also

    int x = 11;
    int *px = &x;
    sizeof(*px) == sizeof(int)
    
    double x = 11;
    double *px = &x;
    sizeof(*px) == sizeof(double)
    

    so sollte das stimmen, bin auch schon etwas eingerostet 😉



  • btw. wenn mein counter zu hoch ist, dann müßte der von Wutz negativ sein :p



  • Elina schrieb:

    Hm, bei 32-Bit gilt doch sizeof(long)==sizeof(double)?

    ANSI C sagt nichts über den Größenvergleich zwischen Gleitkomma- und Nichtgleitkommazahlen aus.
    Wenn du dich nicht an den Code rantraust, bist du denkbar ungeeignet für die Aufgabe, ihn zu korrigieren/portieren.



  • Wutz schrieb:

    Wenn du dich nicht an den Code rantraust, bist du denkbar ungeeignet für die Aufgabe, ihn zu korrigieren/portieren.

    wohoo, meldet sich da jemand freiwillig zum portieren/debuggen 😃

    edit: btw. soweit ich weiß werden frauen da mangelware in diesem forum bevorzugt behandelt...


Anmelden zum Antworten