Verständnisfrage zu Free Prozedur einer Library

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
thosch
Beiträge: 253
Registriert: Mo 10. Jul 2017, 20:32

Verständnisfrage zu Free Prozedur einer Library

Beitrag von thosch »

Ich habe folgende Free Prozedur, weiteren Quellcode gebe ich dazu wenn das für das Verständis nötig sein sollte!

Code: Alles auswählen

procedure Free( var P );
 var
   head : PBlock_Header;
   i    : Integer;
   size : Longint;
 begin
   if Pointer(P) = nil then exit;   // Diese Zeile kapier ich nicht

   i    := -1;
   head := @(PBlock_Headers(P)^[i]);
   (* A hack to get the header in PB, as the line             *)
   (*  @(PBlock_Headers(P)^[-1] would give a 'constant error' *)
   (* at compile time. I'm unsure this works correctly in BP  *)

   if head^.magic <> Mark_Magic then
   begin
     (* PANIC : An invalid Free call *)
     Writeln('Invalid Free call');
     halt(1);
   end;

   size := head^.size;

   head^.magic := 0;  (* cleans the header *)
   head^.size  := 0;

   FreeMem( head, size );

   Pointer(P) := nil;
 end;                           
 
Warum wird hier zu Anfang auf NIL geprüft und wenn nicht NIL, dann Fehler ausgelöst, der mit der Zuweisung i:=-1 vorbereitet wird?

Normalerweise gebe ich doch Speicer frei auf den eine Zeigervariable gerichtet ist. Warum ist das hier anders?

kupferstecher
Beiträge: 299
Registriert: Do 17. Nov 2016, 11:52

Re: Verständnisfrage zu Free Prozedur einer Library

Beitrag von kupferstecher »

thosch hat geschrieben:
Di 23. Mär 2021, 17:09
Warum wird hier zu Anfang auf NIL geprüft
Wenn die Variable nil wäre, also ein Pointer auf 0, dann gäbe es ja auch kein Objekt, das man "freeen" könnte. Würde man die Prozedur an der Stelle nicht verlassen, sondern versuchen auf das Objekt zuzugreifen, würde man eine Zugriffsverletzung bekommen -> Programmcrash.
und wenn nicht NIL, dann Fehler ausgelöst, der mit der Zuweisung i:=-1 vorbereitet wird?
Das ist m.E. nicht der Fall, mit -1 wird absichtlich ein Element außerhalb des Arrays angesprochen, das dort offensichtlich erwartet wird mit dem Wert Mark_Magic. Wenn der Wert dort nicht Mark_Magic ist, ist es offensichtlich nicht das erwartete Objekt -> Fehlermeldung.

thosch
Beiträge: 253
Registriert: Mo 10. Jul 2017, 20:32

Re: Verständnisfrage zu Free Prozedur einer Library

Beitrag von thosch »

Danke für die schnelle Antwort.

Aber was könnte nun der optimale Work Around sein?

Das übergebene Objekt noch mal auf seine Struktur prüfen? Aber was wird dann mit dem Array in Free? Ich steh hier grad auf dem sprichwörtlichen Schlauch. Ich dachte zunächst daran, dafür zu sorgen, dass der übergebene Zeiger auf jeden Fall zu Anfang als Nil Zeiger übergeben wird.

kupferstecher
Beiträge: 299
Registriert: Do 17. Nov 2016, 11:52

Re: Verständnisfrage zu Free Prozedur einer Library

Beitrag von kupferstecher »

thosch hat geschrieben:
Di 23. Mär 2021, 19:36
Aber was könnte nun der optimale Work Around sein?
Was willst du denn erreichen? Die Prozedur funktioniert nur für das spezielle Objekt. Übergibtst du ein solches Objekt (dessen Header scheinbar außerhalb der Pointeradresse steht), dann läuft die Prozedur ganz normal durch und das Objekt wird vom Speicher gelöscht. Dass es funktioniert hat, siehst du daran, dass dein Pointer nach dem Funktionsaufruf auf nil zeigt.

Wenn die Fehlermeldung 'Invalid Free call' auftaucht, du dir aber sicher bist, dass es das korrekte Objekt ist, dann stimmt vielleicht die Adresse nicht, also dass du tatsächlich die Anfangsadresse des Objekts übergeben hast, anstatt die auf das Arrayelement mit Index 1, wie die Prozedur das erwartet. Oder eben das Objekt wurde nicht sauber initialisiert, d.h. die Magik Number fehlt.

Vielleicht beschreibst du nochmal welches Verhalten du erwartest und was tatsächlich passiert. Der Code in der das Array definiert wird, würde vielleicht auch weiterhelfen.

thosch
Beiträge: 253
Registriert: Mo 10. Jul 2017, 20:32

Re: Verständnisfrage zu Free Prozedur einer Library

Beitrag von thosch »

Erreichen will ich dass der übergebene Zeiger, wenn er noch belegt ist frei gegeben und danach neu instantiiert wird. Die Free Prozedur stammt aus einer Programmbibliothek.

Ich werwarte eigentlich dass der übergeben Zeiger frei gegeben und nach Verlassen der Free Prozedur neu angelegt wird mit Alloc().

Code: Alles auswählen

 Update_Max( glyphSize,
                 sizeof(Byte),
                 glyphIns,  Um diesen Zeiger geht es, aus Freetype
                 face^.maxProfile.maxSizeOfInstructions );

// Die Updete_Max Ro
   procedure Update_Max( var size : Int;
                         mult     : Int;
                         var buff;
                         new_max  : Int );
   begin
     if size*mult < new_max then
     begin
       Free(buff);  //Das ist die fragliche Free Prozedur aus der Bibliothek  size ist gleich 0, mult ist glerich 1
       Alloc( buff, new_max*mult );
       size := new_max;
     end;
   end;
  


Erreichen will ich nun, dass buff wenn es denn in diesem Programmableuf dieser Bibliothek so sein soll, frei gegeben wird um anschließend mit Alloc neuen Speicherplatzt zuzuweisen.

Update_Max wird vorher für 2 andere Puffer aufgerufen und funktioniert dort, nur diese eine nach den 2 vorigen Aufrufen will nicht so , wie ich will.

kupferstecher
Beiträge: 299
Registriert: Do 17. Nov 2016, 11:52

Re: Verständnisfrage zu Free Prozedur einer Library

Beitrag von kupferstecher »

thosch hat geschrieben:
Di 23. Mär 2021, 22:16
Update_Max wird vorher für 2 andere Puffer aufgerufen und funktioniert dort, nur diese eine nach den 2 vorigen Aufrufen will nicht so , wie ich will.
D.h. es kommt die Ausgabe 'Invalid Free call'?


Nochmal dazu, was die Free-Prozedur erwartet:

Code: Alles auswählen

|-- HEADER --|-- DATEN --|
              ^
           Pointer
D.h. das Objekt besteht aus zwei Teilen, dem Header und einem nicht näher spezifizierten Datenteil. Der Pointer muss auf das erste Byte im Datenteil zeigen. Soviel lässt sich aus der Free-Prozedur erkennen. Warum das Objekt jetzt nicht dazu passt, kann ich aus deinem Code auch nicht erkennen.

thosch
Beiträge: 253
Registriert: Mo 10. Jul 2017, 20:32

Re: Verständnisfrage zu Free Prozedur einer Library

Beitrag von thosch »

Die Fehlermeldung "Invalid Freecall" kommt nur beim letzten von den folgenden 3 AUfrufen von Update_Max().

Code: Alles auswählen

   procedure Update_Points( max_points   : Int;
                            max_contours : Int;
                            exec         : PExec_Context );
   begin
     if exec^.maxPoints < max_points then
     begin
       Free( exec^.pts.org );
       Free( exec^.pts.cur );
       Free( exec^.pts.flags );

       Alloc( exec^.pts.org, 2*sizeof(TT_F26dot6)*max_points );
       Alloc( exec^.pts.cur, 2*sizeof(TT_F26dot6)*max_points );
       Alloc( exec^.pts.flags, sizeof(Byte)      *max_points );

       exec^.maxPoints := max_points;
     end;

     if exec^.maxContours < max_contours then
     begin
       Free( exec^.pts.conEnds );
       Alloc( exec^.pts.conEnds, sizeof(Short)*max_contours );
       exec^.maxContours := max_contours;
     end;
   end;


 begin
   with exec^ do
   begin

     instance := ins;
     face     := ins^.owner;

     numFDefs := ins^.numFDefs;
     numIDefs := ins^.numIDefs;
     maxFDefs := ins^.maxFDefs;
     maxIDefs := ins^.maxIDefs;
     FDefs    := ins^.FDefs;
     IDefs    := ins^.IDefs;
     maxFunc  := ins^.maxFunc;
     maxIns   := ins^.maxIns;

     metrics  := ins^.metrics;

     codeRangeTable := ins^.codeRangeTable;

     storeSize := ins^.storeSize;
     storage   := ins^.storage;

     twilight  := ins^.twilight;

     (* We reserve some extra space to deal with broken fonts *)
     (* like Arial BS, Courier BS, etc..                      *)
     Update_Max( stackSize,
                 sizeof(Long),
                 stack,
                 face^.maxProfile.maxStackElements+32 );

     Update_Max( loadSize,
                 sizeof(TSubglyph_Record),
                 loadStack,
                 face^.maxComponents+1 );

     Update_Max( glyphSize,
                 sizeof(Byte),
                 glyphIns,
                 face^.maxProfile.maxSizeOfInstructions );

     (* XXXX : Don't forget the phantom points !! *)
     Update_Points( face^.maxPoints+2, face^.maxContours, exec );

     pts.n_points   := 0;
     pts.n_contours := 0;

     instruction_trap := false;

     (* Set default graphics state *)
     GS := ins^.GS;

     cvtSize := ins^.cvtSize;
     cvt     := ins^.cvt;
   end;
 end;
In dieser Prozedur befinden sich die 3 Aufrufe der Update_Max() Routine und nur beim letzten Aufruf kommt die Fehlermeldung, die anderen beiden Aufrufe davor funktionieren fehlerfrei.

Ich guck aber vorher jetzt auch selber noch mal bis der Debugger heiß läuft. :)

glyphins ist vom Typ PByte!

[EDIT]
Ich habe nun mal die Variable glyphins probeweise vor dem dritten Aufruf von Update_Max() auf Nil gesetzt und da läuft die Routine fehlerfrei durch. glyphins wird vorher nicht von irgendwoher belegt.

Jetzt muss ich die Bibliothek weiter testen.

Danke bis hierher für Deine Unterstützung.
:)
[/EDIT]

Antworten